blob: 8afbb34b6e1437f17101bbe681f17ed158e0f698 [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
Daniel Veillardf2a36f92004-11-08 17:55:01 +00001243 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001244 if (ctxt->value == NULL) {
1245 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1246 return(NULL);
1247 }
1248 if (!xmlXPathStackIsNodeSet(ctxt)) {
1249 xmlXPathSetTypeError(ctxt);
1250 return(NULL);
1251 }
1252 obj = valuePop(ctxt);
1253 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001254#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001255 /* to fix memory leak of not clearing obj->user */
1256 if (obj->boolval && obj->user != NULL)
1257 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001258#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001259 xmlXPathFreeNodeSetList(obj);
1260 return(ret);
1261}
1262
1263/**
1264 * xmlXPathPopExternal:
1265 * @ctxt: an XPath parser context
1266 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001267 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001268 * Check error with #xmlXPathCheckError.
1269 *
1270 * Returns the object
1271 */
1272void *
1273xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1274 xmlXPathObjectPtr obj;
1275 void * ret;
1276
Daniel Veillarda82b1822004-11-08 16:24:57 +00001277 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001278 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1279 return(NULL);
1280 }
1281 if (ctxt->value->type != XPATH_USERS) {
1282 xmlXPathSetTypeError(ctxt);
1283 return(NULL);
1284 }
1285 obj = valuePop(ctxt);
1286 ret = obj->user;
1287 xmlXPathFreeObject(obj);
1288 return(ret);
1289}
1290
Owen Taylor3473f882001-02-23 17:55:21 +00001291/*
1292 * Macros for accessing the content. Those should be used only by the parser,
1293 * and not exported.
1294 *
1295 * Dirty macros, i.e. one need to make assumption on the context to use them
1296 *
1297 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1298 * CUR returns the current xmlChar value, i.e. a 8 bit value
1299 * in ISO-Latin or UTF-8.
1300 * This should be used internally by the parser
1301 * only to compare to ASCII values otherwise it would break when
1302 * running with UTF-8 encoding.
1303 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1304 * to compare on ASCII based substring.
1305 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1306 * strings within the parser.
1307 * CURRENT Returns the current char value, with the full decoding of
1308 * UTF-8 if we are using this mode. It returns an int.
1309 * NEXT Skip to the next character, this does the proper decoding
1310 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1311 * It returns the pointer to the current xmlChar.
1312 */
1313
1314#define CUR (*ctxt->cur)
1315#define SKIP(val) ctxt->cur += (val)
1316#define NXT(val) ctxt->cur[(val)]
1317#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001318#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1319
1320#define COPY_BUF(l,b,i,v) \
1321 if (l == 1) b[i++] = (xmlChar) v; \
1322 else i += xmlCopyChar(l,&b[i],v)
1323
1324#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001325
1326#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001327 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001328
1329#define CURRENT (*ctxt->cur)
1330#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1331
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001332
1333#ifndef DBL_DIG
1334#define DBL_DIG 16
1335#endif
1336#ifndef DBL_EPSILON
1337#define DBL_EPSILON 1E-9
1338#endif
1339
1340#define UPPER_DOUBLE 1E9
1341#define LOWER_DOUBLE 1E-5
1342
1343#define INTEGER_DIGITS DBL_DIG
1344#define FRACTION_DIGITS (DBL_DIG + 1)
1345#define EXPONENT_DIGITS (3 + 2)
1346
1347/**
1348 * xmlXPathFormatNumber:
1349 * @number: number to format
1350 * @buffer: output buffer
1351 * @buffersize: size of output buffer
1352 *
1353 * Convert the number into a string representation.
1354 */
1355static void
1356xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1357{
Daniel Veillardcda96922001-08-21 10:56:31 +00001358 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001359 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001360 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001361 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001362 break;
1363 case -1:
1364 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001365 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001366 break;
1367 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001368 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001369 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001370 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001371 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001372 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001373 } else if (number == ((int) number)) {
1374 char work[30];
1375 char *ptr, *cur;
1376 int res, value = (int) number;
1377
1378 ptr = &buffer[0];
1379 if (value < 0) {
1380 *ptr++ = '-';
1381 value = -value;
1382 }
1383 if (value == 0) {
1384 *ptr++ = '0';
1385 } else {
1386 cur = &work[0];
1387 while (value != 0) {
1388 res = value % 10;
1389 value = value / 10;
1390 *cur++ = '0' + res;
1391 }
1392 cur--;
1393 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1394 *ptr++ = *cur--;
1395 }
1396 }
1397 if (ptr - buffer < buffersize) {
1398 *ptr = 0;
1399 } else if (buffersize > 0) {
1400 ptr--;
1401 *ptr = 0;
1402 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001403 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001404 /* 3 is sign, decimal point, and terminating zero */
1405 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1406 int integer_place, fraction_place;
1407 char *ptr;
1408 char *after_fraction;
1409 double absolute_value;
1410 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001411
Bjorn Reese70a9da52001-04-21 16:57:29 +00001412 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001413
Bjorn Reese70a9da52001-04-21 16:57:29 +00001414 /*
1415 * First choose format - scientific or regular floating point.
1416 * In either case, result is in work, and after_fraction points
1417 * just past the fractional part.
1418 */
1419 if ( ((absolute_value > UPPER_DOUBLE) ||
1420 (absolute_value < LOWER_DOUBLE)) &&
1421 (absolute_value != 0.0) ) {
1422 /* Use scientific notation */
1423 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1424 fraction_place = DBL_DIG - 1;
1425 snprintf(work, sizeof(work),"%*.*e",
1426 integer_place, fraction_place, number);
1427 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001428 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001429 else {
1430 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001431 if (absolute_value > 0.0)
1432 integer_place = 1 + (int)log10(absolute_value);
1433 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001434 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001435 fraction_place = (integer_place > 0)
1436 ? DBL_DIG - integer_place
1437 : DBL_DIG;
1438 size = snprintf(work, sizeof(work), "%0.*f",
1439 fraction_place, number);
1440 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001441 }
1442
Bjorn Reese70a9da52001-04-21 16:57:29 +00001443 /* Remove fractional trailing zeroes */
1444 ptr = after_fraction;
1445 while (*(--ptr) == '0')
1446 ;
1447 if (*ptr != '.')
1448 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001449 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001450
1451 /* Finally copy result back to caller */
1452 size = strlen(work) + 1;
1453 if (size > buffersize) {
1454 work[buffersize - 1] = 0;
1455 size = buffersize;
1456 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001457 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001458 }
1459 break;
1460 }
1461}
1462
Owen Taylor3473f882001-02-23 17:55:21 +00001463
1464/************************************************************************
1465 * *
1466 * Routines to handle NodeSets *
1467 * *
1468 ************************************************************************/
1469
1470/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001471 * xmlXPathOrderDocElems:
1472 * @doc: an input document
1473 *
1474 * Call this routine to speed up XPath computation on static documents.
1475 * This stamps all the element nodes with the document order
1476 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001477 * field, the value stored is actually - the node number (starting at -1)
1478 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001479 *
William M. Brack08171912003-12-29 02:52:11 +00001480 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001481 * of error.
1482 */
1483long
1484xmlXPathOrderDocElems(xmlDocPtr doc) {
1485 long count = 0;
1486 xmlNodePtr cur;
1487
1488 if (doc == NULL)
1489 return(-1);
1490 cur = doc->children;
1491 while (cur != NULL) {
1492 if (cur->type == XML_ELEMENT_NODE) {
1493 cur->content = (void *) (-(++count));
1494 if (cur->children != NULL) {
1495 cur = cur->children;
1496 continue;
1497 }
1498 }
1499 if (cur->next != NULL) {
1500 cur = cur->next;
1501 continue;
1502 }
1503 do {
1504 cur = cur->parent;
1505 if (cur == NULL)
1506 break;
1507 if (cur == (xmlNodePtr) doc) {
1508 cur = NULL;
1509 break;
1510 }
1511 if (cur->next != NULL) {
1512 cur = cur->next;
1513 break;
1514 }
1515 } while (cur != NULL);
1516 }
1517 return(count);
1518}
1519
1520/**
Owen Taylor3473f882001-02-23 17:55:21 +00001521 * xmlXPathCmpNodes:
1522 * @node1: the first node
1523 * @node2: the second node
1524 *
1525 * Compare two nodes w.r.t document order
1526 *
1527 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001528 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001529 */
1530int
1531xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1532 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001533 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001534 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001535 xmlNodePtr cur, root;
1536
1537 if ((node1 == NULL) || (node2 == NULL))
1538 return(-2);
1539 /*
1540 * a couple of optimizations which will avoid computations in most cases
1541 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001542 if (node1->type == XML_ATTRIBUTE_NODE) {
1543 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001544 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001545 node1 = node1->parent;
1546 }
1547 if (node2->type == XML_ATTRIBUTE_NODE) {
1548 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001549 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001550 node2 = node2->parent;
1551 }
1552 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001553 if (attr1 == attr2) {
1554 /* not required, but we keep attributes in order */
1555 if (attr1 != 0) {
1556 cur = attrNode2->prev;
1557 while (cur != NULL) {
1558 if (cur == attrNode1)
1559 return (1);
1560 cur = cur->prev;
1561 }
1562 return (-1);
1563 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001564 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001565 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001566 if (attr2 == 1)
1567 return(1);
1568 return(-1);
1569 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001570 if ((node1->type == XML_NAMESPACE_DECL) ||
1571 (node2->type == XML_NAMESPACE_DECL))
1572 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001573 if (node1 == node2->prev)
1574 return(1);
1575 if (node1 == node2->next)
1576 return(-1);
1577
1578 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001579 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001580 */
1581 if ((node1->type == XML_ELEMENT_NODE) &&
1582 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001583 (0 > (long) node1->content) &&
1584 (0 > (long) node2->content) &&
1585 (node1->doc == node2->doc)) {
1586 long l1, l2;
1587
1588 l1 = -((long) node1->content);
1589 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001590 if (l1 < l2)
1591 return(1);
1592 if (l1 > l2)
1593 return(-1);
1594 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001595
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001596 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001597 * compute depth to root
1598 */
1599 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1600 if (cur == node1)
1601 return(1);
1602 depth2++;
1603 }
1604 root = cur;
1605 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1606 if (cur == node2)
1607 return(-1);
1608 depth1++;
1609 }
1610 /*
1611 * Distinct document (or distinct entities :-( ) case.
1612 */
1613 if (root != cur) {
1614 return(-2);
1615 }
1616 /*
1617 * get the nearest common ancestor.
1618 */
1619 while (depth1 > depth2) {
1620 depth1--;
1621 node1 = node1->parent;
1622 }
1623 while (depth2 > depth1) {
1624 depth2--;
1625 node2 = node2->parent;
1626 }
1627 while (node1->parent != node2->parent) {
1628 node1 = node1->parent;
1629 node2 = node2->parent;
1630 /* should not happen but just in case ... */
1631 if ((node1 == NULL) || (node2 == NULL))
1632 return(-2);
1633 }
1634 /*
1635 * Find who's first.
1636 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001637 if (node1 == node2->prev)
1638 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001639 if (node1 == node2->next)
1640 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001641 /*
1642 * Speedup using document order if availble.
1643 */
1644 if ((node1->type == XML_ELEMENT_NODE) &&
1645 (node2->type == XML_ELEMENT_NODE) &&
1646 (0 > (long) node1->content) &&
1647 (0 > (long) node2->content) &&
1648 (node1->doc == node2->doc)) {
1649 long l1, l2;
1650
1651 l1 = -((long) node1->content);
1652 l2 = -((long) node2->content);
1653 if (l1 < l2)
1654 return(1);
1655 if (l1 > l2)
1656 return(-1);
1657 }
1658
Owen Taylor3473f882001-02-23 17:55:21 +00001659 for (cur = node1->next;cur != NULL;cur = cur->next)
1660 if (cur == node2)
1661 return(1);
1662 return(-1); /* assume there is no sibling list corruption */
1663}
1664
1665/**
1666 * xmlXPathNodeSetSort:
1667 * @set: the node set
1668 *
1669 * Sort the node set in document order
1670 */
1671void
1672xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001673 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001674 xmlNodePtr tmp;
1675
1676 if (set == NULL)
1677 return;
1678
1679 /* Use Shell's sort to sort the node-set */
1680 len = set->nodeNr;
1681 for (incr = len / 2; incr > 0; incr /= 2) {
1682 for (i = incr; i < len; i++) {
1683 j = i - incr;
1684 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001685 if (xmlXPathCmpNodes(set->nodeTab[j],
1686 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001687 tmp = set->nodeTab[j];
1688 set->nodeTab[j] = set->nodeTab[j + incr];
1689 set->nodeTab[j + incr] = tmp;
1690 j -= incr;
1691 } else
1692 break;
1693 }
1694 }
1695 }
1696}
1697
1698#define XML_NODESET_DEFAULT 10
1699/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001700 * xmlXPathNodeSetDupNs:
1701 * @node: the parent node of the namespace XPath node
1702 * @ns: the libxml namespace declaration node.
1703 *
1704 * Namespace node in libxml don't match the XPath semantic. In a node set
1705 * the namespace nodes are duplicated and the next pointer is set to the
1706 * parent node in the XPath semantic.
1707 *
1708 * Returns the newly created object.
1709 */
1710static xmlNodePtr
1711xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1712 xmlNsPtr cur;
1713
1714 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1715 return(NULL);
1716 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1717 return((xmlNodePtr) ns);
1718
1719 /*
1720 * Allocate a new Namespace and fill the fields.
1721 */
1722 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1723 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001724 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001725 return(NULL);
1726 }
1727 memset(cur, 0, sizeof(xmlNs));
1728 cur->type = XML_NAMESPACE_DECL;
1729 if (ns->href != NULL)
1730 cur->href = xmlStrdup(ns->href);
1731 if (ns->prefix != NULL)
1732 cur->prefix = xmlStrdup(ns->prefix);
1733 cur->next = (xmlNsPtr) node;
1734 return((xmlNodePtr) cur);
1735}
1736
1737/**
1738 * xmlXPathNodeSetFreeNs:
1739 * @ns: the XPath namespace node found in a nodeset.
1740 *
William M. Brack08171912003-12-29 02:52:11 +00001741 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001742 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001743 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001744 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001745void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001746xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1747 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1748 return;
1749
1750 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1751 if (ns->href != NULL)
1752 xmlFree((xmlChar *)ns->href);
1753 if (ns->prefix != NULL)
1754 xmlFree((xmlChar *)ns->prefix);
1755 xmlFree(ns);
1756 }
1757}
1758
1759/**
Owen Taylor3473f882001-02-23 17:55:21 +00001760 * xmlXPathNodeSetCreate:
1761 * @val: an initial xmlNodePtr, or NULL
1762 *
1763 * Create a new xmlNodeSetPtr of type double and of value @val
1764 *
1765 * Returns the newly created object.
1766 */
1767xmlNodeSetPtr
1768xmlXPathNodeSetCreate(xmlNodePtr val) {
1769 xmlNodeSetPtr ret;
1770
1771 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1772 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001773 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001774 return(NULL);
1775 }
1776 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1777 if (val != NULL) {
1778 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1779 sizeof(xmlNodePtr));
1780 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001781 xmlXPathErrMemory(NULL, "creating nodeset\n");
1782 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001783 return(NULL);
1784 }
1785 memset(ret->nodeTab, 0 ,
1786 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1787 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001788 if (val->type == XML_NAMESPACE_DECL) {
1789 xmlNsPtr ns = (xmlNsPtr) val;
1790
1791 ret->nodeTab[ret->nodeNr++] =
1792 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1793 } else
1794 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001795 }
1796 return(ret);
1797}
1798
1799/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001800 * xmlXPathNodeSetContains:
1801 * @cur: the node-set
1802 * @val: the node
1803 *
1804 * checks whether @cur contains @val
1805 *
1806 * Returns true (1) if @cur contains @val, false (0) otherwise
1807 */
1808int
1809xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1810 int i;
1811
Daniel Veillarda82b1822004-11-08 16:24:57 +00001812 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001813 if (val->type == XML_NAMESPACE_DECL) {
1814 for (i = 0; i < cur->nodeNr; i++) {
1815 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1816 xmlNsPtr ns1, ns2;
1817
1818 ns1 = (xmlNsPtr) val;
1819 ns2 = (xmlNsPtr) cur->nodeTab[i];
1820 if (ns1 == ns2)
1821 return(1);
1822 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1823 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1824 return(1);
1825 }
1826 }
1827 } else {
1828 for (i = 0; i < cur->nodeNr; i++) {
1829 if (cur->nodeTab[i] == val)
1830 return(1);
1831 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001832 }
1833 return(0);
1834}
1835
1836/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001837 * xmlXPathNodeSetAddNs:
1838 * @cur: the initial node set
1839 * @node: the hosting node
1840 * @ns: a the namespace node
1841 *
1842 * add a new namespace node to an existing NodeSet
1843 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001844void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001845xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1846 int i;
1847
Daniel Veillarda82b1822004-11-08 16:24:57 +00001848
1849 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
1850 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001851 (node->type != XML_ELEMENT_NODE))
1852 return;
1853
William M. Brack08171912003-12-29 02:52:11 +00001854 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001855 /*
William M. Brack08171912003-12-29 02:52:11 +00001856 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001857 */
1858 for (i = 0;i < cur->nodeNr;i++) {
1859 if ((cur->nodeTab[i] != NULL) &&
1860 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001861 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001862 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1863 return;
1864 }
1865
1866 /*
1867 * grow the nodeTab if needed
1868 */
1869 if (cur->nodeMax == 0) {
1870 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1871 sizeof(xmlNodePtr));
1872 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001873 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001874 return;
1875 }
1876 memset(cur->nodeTab, 0 ,
1877 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1878 cur->nodeMax = XML_NODESET_DEFAULT;
1879 } else if (cur->nodeNr == cur->nodeMax) {
1880 xmlNodePtr *temp;
1881
1882 cur->nodeMax *= 2;
1883 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1884 sizeof(xmlNodePtr));
1885 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001886 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001887 return;
1888 }
1889 cur->nodeTab = temp;
1890 }
1891 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1892}
1893
1894/**
Owen Taylor3473f882001-02-23 17:55:21 +00001895 * xmlXPathNodeSetAdd:
1896 * @cur: the initial node set
1897 * @val: a new xmlNodePtr
1898 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001899 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001900 */
1901void
1902xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1903 int i;
1904
Daniel Veillarda82b1822004-11-08 16:24:57 +00001905 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001906
Daniel Veillardef0b4502003-03-24 13:57:34 +00001907#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001908 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1909 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001910#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001911
William M. Brack08171912003-12-29 02:52:11 +00001912 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001913 /*
William M. Brack08171912003-12-29 02:52:11 +00001914 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001915 */
1916 for (i = 0;i < cur->nodeNr;i++)
1917 if (cur->nodeTab[i] == val) return;
1918
1919 /*
1920 * grow the nodeTab if needed
1921 */
1922 if (cur->nodeMax == 0) {
1923 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1924 sizeof(xmlNodePtr));
1925 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001926 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001927 return;
1928 }
1929 memset(cur->nodeTab, 0 ,
1930 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1931 cur->nodeMax = XML_NODESET_DEFAULT;
1932 } else if (cur->nodeNr == cur->nodeMax) {
1933 xmlNodePtr *temp;
1934
1935 cur->nodeMax *= 2;
1936 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1937 sizeof(xmlNodePtr));
1938 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001939 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001940 return;
1941 }
1942 cur->nodeTab = temp;
1943 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001944 if (val->type == XML_NAMESPACE_DECL) {
1945 xmlNsPtr ns = (xmlNsPtr) val;
1946
1947 cur->nodeTab[cur->nodeNr++] =
1948 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1949 } else
1950 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001951}
1952
1953/**
1954 * xmlXPathNodeSetAddUnique:
1955 * @cur: the initial node set
1956 * @val: a new xmlNodePtr
1957 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001958 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001959 * when we are sure the node is not already in the set.
1960 */
1961void
1962xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00001963 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001964
Daniel Veillardef0b4502003-03-24 13:57:34 +00001965#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001966 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1967 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001968#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001969
William M. Brack08171912003-12-29 02:52:11 +00001970 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001971 /*
1972 * grow the nodeTab if needed
1973 */
1974 if (cur->nodeMax == 0) {
1975 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1976 sizeof(xmlNodePtr));
1977 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001978 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001979 return;
1980 }
1981 memset(cur->nodeTab, 0 ,
1982 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1983 cur->nodeMax = XML_NODESET_DEFAULT;
1984 } else if (cur->nodeNr == cur->nodeMax) {
1985 xmlNodePtr *temp;
1986
1987 cur->nodeMax *= 2;
1988 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1989 sizeof(xmlNodePtr));
1990 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001991 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001992 return;
1993 }
1994 cur->nodeTab = temp;
1995 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001996 if (val->type == XML_NAMESPACE_DECL) {
1997 xmlNsPtr ns = (xmlNsPtr) val;
1998
1999 cur->nodeTab[cur->nodeNr++] =
2000 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2001 } else
2002 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002003}
2004
2005/**
2006 * xmlXPathNodeSetMerge:
2007 * @val1: the first NodeSet or NULL
2008 * @val2: the second NodeSet
2009 *
2010 * Merges two nodesets, all nodes from @val2 are added to @val1
2011 * if @val1 is NULL, a new set is created and copied from @val2
2012 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002013 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002014 */
2015xmlNodeSetPtr
2016xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002017 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002018
2019 if (val2 == NULL) return(val1);
2020 if (val1 == NULL) {
2021 val1 = xmlXPathNodeSetCreate(NULL);
2022 }
2023
William M. Brack08171912003-12-29 02:52:11 +00002024 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002025 initNr = val1->nodeNr;
2026
2027 for (i = 0;i < val2->nodeNr;i++) {
2028 /*
William M. Brack08171912003-12-29 02:52:11 +00002029 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002030 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002031 skip = 0;
2032 for (j = 0; j < initNr; j++) {
2033 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2034 skip = 1;
2035 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002036 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2037 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2038 xmlNsPtr ns1, ns2;
2039 ns1 = (xmlNsPtr) val1->nodeTab[j];
2040 ns2 = (xmlNsPtr) val2->nodeTab[i];
2041 if ((ns1->next == ns2->next) &&
2042 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2043 skip = 1;
2044 break;
2045 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002046 }
2047 }
2048 if (skip)
2049 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002050
2051 /*
2052 * grow the nodeTab if needed
2053 */
2054 if (val1->nodeMax == 0) {
2055 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2056 sizeof(xmlNodePtr));
2057 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002058 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002059 return(NULL);
2060 }
2061 memset(val1->nodeTab, 0 ,
2062 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2063 val1->nodeMax = XML_NODESET_DEFAULT;
2064 } else if (val1->nodeNr == val1->nodeMax) {
2065 xmlNodePtr *temp;
2066
2067 val1->nodeMax *= 2;
2068 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2069 sizeof(xmlNodePtr));
2070 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002071 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002072 return(NULL);
2073 }
2074 val1->nodeTab = temp;
2075 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002076 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2077 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2078
2079 val1->nodeTab[val1->nodeNr++] =
2080 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2081 } else
2082 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002083 }
2084
2085 return(val1);
2086}
2087
2088/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002089 * xmlXPathNodeSetMergeUnique:
2090 * @val1: the first NodeSet or NULL
2091 * @val2: the second NodeSet
2092 *
2093 * Merges two nodesets, all nodes from @val2 are added to @val1
2094 * if @val1 is NULL, a new set is created and copied from @val2
2095 *
2096 * Returns @val1 once extended or NULL in case of error.
2097 */
2098static xmlNodeSetPtr
2099xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002100 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002101
2102 if (val2 == NULL) return(val1);
2103 if (val1 == NULL) {
2104 val1 = xmlXPathNodeSetCreate(NULL);
2105 }
2106
William M. Brack08171912003-12-29 02:52:11 +00002107 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002108
2109 for (i = 0;i < val2->nodeNr;i++) {
2110 /*
2111 * grow the nodeTab if needed
2112 */
2113 if (val1->nodeMax == 0) {
2114 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2115 sizeof(xmlNodePtr));
2116 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002117 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002118 return(NULL);
2119 }
2120 memset(val1->nodeTab, 0 ,
2121 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2122 val1->nodeMax = XML_NODESET_DEFAULT;
2123 } else if (val1->nodeNr == val1->nodeMax) {
2124 xmlNodePtr *temp;
2125
2126 val1->nodeMax *= 2;
2127 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2128 sizeof(xmlNodePtr));
2129 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002130 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002131 return(NULL);
2132 }
2133 val1->nodeTab = temp;
2134 }
2135 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2136 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2137
2138 val1->nodeTab[val1->nodeNr++] =
2139 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2140 } else
2141 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2142 }
2143
2144 return(val1);
2145}
2146
2147/**
Owen Taylor3473f882001-02-23 17:55:21 +00002148 * xmlXPathNodeSetDel:
2149 * @cur: the initial node set
2150 * @val: an xmlNodePtr
2151 *
2152 * Removes an xmlNodePtr from an existing NodeSet
2153 */
2154void
2155xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2156 int i;
2157
2158 if (cur == NULL) return;
2159 if (val == NULL) return;
2160
2161 /*
William M. Brack08171912003-12-29 02:52:11 +00002162 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002163 */
2164 for (i = 0;i < cur->nodeNr;i++)
2165 if (cur->nodeTab[i] == val) break;
2166
William M. Brack08171912003-12-29 02:52:11 +00002167 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002168#ifdef DEBUG
2169 xmlGenericError(xmlGenericErrorContext,
2170 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2171 val->name);
2172#endif
2173 return;
2174 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002175 if ((cur->nodeTab[i] != NULL) &&
2176 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2177 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002178 cur->nodeNr--;
2179 for (;i < cur->nodeNr;i++)
2180 cur->nodeTab[i] = cur->nodeTab[i + 1];
2181 cur->nodeTab[cur->nodeNr] = NULL;
2182}
2183
2184/**
2185 * xmlXPathNodeSetRemove:
2186 * @cur: the initial node set
2187 * @val: the index to remove
2188 *
2189 * Removes an entry from an existing NodeSet list.
2190 */
2191void
2192xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2193 if (cur == NULL) return;
2194 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002195 if ((cur->nodeTab[val] != NULL) &&
2196 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2197 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002198 cur->nodeNr--;
2199 for (;val < cur->nodeNr;val++)
2200 cur->nodeTab[val] = cur->nodeTab[val + 1];
2201 cur->nodeTab[cur->nodeNr] = NULL;
2202}
2203
2204/**
2205 * xmlXPathFreeNodeSet:
2206 * @obj: the xmlNodeSetPtr to free
2207 *
2208 * Free the NodeSet compound (not the actual nodes !).
2209 */
2210void
2211xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2212 if (obj == NULL) return;
2213 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002214 int i;
2215
William M. Brack08171912003-12-29 02:52:11 +00002216 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002217 for (i = 0;i < obj->nodeNr;i++)
2218 if ((obj->nodeTab[i] != NULL) &&
2219 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2220 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002221 xmlFree(obj->nodeTab);
2222 }
Owen Taylor3473f882001-02-23 17:55:21 +00002223 xmlFree(obj);
2224}
2225
2226/**
2227 * xmlXPathFreeValueTree:
2228 * @obj: the xmlNodeSetPtr to free
2229 *
2230 * Free the NodeSet compound and the actual tree, this is different
2231 * from xmlXPathFreeNodeSet()
2232 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002233static void
Owen Taylor3473f882001-02-23 17:55:21 +00002234xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2235 int i;
2236
2237 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002238
2239 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002240 for (i = 0;i < obj->nodeNr;i++) {
2241 if (obj->nodeTab[i] != NULL) {
2242 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2243 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2244 } else {
2245 xmlFreeNodeList(obj->nodeTab[i]);
2246 }
2247 }
2248 }
Owen Taylor3473f882001-02-23 17:55:21 +00002249 xmlFree(obj->nodeTab);
2250 }
Owen Taylor3473f882001-02-23 17:55:21 +00002251 xmlFree(obj);
2252}
2253
2254#if defined(DEBUG) || defined(DEBUG_STEP)
2255/**
2256 * xmlGenericErrorContextNodeSet:
2257 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002258 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002259 *
2260 * Quick display of a NodeSet
2261 */
2262void
2263xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2264 int i;
2265
2266 if (output == NULL) output = xmlGenericErrorContext;
2267 if (obj == NULL) {
2268 fprintf(output, "NodeSet == NULL !\n");
2269 return;
2270 }
2271 if (obj->nodeNr == 0) {
2272 fprintf(output, "NodeSet is empty\n");
2273 return;
2274 }
2275 if (obj->nodeTab == NULL) {
2276 fprintf(output, " nodeTab == NULL !\n");
2277 return;
2278 }
2279 for (i = 0; i < obj->nodeNr; i++) {
2280 if (obj->nodeTab[i] == NULL) {
2281 fprintf(output, " NULL !\n");
2282 return;
2283 }
2284 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2285 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2286 fprintf(output, " /");
2287 else if (obj->nodeTab[i]->name == NULL)
2288 fprintf(output, " noname!");
2289 else fprintf(output, " %s", obj->nodeTab[i]->name);
2290 }
2291 fprintf(output, "\n");
2292}
2293#endif
2294
2295/**
2296 * xmlXPathNewNodeSet:
2297 * @val: the NodePtr value
2298 *
2299 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2300 * it with the single Node @val
2301 *
2302 * Returns the newly created object.
2303 */
2304xmlXPathObjectPtr
2305xmlXPathNewNodeSet(xmlNodePtr val) {
2306 xmlXPathObjectPtr ret;
2307
2308 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2309 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002310 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002311 return(NULL);
2312 }
2313 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2314 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002315 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002316 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002317 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002318 return(ret);
2319}
2320
2321/**
2322 * xmlXPathNewValueTree:
2323 * @val: the NodePtr value
2324 *
2325 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2326 * it with the tree root @val
2327 *
2328 * Returns the newly created object.
2329 */
2330xmlXPathObjectPtr
2331xmlXPathNewValueTree(xmlNodePtr val) {
2332 xmlXPathObjectPtr ret;
2333
2334 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2335 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002336 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002337 return(NULL);
2338 }
2339 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2340 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002341 ret->boolval = 1;
2342 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002343 ret->nodesetval = xmlXPathNodeSetCreate(val);
2344 return(ret);
2345}
2346
2347/**
2348 * xmlXPathNewNodeSetList:
2349 * @val: an existing NodeSet
2350 *
2351 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2352 * it with the Nodeset @val
2353 *
2354 * Returns the newly created object.
2355 */
2356xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002357xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2358{
Owen Taylor3473f882001-02-23 17:55:21 +00002359 xmlXPathObjectPtr ret;
2360 int i;
2361
2362 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002363 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002364 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002365 ret = xmlXPathNewNodeSet(NULL);
2366 else {
2367 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2368 for (i = 1; i < val->nodeNr; ++i)
2369 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2370 }
Owen Taylor3473f882001-02-23 17:55:21 +00002371
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002372 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002373}
2374
2375/**
2376 * xmlXPathWrapNodeSet:
2377 * @val: the NodePtr value
2378 *
2379 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2380 *
2381 * Returns the newly created object.
2382 */
2383xmlXPathObjectPtr
2384xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2385 xmlXPathObjectPtr ret;
2386
2387 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2388 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002389 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002390 return(NULL);
2391 }
2392 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2393 ret->type = XPATH_NODESET;
2394 ret->nodesetval = val;
2395 return(ret);
2396}
2397
2398/**
2399 * xmlXPathFreeNodeSetList:
2400 * @obj: an existing NodeSetList object
2401 *
2402 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2403 * the list contrary to xmlXPathFreeObject().
2404 */
2405void
2406xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2407 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002408 xmlFree(obj);
2409}
2410
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002411/**
2412 * xmlXPathDifference:
2413 * @nodes1: a node-set
2414 * @nodes2: a node-set
2415 *
2416 * Implements the EXSLT - Sets difference() function:
2417 * node-set set:difference (node-set, node-set)
2418 *
2419 * Returns the difference between the two node sets, or nodes1 if
2420 * nodes2 is empty
2421 */
2422xmlNodeSetPtr
2423xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2424 xmlNodeSetPtr ret;
2425 int i, l1;
2426 xmlNodePtr cur;
2427
2428 if (xmlXPathNodeSetIsEmpty(nodes2))
2429 return(nodes1);
2430
2431 ret = xmlXPathNodeSetCreate(NULL);
2432 if (xmlXPathNodeSetIsEmpty(nodes1))
2433 return(ret);
2434
2435 l1 = xmlXPathNodeSetGetLength(nodes1);
2436
2437 for (i = 0; i < l1; i++) {
2438 cur = xmlXPathNodeSetItem(nodes1, i);
2439 if (!xmlXPathNodeSetContains(nodes2, cur))
2440 xmlXPathNodeSetAddUnique(ret, cur);
2441 }
2442 return(ret);
2443}
2444
2445/**
2446 * xmlXPathIntersection:
2447 * @nodes1: a node-set
2448 * @nodes2: a node-set
2449 *
2450 * Implements the EXSLT - Sets intersection() function:
2451 * node-set set:intersection (node-set, node-set)
2452 *
2453 * Returns a node set comprising the nodes that are within both the
2454 * node sets passed as arguments
2455 */
2456xmlNodeSetPtr
2457xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2458 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2459 int i, l1;
2460 xmlNodePtr cur;
2461
2462 if (xmlXPathNodeSetIsEmpty(nodes1))
2463 return(ret);
2464 if (xmlXPathNodeSetIsEmpty(nodes2))
2465 return(ret);
2466
2467 l1 = xmlXPathNodeSetGetLength(nodes1);
2468
2469 for (i = 0; i < l1; i++) {
2470 cur = xmlXPathNodeSetItem(nodes1, i);
2471 if (xmlXPathNodeSetContains(nodes2, cur))
2472 xmlXPathNodeSetAddUnique(ret, cur);
2473 }
2474 return(ret);
2475}
2476
2477/**
2478 * xmlXPathDistinctSorted:
2479 * @nodes: a node-set, sorted by document order
2480 *
2481 * Implements the EXSLT - Sets distinct() function:
2482 * node-set set:distinct (node-set)
2483 *
2484 * Returns a subset of the nodes contained in @nodes, or @nodes if
2485 * it is empty
2486 */
2487xmlNodeSetPtr
2488xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2489 xmlNodeSetPtr ret;
2490 xmlHashTablePtr hash;
2491 int i, l;
2492 xmlChar * strval;
2493 xmlNodePtr cur;
2494
2495 if (xmlXPathNodeSetIsEmpty(nodes))
2496 return(nodes);
2497
2498 ret = xmlXPathNodeSetCreate(NULL);
2499 l = xmlXPathNodeSetGetLength(nodes);
2500 hash = xmlHashCreate (l);
2501 for (i = 0; i < l; i++) {
2502 cur = xmlXPathNodeSetItem(nodes, i);
2503 strval = xmlXPathCastNodeToString(cur);
2504 if (xmlHashLookup(hash, strval) == NULL) {
2505 xmlHashAddEntry(hash, strval, strval);
2506 xmlXPathNodeSetAddUnique(ret, cur);
2507 } else {
2508 xmlFree(strval);
2509 }
2510 }
2511 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2512 return(ret);
2513}
2514
2515/**
2516 * xmlXPathDistinct:
2517 * @nodes: a node-set
2518 *
2519 * Implements the EXSLT - Sets distinct() function:
2520 * node-set set:distinct (node-set)
2521 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2522 * is called with the sorted node-set
2523 *
2524 * Returns a subset of the nodes contained in @nodes, or @nodes if
2525 * it is empty
2526 */
2527xmlNodeSetPtr
2528xmlXPathDistinct (xmlNodeSetPtr nodes) {
2529 if (xmlXPathNodeSetIsEmpty(nodes))
2530 return(nodes);
2531
2532 xmlXPathNodeSetSort(nodes);
2533 return(xmlXPathDistinctSorted(nodes));
2534}
2535
2536/**
2537 * xmlXPathHasSameNodes:
2538 * @nodes1: a node-set
2539 * @nodes2: a node-set
2540 *
2541 * Implements the EXSLT - Sets has-same-nodes function:
2542 * boolean set:has-same-node(node-set, node-set)
2543 *
2544 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2545 * otherwise
2546 */
2547int
2548xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2549 int i, l;
2550 xmlNodePtr cur;
2551
2552 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2553 xmlXPathNodeSetIsEmpty(nodes2))
2554 return(0);
2555
2556 l = xmlXPathNodeSetGetLength(nodes1);
2557 for (i = 0; i < l; i++) {
2558 cur = xmlXPathNodeSetItem(nodes1, i);
2559 if (xmlXPathNodeSetContains(nodes2, cur))
2560 return(1);
2561 }
2562 return(0);
2563}
2564
2565/**
2566 * xmlXPathNodeLeadingSorted:
2567 * @nodes: a node-set, sorted by document order
2568 * @node: a node
2569 *
2570 * Implements the EXSLT - Sets leading() function:
2571 * node-set set:leading (node-set, node-set)
2572 *
2573 * Returns the nodes in @nodes that precede @node in document order,
2574 * @nodes if @node is NULL or an empty node-set if @nodes
2575 * doesn't contain @node
2576 */
2577xmlNodeSetPtr
2578xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2579 int i, l;
2580 xmlNodePtr cur;
2581 xmlNodeSetPtr ret;
2582
2583 if (node == NULL)
2584 return(nodes);
2585
2586 ret = xmlXPathNodeSetCreate(NULL);
2587 if (xmlXPathNodeSetIsEmpty(nodes) ||
2588 (!xmlXPathNodeSetContains(nodes, node)))
2589 return(ret);
2590
2591 l = xmlXPathNodeSetGetLength(nodes);
2592 for (i = 0; i < l; i++) {
2593 cur = xmlXPathNodeSetItem(nodes, i);
2594 if (cur == node)
2595 break;
2596 xmlXPathNodeSetAddUnique(ret, cur);
2597 }
2598 return(ret);
2599}
2600
2601/**
2602 * xmlXPathNodeLeading:
2603 * @nodes: a node-set
2604 * @node: a node
2605 *
2606 * Implements the EXSLT - Sets leading() function:
2607 * node-set set:leading (node-set, node-set)
2608 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2609 * is called.
2610 *
2611 * Returns the nodes in @nodes that precede @node in document order,
2612 * @nodes if @node is NULL or an empty node-set if @nodes
2613 * doesn't contain @node
2614 */
2615xmlNodeSetPtr
2616xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2617 xmlXPathNodeSetSort(nodes);
2618 return(xmlXPathNodeLeadingSorted(nodes, node));
2619}
2620
2621/**
2622 * xmlXPathLeadingSorted:
2623 * @nodes1: a node-set, sorted by document order
2624 * @nodes2: a node-set, sorted by document order
2625 *
2626 * Implements the EXSLT - Sets leading() function:
2627 * node-set set:leading (node-set, node-set)
2628 *
2629 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2630 * in document order, @nodes1 if @nodes2 is NULL or empty or
2631 * an empty node-set if @nodes1 doesn't contain @nodes2
2632 */
2633xmlNodeSetPtr
2634xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2635 if (xmlXPathNodeSetIsEmpty(nodes2))
2636 return(nodes1);
2637 return(xmlXPathNodeLeadingSorted(nodes1,
2638 xmlXPathNodeSetItem(nodes2, 1)));
2639}
2640
2641/**
2642 * xmlXPathLeading:
2643 * @nodes1: a node-set
2644 * @nodes2: a node-set
2645 *
2646 * Implements the EXSLT - Sets leading() function:
2647 * node-set set:leading (node-set, node-set)
2648 * @nodes1 and @nodes2 are sorted by document order, then
2649 * #exslSetsLeadingSorted is called.
2650 *
2651 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2652 * in document order, @nodes1 if @nodes2 is NULL or empty or
2653 * an empty node-set if @nodes1 doesn't contain @nodes2
2654 */
2655xmlNodeSetPtr
2656xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2657 if (xmlXPathNodeSetIsEmpty(nodes2))
2658 return(nodes1);
2659 if (xmlXPathNodeSetIsEmpty(nodes1))
2660 return(xmlXPathNodeSetCreate(NULL));
2661 xmlXPathNodeSetSort(nodes1);
2662 xmlXPathNodeSetSort(nodes2);
2663 return(xmlXPathNodeLeadingSorted(nodes1,
2664 xmlXPathNodeSetItem(nodes2, 1)));
2665}
2666
2667/**
2668 * xmlXPathNodeTrailingSorted:
2669 * @nodes: a node-set, sorted by document order
2670 * @node: a node
2671 *
2672 * Implements the EXSLT - Sets trailing() function:
2673 * node-set set:trailing (node-set, node-set)
2674 *
2675 * Returns the nodes in @nodes that follow @node in document order,
2676 * @nodes if @node is NULL or an empty node-set if @nodes
2677 * doesn't contain @node
2678 */
2679xmlNodeSetPtr
2680xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2681 int i, l;
2682 xmlNodePtr cur;
2683 xmlNodeSetPtr ret;
2684
2685 if (node == NULL)
2686 return(nodes);
2687
2688 ret = xmlXPathNodeSetCreate(NULL);
2689 if (xmlXPathNodeSetIsEmpty(nodes) ||
2690 (!xmlXPathNodeSetContains(nodes, node)))
2691 return(ret);
2692
2693 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002694 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002695 cur = xmlXPathNodeSetItem(nodes, i);
2696 if (cur == node)
2697 break;
2698 xmlXPathNodeSetAddUnique(ret, cur);
2699 }
2700 return(ret);
2701}
2702
2703/**
2704 * xmlXPathNodeTrailing:
2705 * @nodes: a node-set
2706 * @node: a node
2707 *
2708 * Implements the EXSLT - Sets trailing() function:
2709 * node-set set:trailing (node-set, node-set)
2710 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2711 * is called.
2712 *
2713 * Returns the nodes in @nodes that follow @node in document order,
2714 * @nodes if @node is NULL or an empty node-set if @nodes
2715 * doesn't contain @node
2716 */
2717xmlNodeSetPtr
2718xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2719 xmlXPathNodeSetSort(nodes);
2720 return(xmlXPathNodeTrailingSorted(nodes, node));
2721}
2722
2723/**
2724 * xmlXPathTrailingSorted:
2725 * @nodes1: a node-set, sorted by document order
2726 * @nodes2: a node-set, sorted by document order
2727 *
2728 * Implements the EXSLT - Sets trailing() function:
2729 * node-set set:trailing (node-set, node-set)
2730 *
2731 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2732 * in document order, @nodes1 if @nodes2 is NULL or empty or
2733 * an empty node-set if @nodes1 doesn't contain @nodes2
2734 */
2735xmlNodeSetPtr
2736xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2737 if (xmlXPathNodeSetIsEmpty(nodes2))
2738 return(nodes1);
2739 return(xmlXPathNodeTrailingSorted(nodes1,
2740 xmlXPathNodeSetItem(nodes2, 0)));
2741}
2742
2743/**
2744 * xmlXPathTrailing:
2745 * @nodes1: a node-set
2746 * @nodes2: a node-set
2747 *
2748 * Implements the EXSLT - Sets trailing() function:
2749 * node-set set:trailing (node-set, node-set)
2750 * @nodes1 and @nodes2 are sorted by document order, then
2751 * #xmlXPathTrailingSorted is called.
2752 *
2753 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2754 * in document order, @nodes1 if @nodes2 is NULL or empty or
2755 * an empty node-set if @nodes1 doesn't contain @nodes2
2756 */
2757xmlNodeSetPtr
2758xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2759 if (xmlXPathNodeSetIsEmpty(nodes2))
2760 return(nodes1);
2761 if (xmlXPathNodeSetIsEmpty(nodes1))
2762 return(xmlXPathNodeSetCreate(NULL));
2763 xmlXPathNodeSetSort(nodes1);
2764 xmlXPathNodeSetSort(nodes2);
2765 return(xmlXPathNodeTrailingSorted(nodes1,
2766 xmlXPathNodeSetItem(nodes2, 0)));
2767}
2768
Owen Taylor3473f882001-02-23 17:55:21 +00002769/************************************************************************
2770 * *
2771 * Routines to handle extra functions *
2772 * *
2773 ************************************************************************/
2774
2775/**
2776 * xmlXPathRegisterFunc:
2777 * @ctxt: the XPath context
2778 * @name: the function name
2779 * @f: the function implementation or NULL
2780 *
2781 * Register a new function. If @f is NULL it unregisters the function
2782 *
2783 * Returns 0 in case of success, -1 in case of error
2784 */
2785int
2786xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2787 xmlXPathFunction f) {
2788 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2789}
2790
2791/**
2792 * xmlXPathRegisterFuncNS:
2793 * @ctxt: the XPath context
2794 * @name: the function name
2795 * @ns_uri: the function namespace URI
2796 * @f: the function implementation or NULL
2797 *
2798 * Register a new function. If @f is NULL it unregisters the function
2799 *
2800 * Returns 0 in case of success, -1 in case of error
2801 */
2802int
2803xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2804 const xmlChar *ns_uri, xmlXPathFunction f) {
2805 if (ctxt == NULL)
2806 return(-1);
2807 if (name == NULL)
2808 return(-1);
2809
2810 if (ctxt->funcHash == NULL)
2811 ctxt->funcHash = xmlHashCreate(0);
2812 if (ctxt->funcHash == NULL)
2813 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002814 if (f == NULL)
2815 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002816 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2817}
2818
2819/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002820 * xmlXPathRegisterFuncLookup:
2821 * @ctxt: the XPath context
2822 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002823 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002824 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002825 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002826 */
2827void
2828xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2829 xmlXPathFuncLookupFunc f,
2830 void *funcCtxt) {
2831 if (ctxt == NULL)
2832 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002833 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002834 ctxt->funcLookupData = funcCtxt;
2835}
2836
2837/**
Owen Taylor3473f882001-02-23 17:55:21 +00002838 * xmlXPathFunctionLookup:
2839 * @ctxt: the XPath context
2840 * @name: the function name
2841 *
2842 * Search in the Function array of the context for the given
2843 * function.
2844 *
2845 * Returns the xmlXPathFunction or NULL if not found
2846 */
2847xmlXPathFunction
2848xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002849 if (ctxt == NULL)
2850 return (NULL);
2851
2852 if (ctxt->funcLookupFunc != NULL) {
2853 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002854 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002855
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002856 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002857 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002858 if (ret != NULL)
2859 return(ret);
2860 }
Owen Taylor3473f882001-02-23 17:55:21 +00002861 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2862}
2863
2864/**
2865 * xmlXPathFunctionLookupNS:
2866 * @ctxt: the XPath context
2867 * @name: the function name
2868 * @ns_uri: the function namespace URI
2869 *
2870 * Search in the Function array of the context for the given
2871 * function.
2872 *
2873 * Returns the xmlXPathFunction or NULL if not found
2874 */
2875xmlXPathFunction
2876xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2877 const xmlChar *ns_uri) {
2878 if (ctxt == NULL)
2879 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002880 if (name == NULL)
2881 return(NULL);
2882
Thomas Broyerba4ad322001-07-26 16:55:21 +00002883 if (ctxt->funcLookupFunc != NULL) {
2884 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002885 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002886
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002887 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002888 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002889 if (ret != NULL)
2890 return(ret);
2891 }
2892
2893 if (ctxt->funcHash == NULL)
2894 return(NULL);
2895
Owen Taylor3473f882001-02-23 17:55:21 +00002896 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2897}
2898
2899/**
2900 * xmlXPathRegisteredFuncsCleanup:
2901 * @ctxt: the XPath context
2902 *
2903 * Cleanup the XPath context data associated to registered functions
2904 */
2905void
2906xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2907 if (ctxt == NULL)
2908 return;
2909
2910 xmlHashFree(ctxt->funcHash, NULL);
2911 ctxt->funcHash = NULL;
2912}
2913
2914/************************************************************************
2915 * *
William M. Brack08171912003-12-29 02:52:11 +00002916 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002917 * *
2918 ************************************************************************/
2919
2920/**
2921 * xmlXPathRegisterVariable:
2922 * @ctxt: the XPath context
2923 * @name: the variable name
2924 * @value: the variable value or NULL
2925 *
2926 * Register a new variable value. If @value is NULL it unregisters
2927 * the variable
2928 *
2929 * Returns 0 in case of success, -1 in case of error
2930 */
2931int
2932xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2933 xmlXPathObjectPtr value) {
2934 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2935}
2936
2937/**
2938 * xmlXPathRegisterVariableNS:
2939 * @ctxt: the XPath context
2940 * @name: the variable name
2941 * @ns_uri: the variable namespace URI
2942 * @value: the variable value or NULL
2943 *
2944 * Register a new variable value. If @value is NULL it unregisters
2945 * the variable
2946 *
2947 * Returns 0 in case of success, -1 in case of error
2948 */
2949int
2950xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2951 const xmlChar *ns_uri,
2952 xmlXPathObjectPtr value) {
2953 if (ctxt == NULL)
2954 return(-1);
2955 if (name == NULL)
2956 return(-1);
2957
2958 if (ctxt->varHash == NULL)
2959 ctxt->varHash = xmlHashCreate(0);
2960 if (ctxt->varHash == NULL)
2961 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002962 if (value == NULL)
2963 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2964 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002965 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2966 (void *) value,
2967 (xmlHashDeallocator)xmlXPathFreeObject));
2968}
2969
2970/**
2971 * xmlXPathRegisterVariableLookup:
2972 * @ctxt: the XPath context
2973 * @f: the lookup function
2974 * @data: the lookup data
2975 *
2976 * register an external mechanism to do variable lookup
2977 */
2978void
2979xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2980 xmlXPathVariableLookupFunc f, void *data) {
2981 if (ctxt == NULL)
2982 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002983 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00002984 ctxt->varLookupData = data;
2985}
2986
2987/**
2988 * xmlXPathVariableLookup:
2989 * @ctxt: the XPath context
2990 * @name: the variable name
2991 *
2992 * Search in the Variable array of the context for the given
2993 * variable value.
2994 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002995 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002996 */
2997xmlXPathObjectPtr
2998xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2999 if (ctxt == NULL)
3000 return(NULL);
3001
3002 if (ctxt->varLookupFunc != NULL) {
3003 xmlXPathObjectPtr ret;
3004
3005 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3006 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003007 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003008 }
3009 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3010}
3011
3012/**
3013 * xmlXPathVariableLookupNS:
3014 * @ctxt: the XPath context
3015 * @name: the variable name
3016 * @ns_uri: the variable namespace URI
3017 *
3018 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003019 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003020 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003021 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003022 */
3023xmlXPathObjectPtr
3024xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3025 const xmlChar *ns_uri) {
3026 if (ctxt == NULL)
3027 return(NULL);
3028
3029 if (ctxt->varLookupFunc != NULL) {
3030 xmlXPathObjectPtr ret;
3031
3032 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3033 (ctxt->varLookupData, name, ns_uri);
3034 if (ret != NULL) return(ret);
3035 }
3036
3037 if (ctxt->varHash == NULL)
3038 return(NULL);
3039 if (name == NULL)
3040 return(NULL);
3041
Daniel Veillard8c357d52001-07-03 23:43:33 +00003042 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3043 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003044}
3045
3046/**
3047 * xmlXPathRegisteredVariablesCleanup:
3048 * @ctxt: the XPath context
3049 *
3050 * Cleanup the XPath context data associated to registered variables
3051 */
3052void
3053xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3054 if (ctxt == NULL)
3055 return;
3056
Daniel Veillard76d66f42001-05-16 21:05:17 +00003057 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003058 ctxt->varHash = NULL;
3059}
3060
3061/**
3062 * xmlXPathRegisterNs:
3063 * @ctxt: the XPath context
3064 * @prefix: the namespace prefix
3065 * @ns_uri: the namespace name
3066 *
3067 * Register a new namespace. If @ns_uri is NULL it unregisters
3068 * the namespace
3069 *
3070 * Returns 0 in case of success, -1 in case of error
3071 */
3072int
3073xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3074 const xmlChar *ns_uri) {
3075 if (ctxt == NULL)
3076 return(-1);
3077 if (prefix == NULL)
3078 return(-1);
3079
3080 if (ctxt->nsHash == NULL)
3081 ctxt->nsHash = xmlHashCreate(10);
3082 if (ctxt->nsHash == NULL)
3083 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003084 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003085 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003086 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003087 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003088 (xmlHashDeallocator)xmlFree));
3089}
3090
3091/**
3092 * xmlXPathNsLookup:
3093 * @ctxt: the XPath context
3094 * @prefix: the namespace prefix value
3095 *
3096 * Search in the namespace declaration array of the context for the given
3097 * namespace name associated to the given prefix
3098 *
3099 * Returns the value or NULL if not found
3100 */
3101const xmlChar *
3102xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3103 if (ctxt == NULL)
3104 return(NULL);
3105 if (prefix == NULL)
3106 return(NULL);
3107
3108#ifdef XML_XML_NAMESPACE
3109 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3110 return(XML_XML_NAMESPACE);
3111#endif
3112
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003113 if (ctxt->namespaces != NULL) {
3114 int i;
3115
3116 for (i = 0;i < ctxt->nsNr;i++) {
3117 if ((ctxt->namespaces[i] != NULL) &&
3118 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3119 return(ctxt->namespaces[i]->href);
3120 }
3121 }
Owen Taylor3473f882001-02-23 17:55:21 +00003122
3123 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3124}
3125
3126/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003127 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003128 * @ctxt: the XPath context
3129 *
3130 * Cleanup the XPath context data associated to registered variables
3131 */
3132void
3133xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3134 if (ctxt == NULL)
3135 return;
3136
Daniel Veillard42766c02002-08-22 20:52:17 +00003137 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003138 ctxt->nsHash = NULL;
3139}
3140
3141/************************************************************************
3142 * *
3143 * Routines to handle Values *
3144 * *
3145 ************************************************************************/
3146
William M. Brack08171912003-12-29 02:52:11 +00003147/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003148
3149/**
3150 * xmlXPathNewFloat:
3151 * @val: the double value
3152 *
3153 * Create a new xmlXPathObjectPtr of type double and of value @val
3154 *
3155 * Returns the newly created object.
3156 */
3157xmlXPathObjectPtr
3158xmlXPathNewFloat(double val) {
3159 xmlXPathObjectPtr ret;
3160
3161 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3162 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003163 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003164 return(NULL);
3165 }
3166 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3167 ret->type = XPATH_NUMBER;
3168 ret->floatval = val;
3169 return(ret);
3170}
3171
3172/**
3173 * xmlXPathNewBoolean:
3174 * @val: the boolean value
3175 *
3176 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3177 *
3178 * Returns the newly created object.
3179 */
3180xmlXPathObjectPtr
3181xmlXPathNewBoolean(int val) {
3182 xmlXPathObjectPtr ret;
3183
3184 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3185 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003186 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003187 return(NULL);
3188 }
3189 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3190 ret->type = XPATH_BOOLEAN;
3191 ret->boolval = (val != 0);
3192 return(ret);
3193}
3194
3195/**
3196 * xmlXPathNewString:
3197 * @val: the xmlChar * value
3198 *
3199 * Create a new xmlXPathObjectPtr of type string and of value @val
3200 *
3201 * Returns the newly created object.
3202 */
3203xmlXPathObjectPtr
3204xmlXPathNewString(const xmlChar *val) {
3205 xmlXPathObjectPtr ret;
3206
3207 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3208 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003209 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003210 return(NULL);
3211 }
3212 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3213 ret->type = XPATH_STRING;
3214 if (val != NULL)
3215 ret->stringval = xmlStrdup(val);
3216 else
3217 ret->stringval = xmlStrdup((const xmlChar *)"");
3218 return(ret);
3219}
3220
3221/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003222 * xmlXPathWrapString:
3223 * @val: the xmlChar * value
3224 *
3225 * Wraps the @val string into an XPath object.
3226 *
3227 * Returns the newly created object.
3228 */
3229xmlXPathObjectPtr
3230xmlXPathWrapString (xmlChar *val) {
3231 xmlXPathObjectPtr ret;
3232
3233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3234 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003235 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003236 return(NULL);
3237 }
3238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3239 ret->type = XPATH_STRING;
3240 ret->stringval = val;
3241 return(ret);
3242}
3243
3244/**
Owen Taylor3473f882001-02-23 17:55:21 +00003245 * xmlXPathNewCString:
3246 * @val: the char * value
3247 *
3248 * Create a new xmlXPathObjectPtr of type string and of value @val
3249 *
3250 * Returns the newly created object.
3251 */
3252xmlXPathObjectPtr
3253xmlXPathNewCString(const char *val) {
3254 xmlXPathObjectPtr ret;
3255
3256 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3257 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003258 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003259 return(NULL);
3260 }
3261 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3262 ret->type = XPATH_STRING;
3263 ret->stringval = xmlStrdup(BAD_CAST val);
3264 return(ret);
3265}
3266
3267/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003268 * xmlXPathWrapCString:
3269 * @val: the char * value
3270 *
3271 * Wraps a string into an XPath object.
3272 *
3273 * Returns the newly created object.
3274 */
3275xmlXPathObjectPtr
3276xmlXPathWrapCString (char * val) {
3277 return(xmlXPathWrapString((xmlChar *)(val)));
3278}
3279
3280/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003281 * xmlXPathWrapExternal:
3282 * @val: the user data
3283 *
3284 * Wraps the @val data into an XPath object.
3285 *
3286 * Returns the newly created object.
3287 */
3288xmlXPathObjectPtr
3289xmlXPathWrapExternal (void *val) {
3290 xmlXPathObjectPtr ret;
3291
3292 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3293 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003294 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003295 return(NULL);
3296 }
3297 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3298 ret->type = XPATH_USERS;
3299 ret->user = val;
3300 return(ret);
3301}
3302
3303/**
Owen Taylor3473f882001-02-23 17:55:21 +00003304 * xmlXPathObjectCopy:
3305 * @val: the original object
3306 *
3307 * allocate a new copy of a given object
3308 *
3309 * Returns the newly created object.
3310 */
3311xmlXPathObjectPtr
3312xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3313 xmlXPathObjectPtr ret;
3314
3315 if (val == NULL)
3316 return(NULL);
3317
3318 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3319 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003320 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003321 return(NULL);
3322 }
3323 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3324 switch (val->type) {
3325 case XPATH_BOOLEAN:
3326 case XPATH_NUMBER:
3327 case XPATH_POINT:
3328 case XPATH_RANGE:
3329 break;
3330 case XPATH_STRING:
3331 ret->stringval = xmlStrdup(val->stringval);
3332 break;
3333 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003334#if 0
3335/*
3336 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3337 this previous handling is no longer correct, and can cause some serious
3338 problems (ref. bug 145547)
3339*/
Owen Taylor3473f882001-02-23 17:55:21 +00003340 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003341 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003342 xmlNodePtr cur, tmp;
3343 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003344
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003345 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003346 top = xmlNewDoc(NULL);
3347 top->name = (char *)
3348 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003349 ret->user = top;
3350 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003351 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003352 cur = val->nodesetval->nodeTab[0]->children;
3353 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003354 tmp = xmlDocCopyNode(cur, top, 1);
3355 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003356 cur = cur->next;
3357 }
3358 }
William M. Bracke9449c52004-07-11 14:41:20 +00003359
Daniel Veillard9adc0462003-03-24 18:39:54 +00003360 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003361 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003362 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003363 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003364 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003365#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003366 case XPATH_NODESET:
3367 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003368 /* Do not deallocate the copied tree value */
3369 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003370 break;
3371 case XPATH_LOCATIONSET:
3372#ifdef LIBXML_XPTR_ENABLED
3373 {
3374 xmlLocationSetPtr loc = val->user;
3375 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3376 break;
3377 }
3378#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003379 case XPATH_USERS:
3380 ret->user = val->user;
3381 break;
3382 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003383 xmlGenericError(xmlGenericErrorContext,
3384 "xmlXPathObjectCopy: unsupported type %d\n",
3385 val->type);
3386 break;
3387 }
3388 return(ret);
3389}
3390
3391/**
3392 * xmlXPathFreeObject:
3393 * @obj: the object to free
3394 *
3395 * Free up an xmlXPathObjectPtr object.
3396 */
3397void
3398xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3399 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003400 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003401 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003402#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003403 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003404 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003405 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003406 } else
3407#endif
3408 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003409 xmlXPathFreeValueTree(obj->nodesetval);
3410 } else {
3411 if (obj->nodesetval != NULL)
3412 xmlXPathFreeNodeSet(obj->nodesetval);
3413 }
Owen Taylor3473f882001-02-23 17:55:21 +00003414#ifdef LIBXML_XPTR_ENABLED
3415 } else if (obj->type == XPATH_LOCATIONSET) {
3416 if (obj->user != NULL)
3417 xmlXPtrFreeLocationSet(obj->user);
3418#endif
3419 } else if (obj->type == XPATH_STRING) {
3420 if (obj->stringval != NULL)
3421 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003422 }
3423
Owen Taylor3473f882001-02-23 17:55:21 +00003424 xmlFree(obj);
3425}
3426
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003427
3428/************************************************************************
3429 * *
3430 * Type Casting Routines *
3431 * *
3432 ************************************************************************/
3433
3434/**
3435 * xmlXPathCastBooleanToString:
3436 * @val: a boolean
3437 *
3438 * Converts a boolean to its string value.
3439 *
3440 * Returns a newly allocated string.
3441 */
3442xmlChar *
3443xmlXPathCastBooleanToString (int val) {
3444 xmlChar *ret;
3445 if (val)
3446 ret = xmlStrdup((const xmlChar *) "true");
3447 else
3448 ret = xmlStrdup((const xmlChar *) "false");
3449 return(ret);
3450}
3451
3452/**
3453 * xmlXPathCastNumberToString:
3454 * @val: a number
3455 *
3456 * Converts a number to its string value.
3457 *
3458 * Returns a newly allocated string.
3459 */
3460xmlChar *
3461xmlXPathCastNumberToString (double val) {
3462 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003463 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003464 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003465 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003466 break;
3467 case -1:
3468 ret = xmlStrdup((const xmlChar *) "-Infinity");
3469 break;
3470 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003471 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003472 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003473 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3474 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003475 } else {
3476 /* could be improved */
3477 char buf[100];
3478 xmlXPathFormatNumber(val, buf, 100);
3479 ret = xmlStrdup((const xmlChar *) buf);
3480 }
3481 }
3482 return(ret);
3483}
3484
3485/**
3486 * xmlXPathCastNodeToString:
3487 * @node: a node
3488 *
3489 * Converts a node to its string value.
3490 *
3491 * Returns a newly allocated string.
3492 */
3493xmlChar *
3494xmlXPathCastNodeToString (xmlNodePtr node) {
3495 return(xmlNodeGetContent(node));
3496}
3497
3498/**
3499 * xmlXPathCastNodeSetToString:
3500 * @ns: a node-set
3501 *
3502 * Converts a node-set to its string value.
3503 *
3504 * Returns a newly allocated string.
3505 */
3506xmlChar *
3507xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3508 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3509 return(xmlStrdup((const xmlChar *) ""));
3510
3511 xmlXPathNodeSetSort(ns);
3512 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3513}
3514
3515/**
3516 * xmlXPathCastToString:
3517 * @val: an XPath object
3518 *
3519 * Converts an existing object to its string() equivalent
3520 *
3521 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003522 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003523 * string object).
3524 */
3525xmlChar *
3526xmlXPathCastToString(xmlXPathObjectPtr val) {
3527 xmlChar *ret = NULL;
3528
3529 if (val == NULL)
3530 return(xmlStrdup((const xmlChar *) ""));
3531 switch (val->type) {
3532 case XPATH_UNDEFINED:
3533#ifdef DEBUG_EXPR
3534 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3535#endif
3536 ret = xmlStrdup((const xmlChar *) "");
3537 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003538 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003539 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003540 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3541 break;
3542 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003543 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003544 case XPATH_BOOLEAN:
3545 ret = xmlXPathCastBooleanToString(val->boolval);
3546 break;
3547 case XPATH_NUMBER: {
3548 ret = xmlXPathCastNumberToString(val->floatval);
3549 break;
3550 }
3551 case XPATH_USERS:
3552 case XPATH_POINT:
3553 case XPATH_RANGE:
3554 case XPATH_LOCATIONSET:
3555 TODO
3556 ret = xmlStrdup((const xmlChar *) "");
3557 break;
3558 }
3559 return(ret);
3560}
3561
3562/**
3563 * xmlXPathConvertString:
3564 * @val: an XPath object
3565 *
3566 * Converts an existing object to its string() equivalent
3567 *
3568 * Returns the new object, the old one is freed (or the operation
3569 * is done directly on @val)
3570 */
3571xmlXPathObjectPtr
3572xmlXPathConvertString(xmlXPathObjectPtr val) {
3573 xmlChar *res = NULL;
3574
3575 if (val == NULL)
3576 return(xmlXPathNewCString(""));
3577
3578 switch (val->type) {
3579 case XPATH_UNDEFINED:
3580#ifdef DEBUG_EXPR
3581 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3582#endif
3583 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003584 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003585 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003586 res = xmlXPathCastNodeSetToString(val->nodesetval);
3587 break;
3588 case XPATH_STRING:
3589 return(val);
3590 case XPATH_BOOLEAN:
3591 res = xmlXPathCastBooleanToString(val->boolval);
3592 break;
3593 case XPATH_NUMBER:
3594 res = xmlXPathCastNumberToString(val->floatval);
3595 break;
3596 case XPATH_USERS:
3597 case XPATH_POINT:
3598 case XPATH_RANGE:
3599 case XPATH_LOCATIONSET:
3600 TODO;
3601 break;
3602 }
3603 xmlXPathFreeObject(val);
3604 if (res == NULL)
3605 return(xmlXPathNewCString(""));
3606 return(xmlXPathWrapString(res));
3607}
3608
3609/**
3610 * xmlXPathCastBooleanToNumber:
3611 * @val: a boolean
3612 *
3613 * Converts a boolean to its number value
3614 *
3615 * Returns the number value
3616 */
3617double
3618xmlXPathCastBooleanToNumber(int val) {
3619 if (val)
3620 return(1.0);
3621 return(0.0);
3622}
3623
3624/**
3625 * xmlXPathCastStringToNumber:
3626 * @val: a string
3627 *
3628 * Converts a string to its number value
3629 *
3630 * Returns the number value
3631 */
3632double
3633xmlXPathCastStringToNumber(const xmlChar * val) {
3634 return(xmlXPathStringEvalNumber(val));
3635}
3636
3637/**
3638 * xmlXPathCastNodeToNumber:
3639 * @node: a node
3640 *
3641 * Converts a node to its number value
3642 *
3643 * Returns the number value
3644 */
3645double
3646xmlXPathCastNodeToNumber (xmlNodePtr node) {
3647 xmlChar *strval;
3648 double ret;
3649
3650 if (node == NULL)
3651 return(xmlXPathNAN);
3652 strval = xmlXPathCastNodeToString(node);
3653 if (strval == NULL)
3654 return(xmlXPathNAN);
3655 ret = xmlXPathCastStringToNumber(strval);
3656 xmlFree(strval);
3657
3658 return(ret);
3659}
3660
3661/**
3662 * xmlXPathCastNodeSetToNumber:
3663 * @ns: a node-set
3664 *
3665 * Converts a node-set to its number value
3666 *
3667 * Returns the number value
3668 */
3669double
3670xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3671 xmlChar *str;
3672 double ret;
3673
3674 if (ns == NULL)
3675 return(xmlXPathNAN);
3676 str = xmlXPathCastNodeSetToString(ns);
3677 ret = xmlXPathCastStringToNumber(str);
3678 xmlFree(str);
3679 return(ret);
3680}
3681
3682/**
3683 * xmlXPathCastToNumber:
3684 * @val: an XPath object
3685 *
3686 * Converts an XPath object to its number value
3687 *
3688 * Returns the number value
3689 */
3690double
3691xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3692 double ret = 0.0;
3693
3694 if (val == NULL)
3695 return(xmlXPathNAN);
3696 switch (val->type) {
3697 case XPATH_UNDEFINED:
3698#ifdef DEGUB_EXPR
3699 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3700#endif
3701 ret = xmlXPathNAN;
3702 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003703 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003704 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003705 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3706 break;
3707 case XPATH_STRING:
3708 ret = xmlXPathCastStringToNumber(val->stringval);
3709 break;
3710 case XPATH_NUMBER:
3711 ret = val->floatval;
3712 break;
3713 case XPATH_BOOLEAN:
3714 ret = xmlXPathCastBooleanToNumber(val->boolval);
3715 break;
3716 case XPATH_USERS:
3717 case XPATH_POINT:
3718 case XPATH_RANGE:
3719 case XPATH_LOCATIONSET:
3720 TODO;
3721 ret = xmlXPathNAN;
3722 break;
3723 }
3724 return(ret);
3725}
3726
3727/**
3728 * xmlXPathConvertNumber:
3729 * @val: an XPath object
3730 *
3731 * Converts an existing object to its number() equivalent
3732 *
3733 * Returns the new object, the old one is freed (or the operation
3734 * is done directly on @val)
3735 */
3736xmlXPathObjectPtr
3737xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3738 xmlXPathObjectPtr ret;
3739
3740 if (val == NULL)
3741 return(xmlXPathNewFloat(0.0));
3742 if (val->type == XPATH_NUMBER)
3743 return(val);
3744 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3745 xmlXPathFreeObject(val);
3746 return(ret);
3747}
3748
3749/**
3750 * xmlXPathCastNumberToBoolean:
3751 * @val: a number
3752 *
3753 * Converts a number to its boolean value
3754 *
3755 * Returns the boolean value
3756 */
3757int
3758xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003759 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003760 return(0);
3761 return(1);
3762}
3763
3764/**
3765 * xmlXPathCastStringToBoolean:
3766 * @val: a string
3767 *
3768 * Converts a string to its boolean value
3769 *
3770 * Returns the boolean value
3771 */
3772int
3773xmlXPathCastStringToBoolean (const xmlChar *val) {
3774 if ((val == NULL) || (xmlStrlen(val) == 0))
3775 return(0);
3776 return(1);
3777}
3778
3779/**
3780 * xmlXPathCastNodeSetToBoolean:
3781 * @ns: a node-set
3782 *
3783 * Converts a node-set to its boolean value
3784 *
3785 * Returns the boolean value
3786 */
3787int
3788xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3789 if ((ns == NULL) || (ns->nodeNr == 0))
3790 return(0);
3791 return(1);
3792}
3793
3794/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003795 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003796 * @val: an XPath object
3797 *
3798 * Converts an XPath object to its boolean value
3799 *
3800 * Returns the boolean value
3801 */
3802int
3803xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3804 int ret = 0;
3805
3806 if (val == NULL)
3807 return(0);
3808 switch (val->type) {
3809 case XPATH_UNDEFINED:
3810#ifdef DEBUG_EXPR
3811 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3812#endif
3813 ret = 0;
3814 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003815 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003816 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003817 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3818 break;
3819 case XPATH_STRING:
3820 ret = xmlXPathCastStringToBoolean(val->stringval);
3821 break;
3822 case XPATH_NUMBER:
3823 ret = xmlXPathCastNumberToBoolean(val->floatval);
3824 break;
3825 case XPATH_BOOLEAN:
3826 ret = val->boolval;
3827 break;
3828 case XPATH_USERS:
3829 case XPATH_POINT:
3830 case XPATH_RANGE:
3831 case XPATH_LOCATIONSET:
3832 TODO;
3833 ret = 0;
3834 break;
3835 }
3836 return(ret);
3837}
3838
3839
3840/**
3841 * xmlXPathConvertBoolean:
3842 * @val: an XPath object
3843 *
3844 * Converts an existing object to its boolean() equivalent
3845 *
3846 * Returns the new object, the old one is freed (or the operation
3847 * is done directly on @val)
3848 */
3849xmlXPathObjectPtr
3850xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3851 xmlXPathObjectPtr ret;
3852
3853 if (val == NULL)
3854 return(xmlXPathNewBoolean(0));
3855 if (val->type == XPATH_BOOLEAN)
3856 return(val);
3857 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3858 xmlXPathFreeObject(val);
3859 return(ret);
3860}
3861
Owen Taylor3473f882001-02-23 17:55:21 +00003862/************************************************************************
3863 * *
3864 * Routines to handle XPath contexts *
3865 * *
3866 ************************************************************************/
3867
3868/**
3869 * xmlXPathNewContext:
3870 * @doc: the XML document
3871 *
3872 * Create a new xmlXPathContext
3873 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003874 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003875 */
3876xmlXPathContextPtr
3877xmlXPathNewContext(xmlDocPtr doc) {
3878 xmlXPathContextPtr ret;
3879
3880 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3881 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003882 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003883 return(NULL);
3884 }
3885 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3886 ret->doc = doc;
3887 ret->node = NULL;
3888
3889 ret->varHash = NULL;
3890
3891 ret->nb_types = 0;
3892 ret->max_types = 0;
3893 ret->types = NULL;
3894
3895 ret->funcHash = xmlHashCreate(0);
3896
3897 ret->nb_axis = 0;
3898 ret->max_axis = 0;
3899 ret->axis = NULL;
3900
3901 ret->nsHash = NULL;
3902 ret->user = NULL;
3903
3904 ret->contextSize = -1;
3905 ret->proximityPosition = -1;
3906
3907 xmlXPathRegisterAllFunctions(ret);
3908
3909 return(ret);
3910}
3911
3912/**
3913 * xmlXPathFreeContext:
3914 * @ctxt: the context to free
3915 *
3916 * Free up an xmlXPathContext
3917 */
3918void
3919xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3920 xmlXPathRegisteredNsCleanup(ctxt);
3921 xmlXPathRegisteredFuncsCleanup(ctxt);
3922 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003923 xmlFree(ctxt);
3924}
3925
3926/************************************************************************
3927 * *
3928 * Routines to handle XPath parser contexts *
3929 * *
3930 ************************************************************************/
3931
3932#define CHECK_CTXT(ctxt) \
3933 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00003934 __xmlRaiseError(NULL, NULL, NULL, \
3935 NULL, NULL, XML_FROM_XPATH, \
3936 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
3937 __FILE__, __LINE__, \
3938 NULL, NULL, NULL, 0, 0, \
3939 "NULL context pointer\n"); \
3940 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00003941 } \
3942
3943
3944#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00003945 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
3946 (ctxt->doc->children == NULL)) { \
3947 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003948 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00003949 }
Owen Taylor3473f882001-02-23 17:55:21 +00003950
3951
3952/**
3953 * xmlXPathNewParserContext:
3954 * @str: the XPath expression
3955 * @ctxt: the XPath context
3956 *
3957 * Create a new xmlXPathParserContext
3958 *
3959 * Returns the xmlXPathParserContext just allocated.
3960 */
3961xmlXPathParserContextPtr
3962xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3963 xmlXPathParserContextPtr ret;
3964
3965 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3966 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003967 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003968 return(NULL);
3969 }
3970 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3971 ret->cur = ret->base = str;
3972 ret->context = ctxt;
3973
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003974 ret->comp = xmlXPathNewCompExpr();
3975 if (ret->comp == NULL) {
3976 xmlFree(ret->valueTab);
3977 xmlFree(ret);
3978 return(NULL);
3979 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003980 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3981 ret->comp->dict = ctxt->dict;
3982 xmlDictReference(ret->comp->dict);
3983 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003984
3985 return(ret);
3986}
3987
3988/**
3989 * xmlXPathCompParserContext:
3990 * @comp: the XPath compiled expression
3991 * @ctxt: the XPath context
3992 *
3993 * Create a new xmlXPathParserContext when processing a compiled expression
3994 *
3995 * Returns the xmlXPathParserContext just allocated.
3996 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003997static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003998xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3999 xmlXPathParserContextPtr ret;
4000
4001 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4002 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004003 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004004 return(NULL);
4005 }
4006 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4007
Owen Taylor3473f882001-02-23 17:55:21 +00004008 /* Allocate the value stack */
4009 ret->valueTab = (xmlXPathObjectPtr *)
4010 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004011 if (ret->valueTab == NULL) {
4012 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004013 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004014 return(NULL);
4015 }
Owen Taylor3473f882001-02-23 17:55:21 +00004016 ret->valueNr = 0;
4017 ret->valueMax = 10;
4018 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004019
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004020 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004021 ret->comp = comp;
4022
Owen Taylor3473f882001-02-23 17:55:21 +00004023 return(ret);
4024}
4025
4026/**
4027 * xmlXPathFreeParserContext:
4028 * @ctxt: the context to free
4029 *
4030 * Free up an xmlXPathParserContext
4031 */
4032void
4033xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4034 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004035 xmlFree(ctxt->valueTab);
4036 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004037 if (ctxt->comp)
4038 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00004039 xmlFree(ctxt);
4040}
4041
4042/************************************************************************
4043 * *
4044 * The implicit core function library *
4045 * *
4046 ************************************************************************/
4047
Owen Taylor3473f882001-02-23 17:55:21 +00004048/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004049 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004050 * @node: a node pointer
4051 *
4052 * Function computing the beginning of the string value of the node,
4053 * used to speed up comparisons
4054 *
4055 * Returns an int usable as a hash
4056 */
4057static unsigned int
4058xmlXPathNodeValHash(xmlNodePtr node) {
4059 int len = 2;
4060 const xmlChar * string = NULL;
4061 xmlNodePtr tmp = NULL;
4062 unsigned int ret = 0;
4063
4064 if (node == NULL)
4065 return(0);
4066
Daniel Veillard9adc0462003-03-24 18:39:54 +00004067 if (node->type == XML_DOCUMENT_NODE) {
4068 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4069 if (tmp == NULL)
4070 node = node->children;
4071 else
4072 node = tmp;
4073
4074 if (node == NULL)
4075 return(0);
4076 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004077
4078 switch (node->type) {
4079 case XML_COMMENT_NODE:
4080 case XML_PI_NODE:
4081 case XML_CDATA_SECTION_NODE:
4082 case XML_TEXT_NODE:
4083 string = node->content;
4084 if (string == NULL)
4085 return(0);
4086 if (string[0] == 0)
4087 return(0);
4088 return(((unsigned int) string[0]) +
4089 (((unsigned int) string[1]) << 8));
4090 case XML_NAMESPACE_DECL:
4091 string = ((xmlNsPtr)node)->href;
4092 if (string == NULL)
4093 return(0);
4094 if (string[0] == 0)
4095 return(0);
4096 return(((unsigned int) string[0]) +
4097 (((unsigned int) string[1]) << 8));
4098 case XML_ATTRIBUTE_NODE:
4099 tmp = ((xmlAttrPtr) node)->children;
4100 break;
4101 case XML_ELEMENT_NODE:
4102 tmp = node->children;
4103 break;
4104 default:
4105 return(0);
4106 }
4107 while (tmp != NULL) {
4108 switch (tmp->type) {
4109 case XML_COMMENT_NODE:
4110 case XML_PI_NODE:
4111 case XML_CDATA_SECTION_NODE:
4112 case XML_TEXT_NODE:
4113 string = tmp->content;
4114 break;
4115 case XML_NAMESPACE_DECL:
4116 string = ((xmlNsPtr)tmp)->href;
4117 break;
4118 default:
4119 break;
4120 }
4121 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004122 if (len == 1) {
4123 return(ret + (((unsigned int) string[0]) << 8));
4124 }
4125 if (string[1] == 0) {
4126 len = 1;
4127 ret = (unsigned int) string[0];
4128 } else {
4129 return(((unsigned int) string[0]) +
4130 (((unsigned int) string[1]) << 8));
4131 }
4132 }
4133 /*
4134 * Skip to next node
4135 */
4136 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4137 if (tmp->children->type != XML_ENTITY_DECL) {
4138 tmp = tmp->children;
4139 continue;
4140 }
4141 }
4142 if (tmp == node)
4143 break;
4144
4145 if (tmp->next != NULL) {
4146 tmp = tmp->next;
4147 continue;
4148 }
4149
4150 do {
4151 tmp = tmp->parent;
4152 if (tmp == NULL)
4153 break;
4154 if (tmp == node) {
4155 tmp = NULL;
4156 break;
4157 }
4158 if (tmp->next != NULL) {
4159 tmp = tmp->next;
4160 break;
4161 }
4162 } while (tmp != NULL);
4163 }
4164 return(ret);
4165}
4166
4167/**
4168 * xmlXPathStringHash:
4169 * @string: a string
4170 *
4171 * Function computing the beginning of the string value of the node,
4172 * used to speed up comparisons
4173 *
4174 * Returns an int usable as a hash
4175 */
4176static unsigned int
4177xmlXPathStringHash(const xmlChar * string) {
4178 if (string == NULL)
4179 return((unsigned int) 0);
4180 if (string[0] == 0)
4181 return(0);
4182 return(((unsigned int) string[0]) +
4183 (((unsigned int) string[1]) << 8));
4184}
4185
4186/**
Owen Taylor3473f882001-02-23 17:55:21 +00004187 * xmlXPathCompareNodeSetFloat:
4188 * @ctxt: the XPath Parser context
4189 * @inf: less than (1) or greater than (0)
4190 * @strict: is the comparison strict
4191 * @arg: the node set
4192 * @f: the value
4193 *
4194 * Implement the compare operation between a nodeset and a number
4195 * @ns < @val (1, 1, ...
4196 * @ns <= @val (1, 0, ...
4197 * @ns > @val (0, 1, ...
4198 * @ns >= @val (0, 0, ...
4199 *
4200 * If one object to be compared is a node-set and the other is a number,
4201 * then the comparison will be true if and only if there is a node in the
4202 * node-set such that the result of performing the comparison on the number
4203 * to be compared and on the result of converting the string-value of that
4204 * node to a number using the number function is true.
4205 *
4206 * Returns 0 or 1 depending on the results of the test.
4207 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004208static int
Owen Taylor3473f882001-02-23 17:55:21 +00004209xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4210 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4211 int i, ret = 0;
4212 xmlNodeSetPtr ns;
4213 xmlChar *str2;
4214
4215 if ((f == NULL) || (arg == NULL) ||
4216 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4217 xmlXPathFreeObject(arg);
4218 xmlXPathFreeObject(f);
4219 return(0);
4220 }
4221 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004222 if (ns != NULL) {
4223 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004224 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004225 if (str2 != NULL) {
4226 valuePush(ctxt,
4227 xmlXPathNewString(str2));
4228 xmlFree(str2);
4229 xmlXPathNumberFunction(ctxt, 1);
4230 valuePush(ctxt, xmlXPathObjectCopy(f));
4231 ret = xmlXPathCompareValues(ctxt, inf, strict);
4232 if (ret)
4233 break;
4234 }
4235 }
Owen Taylor3473f882001-02-23 17:55:21 +00004236 }
4237 xmlXPathFreeObject(arg);
4238 xmlXPathFreeObject(f);
4239 return(ret);
4240}
4241
4242/**
4243 * xmlXPathCompareNodeSetString:
4244 * @ctxt: the XPath Parser context
4245 * @inf: less than (1) or greater than (0)
4246 * @strict: is the comparison strict
4247 * @arg: the node set
4248 * @s: the value
4249 *
4250 * Implement the compare operation between a nodeset and a string
4251 * @ns < @val (1, 1, ...
4252 * @ns <= @val (1, 0, ...
4253 * @ns > @val (0, 1, ...
4254 * @ns >= @val (0, 0, ...
4255 *
4256 * If one object to be compared is a node-set and the other is a string,
4257 * then the comparison will be true if and only if there is a node in
4258 * the node-set such that the result of performing the comparison on the
4259 * string-value of the node and the other string is true.
4260 *
4261 * Returns 0 or 1 depending on the results of the test.
4262 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004263static int
Owen Taylor3473f882001-02-23 17:55:21 +00004264xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4265 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4266 int i, ret = 0;
4267 xmlNodeSetPtr ns;
4268 xmlChar *str2;
4269
4270 if ((s == NULL) || (arg == NULL) ||
4271 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4272 xmlXPathFreeObject(arg);
4273 xmlXPathFreeObject(s);
4274 return(0);
4275 }
4276 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004277 if (ns != NULL) {
4278 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004279 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004280 if (str2 != NULL) {
4281 valuePush(ctxt,
4282 xmlXPathNewString(str2));
4283 xmlFree(str2);
4284 valuePush(ctxt, xmlXPathObjectCopy(s));
4285 ret = xmlXPathCompareValues(ctxt, inf, strict);
4286 if (ret)
4287 break;
4288 }
4289 }
Owen Taylor3473f882001-02-23 17:55:21 +00004290 }
4291 xmlXPathFreeObject(arg);
4292 xmlXPathFreeObject(s);
4293 return(ret);
4294}
4295
4296/**
4297 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004298 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004299 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004300 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004301 * @arg2: the second node set object
4302 *
4303 * Implement the compare operation on nodesets:
4304 *
4305 * If both objects to be compared are node-sets, then the comparison
4306 * will be true if and only if there is a node in the first node-set
4307 * and a node in the second node-set such that the result of performing
4308 * the comparison on the string-values of the two nodes is true.
4309 * ....
4310 * When neither object to be compared is a node-set and the operator
4311 * is <=, <, >= or >, then the objects are compared by converting both
4312 * objects to numbers and comparing the numbers according to IEEE 754.
4313 * ....
4314 * The number function converts its argument to a number as follows:
4315 * - a string that consists of optional whitespace followed by an
4316 * optional minus sign followed by a Number followed by whitespace
4317 * is converted to the IEEE 754 number that is nearest (according
4318 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4319 * represented by the string; any other string is converted to NaN
4320 *
4321 * Conclusion all nodes need to be converted first to their string value
4322 * and then the comparison must be done when possible
4323 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004324static int
4325xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004326 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4327 int i, j, init = 0;
4328 double val1;
4329 double *values2;
4330 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004331 xmlNodeSetPtr ns1;
4332 xmlNodeSetPtr ns2;
4333
4334 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004335 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4336 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004337 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004338 }
Owen Taylor3473f882001-02-23 17:55:21 +00004339 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004340 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4341 xmlXPathFreeObject(arg1);
4342 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004343 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004344 }
Owen Taylor3473f882001-02-23 17:55:21 +00004345
4346 ns1 = arg1->nodesetval;
4347 ns2 = arg2->nodesetval;
4348
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004349 if ((ns1 == NULL) || (ns1->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 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004354 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004355 xmlXPathFreeObject(arg1);
4356 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004357 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004358 }
Owen Taylor3473f882001-02-23 17:55:21 +00004359
4360 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4361 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004362 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004363 xmlXPathFreeObject(arg1);
4364 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004365 return(0);
4366 }
4367 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004368 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004369 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004370 continue;
4371 for (j = 0;j < ns2->nodeNr;j++) {
4372 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004373 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004374 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004375 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004376 continue;
4377 if (inf && strict)
4378 ret = (val1 < values2[j]);
4379 else if (inf && !strict)
4380 ret = (val1 <= values2[j]);
4381 else if (!inf && strict)
4382 ret = (val1 > values2[j]);
4383 else if (!inf && !strict)
4384 ret = (val1 >= values2[j]);
4385 if (ret)
4386 break;
4387 }
4388 if (ret)
4389 break;
4390 init = 1;
4391 }
4392 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004393 xmlXPathFreeObject(arg1);
4394 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004395 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004396}
4397
4398/**
4399 * xmlXPathCompareNodeSetValue:
4400 * @ctxt: the XPath Parser context
4401 * @inf: less than (1) or greater than (0)
4402 * @strict: is the comparison strict
4403 * @arg: the node set
4404 * @val: the value
4405 *
4406 * Implement the compare operation between a nodeset and a value
4407 * @ns < @val (1, 1, ...
4408 * @ns <= @val (1, 0, ...
4409 * @ns > @val (0, 1, ...
4410 * @ns >= @val (0, 0, ...
4411 *
4412 * If one object to be compared is a node-set and the other is a boolean,
4413 * then the comparison will be true if and only if the result of performing
4414 * the comparison on the boolean and on the result of converting
4415 * the node-set to a boolean using the boolean function is true.
4416 *
4417 * Returns 0 or 1 depending on the results of the test.
4418 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004419static int
Owen Taylor3473f882001-02-23 17:55:21 +00004420xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4421 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4422 if ((val == NULL) || (arg == NULL) ||
4423 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4424 return(0);
4425
4426 switch(val->type) {
4427 case XPATH_NUMBER:
4428 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4429 case XPATH_NODESET:
4430 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004431 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004432 case XPATH_STRING:
4433 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4434 case XPATH_BOOLEAN:
4435 valuePush(ctxt, arg);
4436 xmlXPathBooleanFunction(ctxt, 1);
4437 valuePush(ctxt, val);
4438 return(xmlXPathCompareValues(ctxt, inf, strict));
4439 default:
4440 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004441 }
4442 return(0);
4443}
4444
4445/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004446 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004447 * @arg: the nodeset object argument
4448 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004449 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004450 *
4451 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4452 * If one object to be compared is a node-set and the other is a string,
4453 * then the comparison will be true if and only if there is a node in
4454 * the node-set such that the result of performing the comparison on the
4455 * string-value of the node and the other string is true.
4456 *
4457 * Returns 0 or 1 depending on the results of the test.
4458 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004459static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004460xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004461{
Owen Taylor3473f882001-02-23 17:55:21 +00004462 int i;
4463 xmlNodeSetPtr ns;
4464 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004465 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004466
4467 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004468 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4469 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004470 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004471 /*
4472 * A NULL nodeset compared with a string is always false
4473 * (since there is no node equal, and no node not equal)
4474 */
4475 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004476 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004477 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004478 for (i = 0; i < ns->nodeNr; i++) {
4479 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4480 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4481 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4482 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004483 if (neq)
4484 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004485 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004486 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4487 if (neq)
4488 continue;
4489 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004490 } else if (neq) {
4491 if (str2 != NULL)
4492 xmlFree(str2);
4493 return (1);
4494 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004495 if (str2 != NULL)
4496 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004497 } else if (neq)
4498 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004499 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004500 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004501}
4502
4503/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004504 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004505 * @arg: the nodeset object argument
4506 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004507 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004508 *
4509 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4510 * If one object to be compared is a node-set and the other is a number,
4511 * then the comparison will be true if and only if there is a node in
4512 * the node-set such that the result of performing the comparison on the
4513 * number to be compared and on the result of converting the string-value
4514 * of that node to a number using the number function is true.
4515 *
4516 * Returns 0 or 1 depending on the results of the test.
4517 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004518static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004519xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4520 xmlXPathObjectPtr arg, double f, int neq) {
4521 int i, ret=0;
4522 xmlNodeSetPtr ns;
4523 xmlChar *str2;
4524 xmlXPathObjectPtr val;
4525 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004526
4527 if ((arg == NULL) ||
4528 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4529 return(0);
4530
William M. Brack0c022ad2002-07-12 00:56:01 +00004531 ns = arg->nodesetval;
4532 if (ns != NULL) {
4533 for (i=0;i<ns->nodeNr;i++) {
4534 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4535 if (str2 != NULL) {
4536 valuePush(ctxt, xmlXPathNewString(str2));
4537 xmlFree(str2);
4538 xmlXPathNumberFunction(ctxt, 1);
4539 val = valuePop(ctxt);
4540 v = val->floatval;
4541 xmlXPathFreeObject(val);
4542 if (!xmlXPathIsNaN(v)) {
4543 if ((!neq) && (v==f)) {
4544 ret = 1;
4545 break;
4546 } else if ((neq) && (v!=f)) {
4547 ret = 1;
4548 break;
4549 }
4550 }
4551 }
4552 }
4553 }
4554
4555 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004556}
4557
4558
4559/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004560 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004561 * @arg1: first nodeset object argument
4562 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004563 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004564 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004565 * Implement the equal / not equal operation on XPath nodesets:
4566 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004567 * If both objects to be compared are node-sets, then the comparison
4568 * will be true if and only if there is a node in the first node-set and
4569 * a node in the second node-set such that the result of performing the
4570 * comparison on the string-values of the two nodes is true.
4571 *
4572 * (needless to say, this is a costly operation)
4573 *
4574 * Returns 0 or 1 depending on the results of the test.
4575 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004576static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004577xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004578 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004579 unsigned int *hashs1;
4580 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004581 xmlChar **values1;
4582 xmlChar **values2;
4583 int ret = 0;
4584 xmlNodeSetPtr ns1;
4585 xmlNodeSetPtr ns2;
4586
4587 if ((arg1 == NULL) ||
4588 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4589 return(0);
4590 if ((arg2 == NULL) ||
4591 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4592 return(0);
4593
4594 ns1 = arg1->nodesetval;
4595 ns2 = arg2->nodesetval;
4596
Daniel Veillard911f49a2001-04-07 15:39:35 +00004597 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004598 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004599 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004600 return(0);
4601
4602 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004603 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004604 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004605 if (neq == 0)
4606 for (i = 0;i < ns1->nodeNr;i++)
4607 for (j = 0;j < ns2->nodeNr;j++)
4608 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4609 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004610
4611 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004612 if (values1 == NULL) {
4613 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004614 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004615 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004616 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4617 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004618 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004619 xmlFree(values1);
4620 return(0);
4621 }
Owen Taylor3473f882001-02-23 17:55:21 +00004622 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4623 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4624 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004625 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004626 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004627 xmlFree(values1);
4628 return(0);
4629 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004630 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4631 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004632 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004633 xmlFree(hashs1);
4634 xmlFree(values1);
4635 xmlFree(values2);
4636 return(0);
4637 }
Owen Taylor3473f882001-02-23 17:55:21 +00004638 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4639 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004640 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004641 for (j = 0;j < ns2->nodeNr;j++) {
4642 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004643 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004644 if (hashs1[i] != hashs2[j]) {
4645 if (neq) {
4646 ret = 1;
4647 break;
4648 }
4649 }
4650 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004651 if (values1[i] == NULL)
4652 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4653 if (values2[j] == NULL)
4654 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004655 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004656 if (ret)
4657 break;
4658 }
Owen Taylor3473f882001-02-23 17:55:21 +00004659 }
4660 if (ret)
4661 break;
4662 }
4663 for (i = 0;i < ns1->nodeNr;i++)
4664 if (values1[i] != NULL)
4665 xmlFree(values1[i]);
4666 for (j = 0;j < ns2->nodeNr;j++)
4667 if (values2[j] != NULL)
4668 xmlFree(values2[j]);
4669 xmlFree(values1);
4670 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004671 xmlFree(hashs1);
4672 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004673 return(ret);
4674}
4675
William M. Brack0c022ad2002-07-12 00:56:01 +00004676static int
4677xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4678 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004679 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004680 /*
4681 *At this point we are assured neither arg1 nor arg2
4682 *is a nodeset, so we can just pick the appropriate routine.
4683 */
Owen Taylor3473f882001-02-23 17:55:21 +00004684 switch (arg1->type) {
4685 case XPATH_UNDEFINED:
4686#ifdef DEBUG_EXPR
4687 xmlGenericError(xmlGenericErrorContext,
4688 "Equal: undefined\n");
4689#endif
4690 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004691 case XPATH_BOOLEAN:
4692 switch (arg2->type) {
4693 case XPATH_UNDEFINED:
4694#ifdef DEBUG_EXPR
4695 xmlGenericError(xmlGenericErrorContext,
4696 "Equal: undefined\n");
4697#endif
4698 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004699 case XPATH_BOOLEAN:
4700#ifdef DEBUG_EXPR
4701 xmlGenericError(xmlGenericErrorContext,
4702 "Equal: %d boolean %d \n",
4703 arg1->boolval, arg2->boolval);
4704#endif
4705 ret = (arg1->boolval == arg2->boolval);
4706 break;
4707 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004708 ret = (arg1->boolval ==
4709 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004710 break;
4711 case XPATH_STRING:
4712 if ((arg2->stringval == NULL) ||
4713 (arg2->stringval[0] == 0)) ret = 0;
4714 else
4715 ret = 1;
4716 ret = (arg1->boolval == ret);
4717 break;
4718 case XPATH_USERS:
4719 case XPATH_POINT:
4720 case XPATH_RANGE:
4721 case XPATH_LOCATIONSET:
4722 TODO
4723 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004724 case XPATH_NODESET:
4725 case XPATH_XSLT_TREE:
4726 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004727 }
4728 break;
4729 case XPATH_NUMBER:
4730 switch (arg2->type) {
4731 case XPATH_UNDEFINED:
4732#ifdef DEBUG_EXPR
4733 xmlGenericError(xmlGenericErrorContext,
4734 "Equal: undefined\n");
4735#endif
4736 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004737 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004738 ret = (arg2->boolval==
4739 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004740 break;
4741 case XPATH_STRING:
4742 valuePush(ctxt, arg2);
4743 xmlXPathNumberFunction(ctxt, 1);
4744 arg2 = valuePop(ctxt);
4745 /* no break on purpose */
4746 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004747 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004748 if (xmlXPathIsNaN(arg1->floatval) ||
4749 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004750 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004751 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4752 if (xmlXPathIsInf(arg2->floatval) == 1)
4753 ret = 1;
4754 else
4755 ret = 0;
4756 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4757 if (xmlXPathIsInf(arg2->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;
4766 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4767 if (xmlXPathIsInf(arg1->floatval) == -1)
4768 ret = 1;
4769 else
4770 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004771 } else {
4772 ret = (arg1->floatval == arg2->floatval);
4773 }
Owen Taylor3473f882001-02-23 17:55:21 +00004774 break;
4775 case XPATH_USERS:
4776 case XPATH_POINT:
4777 case XPATH_RANGE:
4778 case XPATH_LOCATIONSET:
4779 TODO
4780 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004781 case XPATH_NODESET:
4782 case XPATH_XSLT_TREE:
4783 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004784 }
4785 break;
4786 case XPATH_STRING:
4787 switch (arg2->type) {
4788 case XPATH_UNDEFINED:
4789#ifdef DEBUG_EXPR
4790 xmlGenericError(xmlGenericErrorContext,
4791 "Equal: undefined\n");
4792#endif
4793 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004794 case XPATH_BOOLEAN:
4795 if ((arg1->stringval == NULL) ||
4796 (arg1->stringval[0] == 0)) ret = 0;
4797 else
4798 ret = 1;
4799 ret = (arg2->boolval == ret);
4800 break;
4801 case XPATH_STRING:
4802 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4803 break;
4804 case XPATH_NUMBER:
4805 valuePush(ctxt, arg1);
4806 xmlXPathNumberFunction(ctxt, 1);
4807 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004808 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004809 if (xmlXPathIsNaN(arg1->floatval) ||
4810 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004811 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004812 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4813 if (xmlXPathIsInf(arg2->floatval) == 1)
4814 ret = 1;
4815 else
4816 ret = 0;
4817 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4818 if (xmlXPathIsInf(arg2->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;
4827 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4828 if (xmlXPathIsInf(arg1->floatval) == -1)
4829 ret = 1;
4830 else
4831 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004832 } else {
4833 ret = (arg1->floatval == arg2->floatval);
4834 }
Owen Taylor3473f882001-02-23 17:55:21 +00004835 break;
4836 case XPATH_USERS:
4837 case XPATH_POINT:
4838 case XPATH_RANGE:
4839 case XPATH_LOCATIONSET:
4840 TODO
4841 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004842 case XPATH_NODESET:
4843 case XPATH_XSLT_TREE:
4844 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004845 }
4846 break;
4847 case XPATH_USERS:
4848 case XPATH_POINT:
4849 case XPATH_RANGE:
4850 case XPATH_LOCATIONSET:
4851 TODO
4852 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004853 case XPATH_NODESET:
4854 case XPATH_XSLT_TREE:
4855 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004856 }
4857 xmlXPathFreeObject(arg1);
4858 xmlXPathFreeObject(arg2);
4859 return(ret);
4860}
4861
William M. Brack0c022ad2002-07-12 00:56:01 +00004862/**
4863 * xmlXPathEqualValues:
4864 * @ctxt: the XPath Parser context
4865 *
4866 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4867 *
4868 * Returns 0 or 1 depending on the results of the test.
4869 */
4870int
4871xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4872 xmlXPathObjectPtr arg1, arg2, argtmp;
4873 int ret = 0;
4874
Daniel Veillard6128c012004-11-08 17:16:15 +00004875 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004876 arg2 = valuePop(ctxt);
4877 arg1 = valuePop(ctxt);
4878 if ((arg1 == NULL) || (arg2 == NULL)) {
4879 if (arg1 != NULL)
4880 xmlXPathFreeObject(arg1);
4881 else
4882 xmlXPathFreeObject(arg2);
4883 XP_ERROR0(XPATH_INVALID_OPERAND);
4884 }
4885
4886 if (arg1 == arg2) {
4887#ifdef DEBUG_EXPR
4888 xmlGenericError(xmlGenericErrorContext,
4889 "Equal: by pointer\n");
4890#endif
4891 return(1);
4892 }
4893
4894 /*
4895 *If either argument is a nodeset, it's a 'special case'
4896 */
4897 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4898 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4899 /*
4900 *Hack it to assure arg1 is the nodeset
4901 */
4902 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4903 argtmp = arg2;
4904 arg2 = arg1;
4905 arg1 = argtmp;
4906 }
4907 switch (arg2->type) {
4908 case XPATH_UNDEFINED:
4909#ifdef DEBUG_EXPR
4910 xmlGenericError(xmlGenericErrorContext,
4911 "Equal: undefined\n");
4912#endif
4913 break;
4914 case XPATH_NODESET:
4915 case XPATH_XSLT_TREE:
4916 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4917 break;
4918 case XPATH_BOOLEAN:
4919 if ((arg1->nodesetval == NULL) ||
4920 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4921 else
4922 ret = 1;
4923 ret = (ret == arg2->boolval);
4924 break;
4925 case XPATH_NUMBER:
4926 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4927 break;
4928 case XPATH_STRING:
4929 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4930 break;
4931 case XPATH_USERS:
4932 case XPATH_POINT:
4933 case XPATH_RANGE:
4934 case XPATH_LOCATIONSET:
4935 TODO
4936 break;
4937 }
4938 xmlXPathFreeObject(arg1);
4939 xmlXPathFreeObject(arg2);
4940 return(ret);
4941 }
4942
4943 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4944}
4945
4946/**
4947 * xmlXPathNotEqualValues:
4948 * @ctxt: the XPath Parser context
4949 *
4950 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4951 *
4952 * Returns 0 or 1 depending on the results of the test.
4953 */
4954int
4955xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4956 xmlXPathObjectPtr arg1, arg2, argtmp;
4957 int ret = 0;
4958
Daniel Veillard6128c012004-11-08 17:16:15 +00004959 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004960 arg2 = valuePop(ctxt);
4961 arg1 = valuePop(ctxt);
4962 if ((arg1 == NULL) || (arg2 == NULL)) {
4963 if (arg1 != NULL)
4964 xmlXPathFreeObject(arg1);
4965 else
4966 xmlXPathFreeObject(arg2);
4967 XP_ERROR0(XPATH_INVALID_OPERAND);
4968 }
4969
4970 if (arg1 == arg2) {
4971#ifdef DEBUG_EXPR
4972 xmlGenericError(xmlGenericErrorContext,
4973 "NotEqual: by pointer\n");
4974#endif
4975 return(0);
4976 }
4977
4978 /*
4979 *If either argument is a nodeset, it's a 'special case'
4980 */
4981 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4982 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4983 /*
4984 *Hack it to assure arg1 is the nodeset
4985 */
4986 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4987 argtmp = arg2;
4988 arg2 = arg1;
4989 arg1 = argtmp;
4990 }
4991 switch (arg2->type) {
4992 case XPATH_UNDEFINED:
4993#ifdef DEBUG_EXPR
4994 xmlGenericError(xmlGenericErrorContext,
4995 "NotEqual: undefined\n");
4996#endif
4997 break;
4998 case XPATH_NODESET:
4999 case XPATH_XSLT_TREE:
5000 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5001 break;
5002 case XPATH_BOOLEAN:
5003 if ((arg1->nodesetval == NULL) ||
5004 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5005 else
5006 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005007 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005008 break;
5009 case XPATH_NUMBER:
5010 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5011 break;
5012 case XPATH_STRING:
5013 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5014 break;
5015 case XPATH_USERS:
5016 case XPATH_POINT:
5017 case XPATH_RANGE:
5018 case XPATH_LOCATIONSET:
5019 TODO
5020 break;
5021 }
5022 xmlXPathFreeObject(arg1);
5023 xmlXPathFreeObject(arg2);
5024 return(ret);
5025 }
5026
5027 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5028}
Owen Taylor3473f882001-02-23 17:55:21 +00005029
5030/**
5031 * xmlXPathCompareValues:
5032 * @ctxt: the XPath Parser context
5033 * @inf: less than (1) or greater than (0)
5034 * @strict: is the comparison strict
5035 *
5036 * Implement the compare operation on XPath objects:
5037 * @arg1 < @arg2 (1, 1, ...
5038 * @arg1 <= @arg2 (1, 0, ...
5039 * @arg1 > @arg2 (0, 1, ...
5040 * @arg1 >= @arg2 (0, 0, ...
5041 *
5042 * When neither object to be compared is a node-set and the operator is
5043 * <=, <, >=, >, then the objects are compared by converted both objects
5044 * to numbers and comparing the numbers according to IEEE 754. The <
5045 * comparison will be true if and only if the first number is less than the
5046 * second number. The <= comparison will be true if and only if the first
5047 * number is less than or equal to the second number. The > comparison
5048 * will be true if and only if the first number is greater than the second
5049 * number. The >= comparison will be true if and only if the first number
5050 * is greater than or equal to the second number.
5051 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005052 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005053 */
5054int
5055xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005056 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005057 xmlXPathObjectPtr arg1, arg2;
5058
Daniel Veillard6128c012004-11-08 17:16:15 +00005059 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005060 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005061 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005062 if ((arg1 == NULL) || (arg2 == NULL)) {
5063 if (arg1 != NULL)
5064 xmlXPathFreeObject(arg1);
5065 else
5066 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005067 XP_ERROR0(XPATH_INVALID_OPERAND);
5068 }
5069
William M. Brack0c022ad2002-07-12 00:56:01 +00005070 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5071 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5072 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5073 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005074 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005075 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005076 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005077 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5078 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005079 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005080 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5081 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005082 }
5083 }
5084 return(ret);
5085 }
5086
5087 if (arg1->type != XPATH_NUMBER) {
5088 valuePush(ctxt, arg1);
5089 xmlXPathNumberFunction(ctxt, 1);
5090 arg1 = valuePop(ctxt);
5091 }
5092 if (arg1->type != XPATH_NUMBER) {
5093 xmlXPathFreeObject(arg1);
5094 xmlXPathFreeObject(arg2);
5095 XP_ERROR0(XPATH_INVALID_OPERAND);
5096 }
5097 if (arg2->type != XPATH_NUMBER) {
5098 valuePush(ctxt, arg2);
5099 xmlXPathNumberFunction(ctxt, 1);
5100 arg2 = valuePop(ctxt);
5101 }
5102 if (arg2->type != XPATH_NUMBER) {
5103 xmlXPathFreeObject(arg1);
5104 xmlXPathFreeObject(arg2);
5105 XP_ERROR0(XPATH_INVALID_OPERAND);
5106 }
5107 /*
5108 * Add tests for infinity and nan
5109 * => feedback on 3.4 for Inf and NaN
5110 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005111 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005112 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005113 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005114 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005115 arg1i=xmlXPathIsInf(arg1->floatval);
5116 arg2i=xmlXPathIsInf(arg2->floatval);
5117 if (inf && strict) {
5118 if ((arg1i == -1 && arg2i != -1) ||
5119 (arg2i == 1 && arg1i != 1)) {
5120 ret = 1;
5121 } else if (arg1i == 0 && arg2i == 0) {
5122 ret = (arg1->floatval < arg2->floatval);
5123 } else {
5124 ret = 0;
5125 }
5126 }
5127 else if (inf && !strict) {
5128 if (arg1i == -1 || arg2i == 1) {
5129 ret = 1;
5130 } else if (arg1i == 0 && arg2i == 0) {
5131 ret = (arg1->floatval <= arg2->floatval);
5132 } else {
5133 ret = 0;
5134 }
5135 }
5136 else if (!inf && strict) {
5137 if ((arg1i == 1 && arg2i != 1) ||
5138 (arg2i == -1 && arg1i != -1)) {
5139 ret = 1;
5140 } else if (arg1i == 0 && arg2i == 0) {
5141 ret = (arg1->floatval > arg2->floatval);
5142 } else {
5143 ret = 0;
5144 }
5145 }
5146 else if (!inf && !strict) {
5147 if (arg1i == 1 || arg2i == -1) {
5148 ret = 1;
5149 } else if (arg1i == 0 && arg2i == 0) {
5150 ret = (arg1->floatval >= arg2->floatval);
5151 } else {
5152 ret = 0;
5153 }
5154 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005155 }
Owen Taylor3473f882001-02-23 17:55:21 +00005156 xmlXPathFreeObject(arg1);
5157 xmlXPathFreeObject(arg2);
5158 return(ret);
5159}
5160
5161/**
5162 * xmlXPathValueFlipSign:
5163 * @ctxt: the XPath Parser context
5164 *
5165 * Implement the unary - operation on an XPath object
5166 * The numeric operators convert their operands to numbers as if
5167 * by calling the number function.
5168 */
5169void
5170xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005171 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005172 CAST_TO_NUMBER;
5173 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005174 if (xmlXPathIsNaN(ctxt->value->floatval))
5175 ctxt->value->floatval=xmlXPathNAN;
5176 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5177 ctxt->value->floatval=xmlXPathNINF;
5178 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5179 ctxt->value->floatval=xmlXPathPINF;
5180 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005181 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5182 ctxt->value->floatval = xmlXPathNZERO;
5183 else
5184 ctxt->value->floatval = 0;
5185 }
5186 else
5187 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005188}
5189
5190/**
5191 * xmlXPathAddValues:
5192 * @ctxt: the XPath Parser context
5193 *
5194 * Implement the add operation on XPath objects:
5195 * The numeric operators convert their operands to numbers as if
5196 * by calling the number function.
5197 */
5198void
5199xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5200 xmlXPathObjectPtr arg;
5201 double val;
5202
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005203 arg = valuePop(ctxt);
5204 if (arg == NULL)
5205 XP_ERROR(XPATH_INVALID_OPERAND);
5206 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005207 xmlXPathFreeObject(arg);
5208
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005209 CAST_TO_NUMBER;
5210 CHECK_TYPE(XPATH_NUMBER);
5211 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005212}
5213
5214/**
5215 * xmlXPathSubValues:
5216 * @ctxt: the XPath Parser context
5217 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005218 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005219 * The numeric operators convert their operands to numbers as if
5220 * by calling the number function.
5221 */
5222void
5223xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5224 xmlXPathObjectPtr arg;
5225 double val;
5226
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005227 arg = valuePop(ctxt);
5228 if (arg == NULL)
5229 XP_ERROR(XPATH_INVALID_OPERAND);
5230 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005231 xmlXPathFreeObject(arg);
5232
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005233 CAST_TO_NUMBER;
5234 CHECK_TYPE(XPATH_NUMBER);
5235 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005236}
5237
5238/**
5239 * xmlXPathMultValues:
5240 * @ctxt: the XPath Parser context
5241 *
5242 * Implement the multiply operation on XPath objects:
5243 * The numeric operators convert their operands to numbers as if
5244 * by calling the number function.
5245 */
5246void
5247xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5248 xmlXPathObjectPtr arg;
5249 double val;
5250
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005251 arg = valuePop(ctxt);
5252 if (arg == NULL)
5253 XP_ERROR(XPATH_INVALID_OPERAND);
5254 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005255 xmlXPathFreeObject(arg);
5256
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005257 CAST_TO_NUMBER;
5258 CHECK_TYPE(XPATH_NUMBER);
5259 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005260}
5261
5262/**
5263 * xmlXPathDivValues:
5264 * @ctxt: the XPath Parser context
5265 *
5266 * Implement the div operation on XPath objects @arg1 / @arg2:
5267 * The numeric operators convert their operands to numbers as if
5268 * by calling the number function.
5269 */
5270void
5271xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5272 xmlXPathObjectPtr arg;
5273 double val;
5274
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005275 arg = valuePop(ctxt);
5276 if (arg == NULL)
5277 XP_ERROR(XPATH_INVALID_OPERAND);
5278 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005279 xmlXPathFreeObject(arg);
5280
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005281 CAST_TO_NUMBER;
5282 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005283 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5284 ctxt->value->floatval = xmlXPathNAN;
5285 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005286 if (ctxt->value->floatval == 0)
5287 ctxt->value->floatval = xmlXPathNAN;
5288 else if (ctxt->value->floatval > 0)
5289 ctxt->value->floatval = xmlXPathNINF;
5290 else if (ctxt->value->floatval < 0)
5291 ctxt->value->floatval = xmlXPathPINF;
5292 }
5293 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005294 if (ctxt->value->floatval == 0)
5295 ctxt->value->floatval = xmlXPathNAN;
5296 else if (ctxt->value->floatval > 0)
5297 ctxt->value->floatval = xmlXPathPINF;
5298 else if (ctxt->value->floatval < 0)
5299 ctxt->value->floatval = xmlXPathNINF;
5300 } else
5301 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005302}
5303
5304/**
5305 * xmlXPathModValues:
5306 * @ctxt: the XPath Parser context
5307 *
5308 * Implement the mod operation on XPath objects: @arg1 / @arg2
5309 * The numeric operators convert their operands to numbers as if
5310 * by calling the number function.
5311 */
5312void
5313xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5314 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005315 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005316
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005317 arg = valuePop(ctxt);
5318 if (arg == NULL)
5319 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005320 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005321 xmlXPathFreeObject(arg);
5322
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005323 CAST_TO_NUMBER;
5324 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005325 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005326 if (arg2 == 0)
5327 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005328 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005329 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005330 }
Owen Taylor3473f882001-02-23 17:55:21 +00005331}
5332
5333/************************************************************************
5334 * *
5335 * The traversal functions *
5336 * *
5337 ************************************************************************/
5338
Owen Taylor3473f882001-02-23 17:55:21 +00005339/*
5340 * A traversal function enumerates nodes along an axis.
5341 * Initially it must be called with NULL, and it indicates
5342 * termination on the axis by returning NULL.
5343 */
5344typedef xmlNodePtr (*xmlXPathTraversalFunction)
5345 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5346
5347/**
5348 * xmlXPathNextSelf:
5349 * @ctxt: the XPath Parser context
5350 * @cur: the current node in the traversal
5351 *
5352 * Traversal function for the "self" direction
5353 * The self axis contains just the context node itself
5354 *
5355 * Returns the next element following that axis
5356 */
5357xmlNodePtr
5358xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005359 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005360 if (cur == NULL)
5361 return(ctxt->context->node);
5362 return(NULL);
5363}
5364
5365/**
5366 * xmlXPathNextChild:
5367 * @ctxt: the XPath Parser context
5368 * @cur: the current node in the traversal
5369 *
5370 * Traversal function for the "child" direction
5371 * The child axis contains the children of the context node in document order.
5372 *
5373 * Returns the next element following that axis
5374 */
5375xmlNodePtr
5376xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005377 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005378 if (cur == NULL) {
5379 if (ctxt->context->node == NULL) return(NULL);
5380 switch (ctxt->context->node->type) {
5381 case XML_ELEMENT_NODE:
5382 case XML_TEXT_NODE:
5383 case XML_CDATA_SECTION_NODE:
5384 case XML_ENTITY_REF_NODE:
5385 case XML_ENTITY_NODE:
5386 case XML_PI_NODE:
5387 case XML_COMMENT_NODE:
5388 case XML_NOTATION_NODE:
5389 case XML_DTD_NODE:
5390 return(ctxt->context->node->children);
5391 case XML_DOCUMENT_NODE:
5392 case XML_DOCUMENT_TYPE_NODE:
5393 case XML_DOCUMENT_FRAG_NODE:
5394 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005395#ifdef LIBXML_DOCB_ENABLED
5396 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005397#endif
5398 return(((xmlDocPtr) ctxt->context->node)->children);
5399 case XML_ELEMENT_DECL:
5400 case XML_ATTRIBUTE_DECL:
5401 case XML_ENTITY_DECL:
5402 case XML_ATTRIBUTE_NODE:
5403 case XML_NAMESPACE_DECL:
5404 case XML_XINCLUDE_START:
5405 case XML_XINCLUDE_END:
5406 return(NULL);
5407 }
5408 return(NULL);
5409 }
5410 if ((cur->type == XML_DOCUMENT_NODE) ||
5411 (cur->type == XML_HTML_DOCUMENT_NODE))
5412 return(NULL);
5413 return(cur->next);
5414}
5415
5416/**
5417 * xmlXPathNextDescendant:
5418 * @ctxt: the XPath Parser context
5419 * @cur: the current node in the traversal
5420 *
5421 * Traversal function for the "descendant" direction
5422 * the descendant axis contains the descendants of the context node in document
5423 * order; a descendant is a child or a child of a child and so on.
5424 *
5425 * Returns the next element following that axis
5426 */
5427xmlNodePtr
5428xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005429 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005430 if (cur == NULL) {
5431 if (ctxt->context->node == NULL)
5432 return(NULL);
5433 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5434 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5435 return(NULL);
5436
5437 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5438 return(ctxt->context->doc->children);
5439 return(ctxt->context->node->children);
5440 }
5441
Daniel Veillard567e1b42001-08-01 15:53:47 +00005442 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005443 /*
5444 * Do not descend on entities declarations
5445 */
5446 if (cur->children->type != XML_ENTITY_DECL) {
5447 cur = cur->children;
5448 /*
5449 * Skip DTDs
5450 */
5451 if (cur->type != XML_DTD_NODE)
5452 return(cur);
5453 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005454 }
5455
5456 if (cur == ctxt->context->node) return(NULL);
5457
Daniel Veillard68e9e742002-11-16 15:35:11 +00005458 while (cur->next != NULL) {
5459 cur = cur->next;
5460 if ((cur->type != XML_ENTITY_DECL) &&
5461 (cur->type != XML_DTD_NODE))
5462 return(cur);
5463 }
Owen Taylor3473f882001-02-23 17:55:21 +00005464
5465 do {
5466 cur = cur->parent;
5467 if (cur == NULL) return(NULL);
5468 if (cur == ctxt->context->node) return(NULL);
5469 if (cur->next != NULL) {
5470 cur = cur->next;
5471 return(cur);
5472 }
5473 } while (cur != NULL);
5474 return(cur);
5475}
5476
5477/**
5478 * xmlXPathNextDescendantOrSelf:
5479 * @ctxt: the XPath Parser context
5480 * @cur: the current node in the traversal
5481 *
5482 * Traversal function for the "descendant-or-self" direction
5483 * the descendant-or-self axis contains the context node and the descendants
5484 * of the context node in document order; thus the context node is the first
5485 * node on the axis, and the first child of the context node is the second node
5486 * on the axis
5487 *
5488 * Returns the next element following that axis
5489 */
5490xmlNodePtr
5491xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005492 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005493 if (cur == NULL) {
5494 if (ctxt->context->node == NULL)
5495 return(NULL);
5496 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5497 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5498 return(NULL);
5499 return(ctxt->context->node);
5500 }
5501
5502 return(xmlXPathNextDescendant(ctxt, cur));
5503}
5504
5505/**
5506 * xmlXPathNextParent:
5507 * @ctxt: the XPath Parser context
5508 * @cur: the current node in the traversal
5509 *
5510 * Traversal function for the "parent" direction
5511 * The parent axis contains the parent of the context node, if there is one.
5512 *
5513 * Returns the next element following that axis
5514 */
5515xmlNodePtr
5516xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005517 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005518 /*
5519 * the parent of an attribute or namespace node is the element
5520 * to which the attribute or namespace node is attached
5521 * Namespace handling !!!
5522 */
5523 if (cur == NULL) {
5524 if (ctxt->context->node == NULL) return(NULL);
5525 switch (ctxt->context->node->type) {
5526 case XML_ELEMENT_NODE:
5527 case XML_TEXT_NODE:
5528 case XML_CDATA_SECTION_NODE:
5529 case XML_ENTITY_REF_NODE:
5530 case XML_ENTITY_NODE:
5531 case XML_PI_NODE:
5532 case XML_COMMENT_NODE:
5533 case XML_NOTATION_NODE:
5534 case XML_DTD_NODE:
5535 case XML_ELEMENT_DECL:
5536 case XML_ATTRIBUTE_DECL:
5537 case XML_XINCLUDE_START:
5538 case XML_XINCLUDE_END:
5539 case XML_ENTITY_DECL:
5540 if (ctxt->context->node->parent == NULL)
5541 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005542 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005543 ((ctxt->context->node->parent->name[0] == ' ') ||
5544 (xmlStrEqual(ctxt->context->node->parent->name,
5545 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005546 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005547 return(ctxt->context->node->parent);
5548 case XML_ATTRIBUTE_NODE: {
5549 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5550
5551 return(att->parent);
5552 }
5553 case XML_DOCUMENT_NODE:
5554 case XML_DOCUMENT_TYPE_NODE:
5555 case XML_DOCUMENT_FRAG_NODE:
5556 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005557#ifdef LIBXML_DOCB_ENABLED
5558 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005559#endif
5560 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005561 case XML_NAMESPACE_DECL: {
5562 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5563
5564 if ((ns->next != NULL) &&
5565 (ns->next->type != XML_NAMESPACE_DECL))
5566 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005567 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005568 }
Owen Taylor3473f882001-02-23 17:55:21 +00005569 }
5570 }
5571 return(NULL);
5572}
5573
5574/**
5575 * xmlXPathNextAncestor:
5576 * @ctxt: the XPath Parser context
5577 * @cur: the current node in the traversal
5578 *
5579 * Traversal function for the "ancestor" direction
5580 * the ancestor axis contains the ancestors of the context node; the ancestors
5581 * of the context node consist of the parent of context node and the parent's
5582 * parent and so on; the nodes are ordered in reverse document order; thus the
5583 * parent is the first node on the axis, and the parent's parent is the second
5584 * node on the axis
5585 *
5586 * Returns the next element following that axis
5587 */
5588xmlNodePtr
5589xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005590 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005591 /*
5592 * the parent of an attribute or namespace node is the element
5593 * to which the attribute or namespace node is attached
5594 * !!!!!!!!!!!!!
5595 */
5596 if (cur == NULL) {
5597 if (ctxt->context->node == NULL) return(NULL);
5598 switch (ctxt->context->node->type) {
5599 case XML_ELEMENT_NODE:
5600 case XML_TEXT_NODE:
5601 case XML_CDATA_SECTION_NODE:
5602 case XML_ENTITY_REF_NODE:
5603 case XML_ENTITY_NODE:
5604 case XML_PI_NODE:
5605 case XML_COMMENT_NODE:
5606 case XML_DTD_NODE:
5607 case XML_ELEMENT_DECL:
5608 case XML_ATTRIBUTE_DECL:
5609 case XML_ENTITY_DECL:
5610 case XML_NOTATION_NODE:
5611 case XML_XINCLUDE_START:
5612 case XML_XINCLUDE_END:
5613 if (ctxt->context->node->parent == NULL)
5614 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005615 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005616 ((ctxt->context->node->parent->name[0] == ' ') ||
5617 (xmlStrEqual(ctxt->context->node->parent->name,
5618 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005619 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005620 return(ctxt->context->node->parent);
5621 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005622 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005623
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005624 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005625 }
5626 case XML_DOCUMENT_NODE:
5627 case XML_DOCUMENT_TYPE_NODE:
5628 case XML_DOCUMENT_FRAG_NODE:
5629 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005630#ifdef LIBXML_DOCB_ENABLED
5631 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005632#endif
5633 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005634 case XML_NAMESPACE_DECL: {
5635 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5636
5637 if ((ns->next != NULL) &&
5638 (ns->next->type != XML_NAMESPACE_DECL))
5639 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005640 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005641 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005642 }
Owen Taylor3473f882001-02-23 17:55:21 +00005643 }
5644 return(NULL);
5645 }
5646 if (cur == ctxt->context->doc->children)
5647 return((xmlNodePtr) ctxt->context->doc);
5648 if (cur == (xmlNodePtr) ctxt->context->doc)
5649 return(NULL);
5650 switch (cur->type) {
5651 case XML_ELEMENT_NODE:
5652 case XML_TEXT_NODE:
5653 case XML_CDATA_SECTION_NODE:
5654 case XML_ENTITY_REF_NODE:
5655 case XML_ENTITY_NODE:
5656 case XML_PI_NODE:
5657 case XML_COMMENT_NODE:
5658 case XML_NOTATION_NODE:
5659 case XML_DTD_NODE:
5660 case XML_ELEMENT_DECL:
5661 case XML_ATTRIBUTE_DECL:
5662 case XML_ENTITY_DECL:
5663 case XML_XINCLUDE_START:
5664 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005665 if (cur->parent == NULL)
5666 return(NULL);
5667 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005668 ((cur->parent->name[0] == ' ') ||
5669 (xmlStrEqual(cur->parent->name,
5670 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005671 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005672 return(cur->parent);
5673 case XML_ATTRIBUTE_NODE: {
5674 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5675
5676 return(att->parent);
5677 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005678 case XML_NAMESPACE_DECL: {
5679 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5680
5681 if ((ns->next != NULL) &&
5682 (ns->next->type != XML_NAMESPACE_DECL))
5683 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005684 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005685 return(NULL);
5686 }
Owen Taylor3473f882001-02-23 17:55:21 +00005687 case XML_DOCUMENT_NODE:
5688 case XML_DOCUMENT_TYPE_NODE:
5689 case XML_DOCUMENT_FRAG_NODE:
5690 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005691#ifdef LIBXML_DOCB_ENABLED
5692 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005693#endif
5694 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005695 }
5696 return(NULL);
5697}
5698
5699/**
5700 * xmlXPathNextAncestorOrSelf:
5701 * @ctxt: the XPath Parser context
5702 * @cur: the current node in the traversal
5703 *
5704 * Traversal function for the "ancestor-or-self" direction
5705 * he ancestor-or-self axis contains the context node and ancestors of
5706 * the context node in reverse document order; thus the context node is
5707 * the first node on the axis, and the context node's parent the second;
5708 * parent here is defined the same as with the parent axis.
5709 *
5710 * Returns the next element following that axis
5711 */
5712xmlNodePtr
5713xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005714 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005715 if (cur == NULL)
5716 return(ctxt->context->node);
5717 return(xmlXPathNextAncestor(ctxt, cur));
5718}
5719
5720/**
5721 * xmlXPathNextFollowingSibling:
5722 * @ctxt: the XPath Parser context
5723 * @cur: the current node in the traversal
5724 *
5725 * Traversal function for the "following-sibling" direction
5726 * The following-sibling axis contains the following siblings of the context
5727 * node in document order.
5728 *
5729 * Returns the next element following that axis
5730 */
5731xmlNodePtr
5732xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005733 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005734 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5735 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5736 return(NULL);
5737 if (cur == (xmlNodePtr) ctxt->context->doc)
5738 return(NULL);
5739 if (cur == NULL)
5740 return(ctxt->context->node->next);
5741 return(cur->next);
5742}
5743
5744/**
5745 * xmlXPathNextPrecedingSibling:
5746 * @ctxt: the XPath Parser context
5747 * @cur: the current node in the traversal
5748 *
5749 * Traversal function for the "preceding-sibling" direction
5750 * The preceding-sibling axis contains the preceding siblings of the context
5751 * node in reverse document order; the first preceding sibling is first on the
5752 * axis; the sibling preceding that node is the second on the axis and so on.
5753 *
5754 * Returns the next element following that axis
5755 */
5756xmlNodePtr
5757xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005758 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005759 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5760 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5761 return(NULL);
5762 if (cur == (xmlNodePtr) ctxt->context->doc)
5763 return(NULL);
5764 if (cur == NULL)
5765 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005766 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5767 cur = cur->prev;
5768 if (cur == NULL)
5769 return(ctxt->context->node->prev);
5770 }
Owen Taylor3473f882001-02-23 17:55:21 +00005771 return(cur->prev);
5772}
5773
5774/**
5775 * xmlXPathNextFollowing:
5776 * @ctxt: the XPath Parser context
5777 * @cur: the current node in the traversal
5778 *
5779 * Traversal function for the "following" direction
5780 * The following axis contains all nodes in the same document as the context
5781 * node that are after the context node in document order, excluding any
5782 * descendants and excluding attribute nodes and namespace nodes; the nodes
5783 * are ordered in document order
5784 *
5785 * Returns the next element following that axis
5786 */
5787xmlNodePtr
5788xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005789 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005790 if (cur != NULL && cur->children != NULL)
5791 return cur->children ;
5792 if (cur == NULL) cur = ctxt->context->node;
5793 if (cur == NULL) return(NULL) ; /* ERROR */
5794 if (cur->next != NULL) return(cur->next) ;
5795 do {
5796 cur = cur->parent;
5797 if (cur == NULL) return(NULL);
5798 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5799 if (cur->next != NULL) return(cur->next);
5800 } while (cur != NULL);
5801 return(cur);
5802}
5803
5804/*
5805 * xmlXPathIsAncestor:
5806 * @ancestor: the ancestor node
5807 * @node: the current node
5808 *
5809 * Check that @ancestor is a @node's ancestor
5810 *
5811 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5812 */
5813static int
5814xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5815 if ((ancestor == NULL) || (node == NULL)) return(0);
5816 /* nodes need to be in the same document */
5817 if (ancestor->doc != node->doc) return(0);
5818 /* avoid searching if ancestor or node is the root node */
5819 if (ancestor == (xmlNodePtr) node->doc) return(1);
5820 if (node == (xmlNodePtr) ancestor->doc) return(0);
5821 while (node->parent != NULL) {
5822 if (node->parent == ancestor)
5823 return(1);
5824 node = node->parent;
5825 }
5826 return(0);
5827}
5828
5829/**
5830 * xmlXPathNextPreceding:
5831 * @ctxt: the XPath Parser context
5832 * @cur: the current node in the traversal
5833 *
5834 * Traversal function for the "preceding" direction
5835 * the preceding axis contains all nodes in the same document as the context
5836 * node that are before the context node in document order, excluding any
5837 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5838 * ordered in reverse document order
5839 *
5840 * Returns the next element following that axis
5841 */
5842xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005843xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5844{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005845 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005846 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005847 cur = ctxt->context->node;
5848 if (cur == NULL)
5849 return (NULL);
5850 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5851 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005852 do {
5853 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005854 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5855 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005856 }
5857
5858 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005859 if (cur == NULL)
5860 return (NULL);
5861 if (cur == ctxt->context->doc->children)
5862 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005863 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005864 return (cur);
5865}
5866
5867/**
5868 * xmlXPathNextPrecedingInternal:
5869 * @ctxt: the XPath Parser context
5870 * @cur: the current node in the traversal
5871 *
5872 * Traversal function for the "preceding" direction
5873 * the preceding axis contains all nodes in the same document as the context
5874 * node that are before the context node in document order, excluding any
5875 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5876 * ordered in reverse document order
5877 * This is a faster implementation but internal only since it requires a
5878 * state kept in the parser context: ctxt->ancestor.
5879 *
5880 * Returns the next element following that axis
5881 */
5882static xmlNodePtr
5883xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5884 xmlNodePtr cur)
5885{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005886 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005887 if (cur == NULL) {
5888 cur = ctxt->context->node;
5889 if (cur == NULL)
5890 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005891 if (cur->type == XML_NAMESPACE_DECL)
5892 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005893 ctxt->ancestor = cur->parent;
5894 }
5895 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5896 cur = cur->prev;
5897 while (cur->prev == NULL) {
5898 cur = cur->parent;
5899 if (cur == NULL)
5900 return (NULL);
5901 if (cur == ctxt->context->doc->children)
5902 return (NULL);
5903 if (cur != ctxt->ancestor)
5904 return (cur);
5905 ctxt->ancestor = cur->parent;
5906 }
5907 cur = cur->prev;
5908 while (cur->last != NULL)
5909 cur = cur->last;
5910 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005911}
5912
5913/**
5914 * xmlXPathNextNamespace:
5915 * @ctxt: the XPath Parser context
5916 * @cur: the current attribute in the traversal
5917 *
5918 * Traversal function for the "namespace" direction
5919 * the namespace axis contains the namespace nodes of the context node;
5920 * the order of nodes on this axis is implementation-defined; the axis will
5921 * be empty unless the context node is an element
5922 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005923 * We keep the XML namespace node at the end of the list.
5924 *
Owen Taylor3473f882001-02-23 17:55:21 +00005925 * Returns the next element following that axis
5926 */
5927xmlNodePtr
5928xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005929 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005930 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005931 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005932 if (ctxt->context->tmpNsList != NULL)
5933 xmlFree(ctxt->context->tmpNsList);
5934 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005935 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005936 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005937 if (ctxt->context->tmpNsList != NULL) {
5938 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5939 ctxt->context->tmpNsNr++;
5940 }
5941 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005942 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005943 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005944 if (ctxt->context->tmpNsNr > 0) {
5945 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5946 } else {
5947 if (ctxt->context->tmpNsList != NULL)
5948 xmlFree(ctxt->context->tmpNsList);
5949 ctxt->context->tmpNsList = NULL;
5950 return(NULL);
5951 }
Owen Taylor3473f882001-02-23 17:55:21 +00005952}
5953
5954/**
5955 * xmlXPathNextAttribute:
5956 * @ctxt: the XPath Parser context
5957 * @cur: the current attribute in the traversal
5958 *
5959 * Traversal function for the "attribute" direction
5960 * TODO: support DTD inherited default attributes
5961 *
5962 * Returns the next element following that axis
5963 */
5964xmlNodePtr
5965xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005966 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00005967 if (ctxt->context->node == NULL)
5968 return(NULL);
5969 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5970 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005971 if (cur == NULL) {
5972 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5973 return(NULL);
5974 return((xmlNodePtr)ctxt->context->node->properties);
5975 }
5976 return((xmlNodePtr)cur->next);
5977}
5978
5979/************************************************************************
5980 * *
5981 * NodeTest Functions *
5982 * *
5983 ************************************************************************/
5984
Owen Taylor3473f882001-02-23 17:55:21 +00005985#define IS_FUNCTION 200
5986
Owen Taylor3473f882001-02-23 17:55:21 +00005987
5988/************************************************************************
5989 * *
5990 * Implicit tree core function library *
5991 * *
5992 ************************************************************************/
5993
5994/**
5995 * xmlXPathRoot:
5996 * @ctxt: the XPath Parser context
5997 *
5998 * Initialize the context to the root of the document
5999 */
6000void
6001xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006002 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006003 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6004 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6005}
6006
6007/************************************************************************
6008 * *
6009 * The explicit core function library *
6010 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6011 * *
6012 ************************************************************************/
6013
6014
6015/**
6016 * xmlXPathLastFunction:
6017 * @ctxt: the XPath Parser context
6018 * @nargs: the number of arguments
6019 *
6020 * Implement the last() XPath function
6021 * number last()
6022 * The last function returns the number of nodes in the context node list.
6023 */
6024void
6025xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6026 CHECK_ARITY(0);
6027 if (ctxt->context->contextSize >= 0) {
6028 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6029#ifdef DEBUG_EXPR
6030 xmlGenericError(xmlGenericErrorContext,
6031 "last() : %d\n", ctxt->context->contextSize);
6032#endif
6033 } else {
6034 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6035 }
6036}
6037
6038/**
6039 * xmlXPathPositionFunction:
6040 * @ctxt: the XPath Parser context
6041 * @nargs: the number of arguments
6042 *
6043 * Implement the position() XPath function
6044 * number position()
6045 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006046 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006047 * will be equal to last().
6048 */
6049void
6050xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6051 CHECK_ARITY(0);
6052 if (ctxt->context->proximityPosition >= 0) {
6053 valuePush(ctxt,
6054 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6055#ifdef DEBUG_EXPR
6056 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6057 ctxt->context->proximityPosition);
6058#endif
6059 } else {
6060 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6061 }
6062}
6063
6064/**
6065 * xmlXPathCountFunction:
6066 * @ctxt: the XPath Parser context
6067 * @nargs: the number of arguments
6068 *
6069 * Implement the count() XPath function
6070 * number count(node-set)
6071 */
6072void
6073xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6074 xmlXPathObjectPtr cur;
6075
6076 CHECK_ARITY(1);
6077 if ((ctxt->value == NULL) ||
6078 ((ctxt->value->type != XPATH_NODESET) &&
6079 (ctxt->value->type != XPATH_XSLT_TREE)))
6080 XP_ERROR(XPATH_INVALID_TYPE);
6081 cur = valuePop(ctxt);
6082
Daniel Veillard911f49a2001-04-07 15:39:35 +00006083 if ((cur == NULL) || (cur->nodesetval == NULL))
6084 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006085 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006086 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006087 } else {
6088 if ((cur->nodesetval->nodeNr != 1) ||
6089 (cur->nodesetval->nodeTab == NULL)) {
6090 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6091 } else {
6092 xmlNodePtr tmp;
6093 int i = 0;
6094
6095 tmp = cur->nodesetval->nodeTab[0];
6096 if (tmp != NULL) {
6097 tmp = tmp->children;
6098 while (tmp != NULL) {
6099 tmp = tmp->next;
6100 i++;
6101 }
6102 }
6103 valuePush(ctxt, xmlXPathNewFloat((double) i));
6104 }
6105 }
Owen Taylor3473f882001-02-23 17:55:21 +00006106 xmlXPathFreeObject(cur);
6107}
6108
6109/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006110 * xmlXPathGetElementsByIds:
6111 * @doc: the document
6112 * @ids: a whitespace separated list of IDs
6113 *
6114 * Selects elements by their unique ID.
6115 *
6116 * Returns a node-set of selected elements.
6117 */
6118static xmlNodeSetPtr
6119xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6120 xmlNodeSetPtr ret;
6121 const xmlChar *cur = ids;
6122 xmlChar *ID;
6123 xmlAttrPtr attr;
6124 xmlNodePtr elem = NULL;
6125
Daniel Veillard7a985a12003-07-06 17:57:42 +00006126 if (ids == NULL) return(NULL);
6127
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006128 ret = xmlXPathNodeSetCreate(NULL);
6129
William M. Brack76e95df2003-10-18 16:20:14 +00006130 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006131 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006132 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006133 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006134
6135 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006136 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006137 /*
6138 * We used to check the fact that the value passed
6139 * was an NCName, but this generated much troubles for
6140 * me and Aleksey Sanin, people blatantly violated that
6141 * constaint, like Visa3D spec.
6142 * if (xmlValidateNCName(ID, 1) == 0)
6143 */
6144 attr = xmlGetID(doc, ID);
6145 if (attr != NULL) {
6146 if (attr->type == XML_ATTRIBUTE_NODE)
6147 elem = attr->parent;
6148 else if (attr->type == XML_ELEMENT_NODE)
6149 elem = (xmlNodePtr) attr;
6150 else
6151 elem = NULL;
6152 if (elem != NULL)
6153 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006154 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006155 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006156 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006157
William M. Brack76e95df2003-10-18 16:20:14 +00006158 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006159 ids = cur;
6160 }
6161 return(ret);
6162}
6163
6164/**
Owen Taylor3473f882001-02-23 17:55:21 +00006165 * xmlXPathIdFunction:
6166 * @ctxt: the XPath Parser context
6167 * @nargs: the number of arguments
6168 *
6169 * Implement the id() XPath function
6170 * node-set id(object)
6171 * The id function selects elements by their unique ID
6172 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6173 * then the result is the union of the result of applying id to the
6174 * string value of each of the nodes in the argument node-set. When the
6175 * argument to id is of any other type, the argument is converted to a
6176 * string as if by a call to the string function; the string is split
6177 * into a whitespace-separated list of tokens (whitespace is any sequence
6178 * of characters matching the production S); the result is a node-set
6179 * containing the elements in the same document as the context node that
6180 * have a unique ID equal to any of the tokens in the list.
6181 */
6182void
6183xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006184 xmlChar *tokens;
6185 xmlNodeSetPtr ret;
6186 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006187
6188 CHECK_ARITY(1);
6189 obj = valuePop(ctxt);
6190 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006191 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006192 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006193 int i;
6194
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006195 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006196
Daniel Veillard911f49a2001-04-07 15:39:35 +00006197 if (obj->nodesetval != NULL) {
6198 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006199 tokens =
6200 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6201 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6202 ret = xmlXPathNodeSetMerge(ret, ns);
6203 xmlXPathFreeNodeSet(ns);
6204 if (tokens != NULL)
6205 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006206 }
Owen Taylor3473f882001-02-23 17:55:21 +00006207 }
6208
6209 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006210 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006211 return;
6212 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006213 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006214
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006215 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6216 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006217
Owen Taylor3473f882001-02-23 17:55:21 +00006218 xmlXPathFreeObject(obj);
6219 return;
6220}
6221
6222/**
6223 * xmlXPathLocalNameFunction:
6224 * @ctxt: the XPath Parser context
6225 * @nargs: the number of arguments
6226 *
6227 * Implement the local-name() XPath function
6228 * string local-name(node-set?)
6229 * The local-name function returns a string containing the local part
6230 * of the name of the node in the argument node-set that is first in
6231 * document order. If the node-set is empty or the first node has no
6232 * name, an empty string is returned. If the argument is omitted it
6233 * defaults to the context node.
6234 */
6235void
6236xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6237 xmlXPathObjectPtr cur;
6238
Daniel Veillarda82b1822004-11-08 16:24:57 +00006239 if (ctxt == NULL) return;
6240
Owen Taylor3473f882001-02-23 17:55:21 +00006241 if (nargs == 0) {
6242 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6243 nargs = 1;
6244 }
6245
6246 CHECK_ARITY(1);
6247 if ((ctxt->value == NULL) ||
6248 ((ctxt->value->type != XPATH_NODESET) &&
6249 (ctxt->value->type != XPATH_XSLT_TREE)))
6250 XP_ERROR(XPATH_INVALID_TYPE);
6251 cur = valuePop(ctxt);
6252
Daniel Veillard911f49a2001-04-07 15:39:35 +00006253 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006254 valuePush(ctxt, xmlXPathNewCString(""));
6255 } else {
6256 int i = 0; /* Should be first in document order !!!!! */
6257 switch (cur->nodesetval->nodeTab[i]->type) {
6258 case XML_ELEMENT_NODE:
6259 case XML_ATTRIBUTE_NODE:
6260 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006261 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6262 valuePush(ctxt, xmlXPathNewCString(""));
6263 else
6264 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006265 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6266 break;
6267 case XML_NAMESPACE_DECL:
6268 valuePush(ctxt, xmlXPathNewString(
6269 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6270 break;
6271 default:
6272 valuePush(ctxt, xmlXPathNewCString(""));
6273 }
6274 }
6275 xmlXPathFreeObject(cur);
6276}
6277
6278/**
6279 * xmlXPathNamespaceURIFunction:
6280 * @ctxt: the XPath Parser context
6281 * @nargs: the number of arguments
6282 *
6283 * Implement the namespace-uri() XPath function
6284 * string namespace-uri(node-set?)
6285 * The namespace-uri function returns a string containing the
6286 * namespace URI of the expanded name of the node in the argument
6287 * node-set that is first in document order. If the node-set is empty,
6288 * the first node has no name, or the expanded name has no namespace
6289 * URI, an empty string is returned. If the argument is omitted it
6290 * defaults to the context node.
6291 */
6292void
6293xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6294 xmlXPathObjectPtr cur;
6295
Daniel Veillarda82b1822004-11-08 16:24:57 +00006296 if (ctxt == NULL) return;
6297
Owen Taylor3473f882001-02-23 17:55:21 +00006298 if (nargs == 0) {
6299 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6300 nargs = 1;
6301 }
6302 CHECK_ARITY(1);
6303 if ((ctxt->value == NULL) ||
6304 ((ctxt->value->type != XPATH_NODESET) &&
6305 (ctxt->value->type != XPATH_XSLT_TREE)))
6306 XP_ERROR(XPATH_INVALID_TYPE);
6307 cur = valuePop(ctxt);
6308
Daniel Veillard911f49a2001-04-07 15:39:35 +00006309 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006310 valuePush(ctxt, xmlXPathNewCString(""));
6311 } else {
6312 int i = 0; /* Should be first in document order !!!!! */
6313 switch (cur->nodesetval->nodeTab[i]->type) {
6314 case XML_ELEMENT_NODE:
6315 case XML_ATTRIBUTE_NODE:
6316 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6317 valuePush(ctxt, xmlXPathNewCString(""));
6318 else
6319 valuePush(ctxt, xmlXPathNewString(
6320 cur->nodesetval->nodeTab[i]->ns->href));
6321 break;
6322 default:
6323 valuePush(ctxt, xmlXPathNewCString(""));
6324 }
6325 }
6326 xmlXPathFreeObject(cur);
6327}
6328
6329/**
6330 * xmlXPathNameFunction:
6331 * @ctxt: the XPath Parser context
6332 * @nargs: the number of arguments
6333 *
6334 * Implement the name() XPath function
6335 * string name(node-set?)
6336 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006337 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006338 * order. The QName must represent the name with respect to the namespace
6339 * declarations in effect on the node whose name is being represented.
6340 * Typically, this will be the form in which the name occurred in the XML
6341 * source. This need not be the case if there are namespace declarations
6342 * in effect on the node that associate multiple prefixes with the same
6343 * namespace. However, an implementation may include information about
6344 * the original prefix in its representation of nodes; in this case, an
6345 * implementation can ensure that the returned string is always the same
6346 * as the QName used in the XML source. If the argument it omitted it
6347 * defaults to the context node.
6348 * Libxml keep the original prefix so the "real qualified name" used is
6349 * returned.
6350 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006351static void
Daniel Veillard04383752001-07-08 14:27:15 +00006352xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6353{
Owen Taylor3473f882001-02-23 17:55:21 +00006354 xmlXPathObjectPtr cur;
6355
6356 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006357 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6358 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006359 }
6360
6361 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006362 if ((ctxt->value == NULL) ||
6363 ((ctxt->value->type != XPATH_NODESET) &&
6364 (ctxt->value->type != XPATH_XSLT_TREE)))
6365 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006366 cur = valuePop(ctxt);
6367
Daniel Veillard911f49a2001-04-07 15:39:35 +00006368 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006369 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006370 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006371 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006372
Daniel Veillard04383752001-07-08 14:27:15 +00006373 switch (cur->nodesetval->nodeTab[i]->type) {
6374 case XML_ELEMENT_NODE:
6375 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006376 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6377 valuePush(ctxt, xmlXPathNewCString(""));
6378 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6379 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006380 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006381 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006382
Daniel Veillard652d8a92003-02-04 19:28:49 +00006383 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006384 xmlChar *fullname;
6385
6386 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6387 cur->nodesetval->nodeTab[i]->ns->prefix,
6388 NULL, 0);
6389 if (fullname == cur->nodesetval->nodeTab[i]->name)
6390 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6391 if (fullname == NULL) {
6392 XP_ERROR(XPATH_MEMORY_ERROR);
6393 }
6394 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006395 }
6396 break;
6397 default:
6398 valuePush(ctxt,
6399 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6400 xmlXPathLocalNameFunction(ctxt, 1);
6401 }
Owen Taylor3473f882001-02-23 17:55:21 +00006402 }
6403 xmlXPathFreeObject(cur);
6404}
6405
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006406
6407/**
Owen Taylor3473f882001-02-23 17:55:21 +00006408 * xmlXPathStringFunction:
6409 * @ctxt: the XPath Parser context
6410 * @nargs: the number of arguments
6411 *
6412 * Implement the string() XPath function
6413 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006414 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006415 * - A node-set is converted to a string by returning the value of
6416 * the node in the node-set that is first in document order.
6417 * If the node-set is empty, an empty string is returned.
6418 * - A number is converted to a string as follows
6419 * + NaN is converted to the string NaN
6420 * + positive zero is converted to the string 0
6421 * + negative zero is converted to the string 0
6422 * + positive infinity is converted to the string Infinity
6423 * + negative infinity is converted to the string -Infinity
6424 * + if the number is an integer, the number is represented in
6425 * decimal form as a Number with no decimal point and no leading
6426 * zeros, preceded by a minus sign (-) if the number is negative
6427 * + otherwise, the number is represented in decimal form as a
6428 * Number including a decimal point with at least one digit
6429 * before the decimal point and at least one digit after the
6430 * decimal point, preceded by a minus sign (-) if the number
6431 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006432 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006433 * before the decimal point; beyond the one required digit
6434 * after the decimal point there must be as many, but only as
6435 * many, more digits as are needed to uniquely distinguish the
6436 * number from all other IEEE 754 numeric values.
6437 * - The boolean false value is converted to the string false.
6438 * The boolean true value is converted to the string true.
6439 *
6440 * If the argument is omitted, it defaults to a node-set with the
6441 * context node as its only member.
6442 */
6443void
6444xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6445 xmlXPathObjectPtr cur;
6446
Daniel Veillarda82b1822004-11-08 16:24:57 +00006447 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006448 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006449 valuePush(ctxt,
6450 xmlXPathWrapString(
6451 xmlXPathCastNodeToString(ctxt->context->node)));
6452 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006453 }
6454
6455 CHECK_ARITY(1);
6456 cur = valuePop(ctxt);
6457 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006458 cur = xmlXPathConvertString(cur);
6459 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006460}
6461
6462/**
6463 * xmlXPathStringLengthFunction:
6464 * @ctxt: the XPath Parser context
6465 * @nargs: the number of arguments
6466 *
6467 * Implement the string-length() XPath function
6468 * number string-length(string?)
6469 * The string-length returns the number of characters in the string
6470 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6471 * the context node converted to a string, in other words the value
6472 * of the context node.
6473 */
6474void
6475xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6476 xmlXPathObjectPtr cur;
6477
6478 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006479 if ((ctxt == NULL) || (ctxt->context == NULL))
6480 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006481 if (ctxt->context->node == NULL) {
6482 valuePush(ctxt, xmlXPathNewFloat(0));
6483 } else {
6484 xmlChar *content;
6485
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006486 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006487 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006488 xmlFree(content);
6489 }
6490 return;
6491 }
6492 CHECK_ARITY(1);
6493 CAST_TO_STRING;
6494 CHECK_TYPE(XPATH_STRING);
6495 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006496 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006497 xmlXPathFreeObject(cur);
6498}
6499
6500/**
6501 * xmlXPathConcatFunction:
6502 * @ctxt: the XPath Parser context
6503 * @nargs: the number of arguments
6504 *
6505 * Implement the concat() XPath function
6506 * string concat(string, string, string*)
6507 * The concat function returns the concatenation of its arguments.
6508 */
6509void
6510xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6511 xmlXPathObjectPtr cur, newobj;
6512 xmlChar *tmp;
6513
Daniel Veillarda82b1822004-11-08 16:24:57 +00006514 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006515 if (nargs < 2) {
6516 CHECK_ARITY(2);
6517 }
6518
6519 CAST_TO_STRING;
6520 cur = valuePop(ctxt);
6521 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6522 xmlXPathFreeObject(cur);
6523 return;
6524 }
6525 nargs--;
6526
6527 while (nargs > 0) {
6528 CAST_TO_STRING;
6529 newobj = valuePop(ctxt);
6530 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6531 xmlXPathFreeObject(newobj);
6532 xmlXPathFreeObject(cur);
6533 XP_ERROR(XPATH_INVALID_TYPE);
6534 }
6535 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6536 newobj->stringval = cur->stringval;
6537 cur->stringval = tmp;
6538
6539 xmlXPathFreeObject(newobj);
6540 nargs--;
6541 }
6542 valuePush(ctxt, cur);
6543}
6544
6545/**
6546 * xmlXPathContainsFunction:
6547 * @ctxt: the XPath Parser context
6548 * @nargs: the number of arguments
6549 *
6550 * Implement the contains() XPath function
6551 * boolean contains(string, string)
6552 * The contains function returns true if the first argument string
6553 * contains the second argument string, and otherwise returns false.
6554 */
6555void
6556xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6557 xmlXPathObjectPtr hay, needle;
6558
6559 CHECK_ARITY(2);
6560 CAST_TO_STRING;
6561 CHECK_TYPE(XPATH_STRING);
6562 needle = valuePop(ctxt);
6563 CAST_TO_STRING;
6564 hay = valuePop(ctxt);
6565 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6566 xmlXPathFreeObject(hay);
6567 xmlXPathFreeObject(needle);
6568 XP_ERROR(XPATH_INVALID_TYPE);
6569 }
6570 if (xmlStrstr(hay->stringval, needle->stringval))
6571 valuePush(ctxt, xmlXPathNewBoolean(1));
6572 else
6573 valuePush(ctxt, xmlXPathNewBoolean(0));
6574 xmlXPathFreeObject(hay);
6575 xmlXPathFreeObject(needle);
6576}
6577
6578/**
6579 * xmlXPathStartsWithFunction:
6580 * @ctxt: the XPath Parser context
6581 * @nargs: the number of arguments
6582 *
6583 * Implement the starts-with() XPath function
6584 * boolean starts-with(string, string)
6585 * The starts-with function returns true if the first argument string
6586 * starts with the second argument string, and otherwise returns false.
6587 */
6588void
6589xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6590 xmlXPathObjectPtr hay, needle;
6591 int n;
6592
6593 CHECK_ARITY(2);
6594 CAST_TO_STRING;
6595 CHECK_TYPE(XPATH_STRING);
6596 needle = valuePop(ctxt);
6597 CAST_TO_STRING;
6598 hay = valuePop(ctxt);
6599 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6600 xmlXPathFreeObject(hay);
6601 xmlXPathFreeObject(needle);
6602 XP_ERROR(XPATH_INVALID_TYPE);
6603 }
6604 n = xmlStrlen(needle->stringval);
6605 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6606 valuePush(ctxt, xmlXPathNewBoolean(0));
6607 else
6608 valuePush(ctxt, xmlXPathNewBoolean(1));
6609 xmlXPathFreeObject(hay);
6610 xmlXPathFreeObject(needle);
6611}
6612
6613/**
6614 * xmlXPathSubstringFunction:
6615 * @ctxt: the XPath Parser context
6616 * @nargs: the number of arguments
6617 *
6618 * Implement the substring() XPath function
6619 * string substring(string, number, number?)
6620 * The substring function returns the substring of the first argument
6621 * starting at the position specified in the second argument with
6622 * length specified in the third argument. For example,
6623 * substring("12345",2,3) returns "234". If the third argument is not
6624 * specified, it returns the substring starting at the position specified
6625 * in the second argument and continuing to the end of the string. For
6626 * example, substring("12345",2) returns "2345". More precisely, each
6627 * character in the string (see [3.6 Strings]) is considered to have a
6628 * numeric position: the position of the first character is 1, the position
6629 * of the second character is 2 and so on. The returned substring contains
6630 * those characters for which the position of the character is greater than
6631 * or equal to the second argument and, if the third argument is specified,
6632 * less than the sum of the second and third arguments; the comparisons
6633 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6634 * - substring("12345", 1.5, 2.6) returns "234"
6635 * - substring("12345", 0, 3) returns "12"
6636 * - substring("12345", 0 div 0, 3) returns ""
6637 * - substring("12345", 1, 0 div 0) returns ""
6638 * - substring("12345", -42, 1 div 0) returns "12345"
6639 * - substring("12345", -1 div 0, 1 div 0) returns ""
6640 */
6641void
6642xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6643 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006644 double le=0, in;
6645 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006646 xmlChar *ret;
6647
Owen Taylor3473f882001-02-23 17:55:21 +00006648 if (nargs < 2) {
6649 CHECK_ARITY(2);
6650 }
6651 if (nargs > 3) {
6652 CHECK_ARITY(3);
6653 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006654 /*
6655 * take care of possible last (position) argument
6656 */
Owen Taylor3473f882001-02-23 17:55:21 +00006657 if (nargs == 3) {
6658 CAST_TO_NUMBER;
6659 CHECK_TYPE(XPATH_NUMBER);
6660 len = valuePop(ctxt);
6661 le = len->floatval;
6662 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006663 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006664
Owen Taylor3473f882001-02-23 17:55:21 +00006665 CAST_TO_NUMBER;
6666 CHECK_TYPE(XPATH_NUMBER);
6667 start = valuePop(ctxt);
6668 in = start->floatval;
6669 xmlXPathFreeObject(start);
6670 CAST_TO_STRING;
6671 CHECK_TYPE(XPATH_STRING);
6672 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006673 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006674
Daniel Veillard97ac1312001-05-30 19:14:17 +00006675 /*
6676 * If last pos not present, calculate last position
6677 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006678 if (nargs != 3) {
6679 le = (double)m;
6680 if (in < 1.0)
6681 in = 1.0;
6682 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006683
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006684 /* Need to check for the special cases where either
6685 * the index is NaN, the length is NaN, or both
6686 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006687 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006688 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006689 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006690 * To meet the requirements of the spec, the arguments
6691 * must be converted to integer format before
6692 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006693 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006694 * First we go to integer form, rounding up
6695 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006696 */
6697 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006698 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006699
Daniel Veillard9e412302002-06-10 15:59:44 +00006700 if (xmlXPathIsInf(le) == 1) {
6701 l = m;
6702 if (i < 1)
6703 i = 1;
6704 }
6705 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6706 l = 0;
6707 else {
6708 l = (int) le;
6709 if (((double)l)+0.5 <= le) l++;
6710 }
6711
6712 /* Now we normalize inidices */
6713 i -= 1;
6714 l += i;
6715 if (i < 0)
6716 i = 0;
6717 if (l > m)
6718 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006719
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006720 /* number of chars to copy */
6721 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006722
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006723 ret = xmlUTF8Strsub(str->stringval, i, l);
6724 }
6725 else {
6726 ret = NULL;
6727 }
6728
Owen Taylor3473f882001-02-23 17:55:21 +00006729 if (ret == NULL)
6730 valuePush(ctxt, xmlXPathNewCString(""));
6731 else {
6732 valuePush(ctxt, xmlXPathNewString(ret));
6733 xmlFree(ret);
6734 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006735
Owen Taylor3473f882001-02-23 17:55:21 +00006736 xmlXPathFreeObject(str);
6737}
6738
6739/**
6740 * xmlXPathSubstringBeforeFunction:
6741 * @ctxt: the XPath Parser context
6742 * @nargs: the number of arguments
6743 *
6744 * Implement the substring-before() XPath function
6745 * string substring-before(string, string)
6746 * The substring-before function returns the substring of the first
6747 * argument string that precedes the first occurrence of the second
6748 * argument string in the first argument string, or the empty string
6749 * if the first argument string does not contain the second argument
6750 * string. For example, substring-before("1999/04/01","/") returns 1999.
6751 */
6752void
6753xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6754 xmlXPathObjectPtr str;
6755 xmlXPathObjectPtr find;
6756 xmlBufferPtr target;
6757 const xmlChar *point;
6758 int offset;
6759
6760 CHECK_ARITY(2);
6761 CAST_TO_STRING;
6762 find = valuePop(ctxt);
6763 CAST_TO_STRING;
6764 str = valuePop(ctxt);
6765
6766 target = xmlBufferCreate();
6767 if (target) {
6768 point = xmlStrstr(str->stringval, find->stringval);
6769 if (point) {
6770 offset = (int)(point - str->stringval);
6771 xmlBufferAdd(target, str->stringval, offset);
6772 }
6773 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6774 xmlBufferFree(target);
6775 }
6776
6777 xmlXPathFreeObject(str);
6778 xmlXPathFreeObject(find);
6779}
6780
6781/**
6782 * xmlXPathSubstringAfterFunction:
6783 * @ctxt: the XPath Parser context
6784 * @nargs: the number of arguments
6785 *
6786 * Implement the substring-after() XPath function
6787 * string substring-after(string, string)
6788 * The substring-after function returns the substring of the first
6789 * argument string that follows the first occurrence of the second
6790 * argument string in the first argument string, or the empty stringi
6791 * if the first argument string does not contain the second argument
6792 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6793 * and substring-after("1999/04/01","19") returns 99/04/01.
6794 */
6795void
6796xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6797 xmlXPathObjectPtr str;
6798 xmlXPathObjectPtr find;
6799 xmlBufferPtr target;
6800 const xmlChar *point;
6801 int offset;
6802
6803 CHECK_ARITY(2);
6804 CAST_TO_STRING;
6805 find = valuePop(ctxt);
6806 CAST_TO_STRING;
6807 str = valuePop(ctxt);
6808
6809 target = xmlBufferCreate();
6810 if (target) {
6811 point = xmlStrstr(str->stringval, find->stringval);
6812 if (point) {
6813 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6814 xmlBufferAdd(target, &str->stringval[offset],
6815 xmlStrlen(str->stringval) - offset);
6816 }
6817 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6818 xmlBufferFree(target);
6819 }
6820
6821 xmlXPathFreeObject(str);
6822 xmlXPathFreeObject(find);
6823}
6824
6825/**
6826 * xmlXPathNormalizeFunction:
6827 * @ctxt: the XPath Parser context
6828 * @nargs: the number of arguments
6829 *
6830 * Implement the normalize-space() XPath function
6831 * string normalize-space(string?)
6832 * The normalize-space function returns the argument string with white
6833 * space normalized by stripping leading and trailing whitespace
6834 * and replacing sequences of whitespace characters by a single
6835 * space. Whitespace characters are the same allowed by the S production
6836 * in XML. If the argument is omitted, it defaults to the context
6837 * node converted to a string, in other words the value of the context node.
6838 */
6839void
6840xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6841 xmlXPathObjectPtr obj = NULL;
6842 xmlChar *source = NULL;
6843 xmlBufferPtr target;
6844 xmlChar blank;
6845
Daniel Veillarda82b1822004-11-08 16:24:57 +00006846 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006847 if (nargs == 0) {
6848 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006849 valuePush(ctxt,
6850 xmlXPathWrapString(
6851 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006852 nargs = 1;
6853 }
6854
6855 CHECK_ARITY(1);
6856 CAST_TO_STRING;
6857 CHECK_TYPE(XPATH_STRING);
6858 obj = valuePop(ctxt);
6859 source = obj->stringval;
6860
6861 target = xmlBufferCreate();
6862 if (target && source) {
6863
6864 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006865 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006866 source++;
6867
6868 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6869 blank = 0;
6870 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006871 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006872 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006873 } else {
6874 if (blank) {
6875 xmlBufferAdd(target, &blank, 1);
6876 blank = 0;
6877 }
6878 xmlBufferAdd(target, source, 1);
6879 }
6880 source++;
6881 }
6882
6883 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6884 xmlBufferFree(target);
6885 }
6886 xmlXPathFreeObject(obj);
6887}
6888
6889/**
6890 * xmlXPathTranslateFunction:
6891 * @ctxt: the XPath Parser context
6892 * @nargs: the number of arguments
6893 *
6894 * Implement the translate() XPath function
6895 * string translate(string, string, string)
6896 * The translate function returns the first argument string with
6897 * occurrences of characters in the second argument string replaced
6898 * by the character at the corresponding position in the third argument
6899 * string. For example, translate("bar","abc","ABC") returns the string
6900 * BAr. If there is a character in the second argument string with no
6901 * character at a corresponding position in the third argument string
6902 * (because the second argument string is longer than the third argument
6903 * string), then occurrences of that character in the first argument
6904 * string are removed. For example, translate("--aaa--","abc-","ABC")
6905 * returns "AAA". If a character occurs more than once in second
6906 * argument string, then the first occurrence determines the replacement
6907 * character. If the third argument string is longer than the second
6908 * argument string, then excess characters are ignored.
6909 */
6910void
6911xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006912 xmlXPathObjectPtr str;
6913 xmlXPathObjectPtr from;
6914 xmlXPathObjectPtr to;
6915 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006916 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006917 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006918 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006919 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006920
Daniel Veillarde043ee12001-04-16 14:08:07 +00006921 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006922
Daniel Veillarde043ee12001-04-16 14:08:07 +00006923 CAST_TO_STRING;
6924 to = valuePop(ctxt);
6925 CAST_TO_STRING;
6926 from = valuePop(ctxt);
6927 CAST_TO_STRING;
6928 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006929
Daniel Veillarde043ee12001-04-16 14:08:07 +00006930 target = xmlBufferCreate();
6931 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006932 max = xmlUTF8Strlen(to->stringval);
6933 for (cptr = str->stringval; (ch=*cptr); ) {
6934 offset = xmlUTF8Strloc(from->stringval, cptr);
6935 if (offset >= 0) {
6936 if (offset < max) {
6937 point = xmlUTF8Strpos(to->stringval, offset);
6938 if (point)
6939 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6940 }
6941 } else
6942 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6943
6944 /* Step to next character in input */
6945 cptr++;
6946 if ( ch & 0x80 ) {
6947 /* if not simple ascii, verify proper format */
6948 if ( (ch & 0xc0) != 0xc0 ) {
6949 xmlGenericError(xmlGenericErrorContext,
6950 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6951 break;
6952 }
6953 /* then skip over remaining bytes for this char */
6954 while ( (ch <<= 1) & 0x80 )
6955 if ( (*cptr++ & 0xc0) != 0x80 ) {
6956 xmlGenericError(xmlGenericErrorContext,
6957 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6958 break;
6959 }
6960 if (ch & 0x80) /* must have had error encountered */
6961 break;
6962 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006963 }
Owen Taylor3473f882001-02-23 17:55:21 +00006964 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006965 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6966 xmlBufferFree(target);
6967 xmlXPathFreeObject(str);
6968 xmlXPathFreeObject(from);
6969 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006970}
6971
6972/**
6973 * xmlXPathBooleanFunction:
6974 * @ctxt: the XPath Parser context
6975 * @nargs: the number of arguments
6976 *
6977 * Implement the boolean() XPath function
6978 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006979 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006980 * - a number is true if and only if it is neither positive or
6981 * negative zero nor NaN
6982 * - a node-set is true if and only if it is non-empty
6983 * - a string is true if and only if its length is non-zero
6984 */
6985void
6986xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6987 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006988
6989 CHECK_ARITY(1);
6990 cur = valuePop(ctxt);
6991 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006992 cur = xmlXPathConvertBoolean(cur);
6993 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006994}
6995
6996/**
6997 * xmlXPathNotFunction:
6998 * @ctxt: the XPath Parser context
6999 * @nargs: the number of arguments
7000 *
7001 * Implement the not() XPath function
7002 * boolean not(boolean)
7003 * The not function returns true if its argument is false,
7004 * and false otherwise.
7005 */
7006void
7007xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7008 CHECK_ARITY(1);
7009 CAST_TO_BOOLEAN;
7010 CHECK_TYPE(XPATH_BOOLEAN);
7011 ctxt->value->boolval = ! ctxt->value->boolval;
7012}
7013
7014/**
7015 * xmlXPathTrueFunction:
7016 * @ctxt: the XPath Parser context
7017 * @nargs: the number of arguments
7018 *
7019 * Implement the true() XPath function
7020 * boolean true()
7021 */
7022void
7023xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7024 CHECK_ARITY(0);
7025 valuePush(ctxt, xmlXPathNewBoolean(1));
7026}
7027
7028/**
7029 * xmlXPathFalseFunction:
7030 * @ctxt: the XPath Parser context
7031 * @nargs: the number of arguments
7032 *
7033 * Implement the false() XPath function
7034 * boolean false()
7035 */
7036void
7037xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7038 CHECK_ARITY(0);
7039 valuePush(ctxt, xmlXPathNewBoolean(0));
7040}
7041
7042/**
7043 * xmlXPathLangFunction:
7044 * @ctxt: the XPath Parser context
7045 * @nargs: the number of arguments
7046 *
7047 * Implement the lang() XPath function
7048 * boolean lang(string)
7049 * The lang function returns true or false depending on whether the
7050 * language of the context node as specified by xml:lang attributes
7051 * is the same as or is a sublanguage of the language specified by
7052 * the argument string. The language of the context node is determined
7053 * by the value of the xml:lang attribute on the context node, or, if
7054 * the context node has no xml:lang attribute, by the value of the
7055 * xml:lang attribute on the nearest ancestor of the context node that
7056 * has an xml:lang attribute. If there is no such attribute, then lang
7057 * returns false. If there is such an attribute, then lang returns
7058 * true if the attribute value is equal to the argument ignoring case,
7059 * or if there is some suffix starting with - such that the attribute
7060 * value is equal to the argument ignoring that suffix of the attribute
7061 * value and ignoring case.
7062 */
7063void
7064xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7065 xmlXPathObjectPtr val;
7066 const xmlChar *theLang;
7067 const xmlChar *lang;
7068 int ret = 0;
7069 int i;
7070
7071 CHECK_ARITY(1);
7072 CAST_TO_STRING;
7073 CHECK_TYPE(XPATH_STRING);
7074 val = valuePop(ctxt);
7075 lang = val->stringval;
7076 theLang = xmlNodeGetLang(ctxt->context->node);
7077 if ((theLang != NULL) && (lang != NULL)) {
7078 for (i = 0;lang[i] != 0;i++)
7079 if (toupper(lang[i]) != toupper(theLang[i]))
7080 goto not_equal;
7081 ret = 1;
7082 }
7083not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007084 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007085 xmlXPathFreeObject(val);
7086 valuePush(ctxt, xmlXPathNewBoolean(ret));
7087}
7088
7089/**
7090 * xmlXPathNumberFunction:
7091 * @ctxt: the XPath Parser context
7092 * @nargs: the number of arguments
7093 *
7094 * Implement the number() XPath function
7095 * number number(object?)
7096 */
7097void
7098xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7099 xmlXPathObjectPtr cur;
7100 double res;
7101
Daniel Veillarda82b1822004-11-08 16:24:57 +00007102 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007103 if (nargs == 0) {
7104 if (ctxt->context->node == NULL) {
7105 valuePush(ctxt, xmlXPathNewFloat(0.0));
7106 } else {
7107 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7108
7109 res = xmlXPathStringEvalNumber(content);
7110 valuePush(ctxt, xmlXPathNewFloat(res));
7111 xmlFree(content);
7112 }
7113 return;
7114 }
7115
7116 CHECK_ARITY(1);
7117 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007118 cur = xmlXPathConvertNumber(cur);
7119 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007120}
7121
7122/**
7123 * xmlXPathSumFunction:
7124 * @ctxt: the XPath Parser context
7125 * @nargs: the number of arguments
7126 *
7127 * Implement the sum() XPath function
7128 * number sum(node-set)
7129 * The sum function returns the sum of the values of the nodes in
7130 * the argument node-set.
7131 */
7132void
7133xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7134 xmlXPathObjectPtr cur;
7135 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007136 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007137
7138 CHECK_ARITY(1);
7139 if ((ctxt->value == NULL) ||
7140 ((ctxt->value->type != XPATH_NODESET) &&
7141 (ctxt->value->type != XPATH_XSLT_TREE)))
7142 XP_ERROR(XPATH_INVALID_TYPE);
7143 cur = valuePop(ctxt);
7144
William M. Brack08171912003-12-29 02:52:11 +00007145 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007146 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7147 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007148 }
7149 }
William M. Brack08171912003-12-29 02:52:11 +00007150 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007151 xmlXPathFreeObject(cur);
7152}
7153
7154/**
7155 * xmlXPathFloorFunction:
7156 * @ctxt: the XPath Parser context
7157 * @nargs: the number of arguments
7158 *
7159 * Implement the floor() XPath function
7160 * number floor(number)
7161 * The floor function returns the largest (closest to positive infinity)
7162 * number that is not greater than the argument and that is an integer.
7163 */
7164void
7165xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007166 double f;
7167
Owen Taylor3473f882001-02-23 17:55:21 +00007168 CHECK_ARITY(1);
7169 CAST_TO_NUMBER;
7170 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007171
7172 f = (double)((int) ctxt->value->floatval);
7173 if (f != ctxt->value->floatval) {
7174 if (ctxt->value->floatval > 0)
7175 ctxt->value->floatval = f;
7176 else
7177 ctxt->value->floatval = f - 1;
7178 }
Owen Taylor3473f882001-02-23 17:55:21 +00007179}
7180
7181/**
7182 * xmlXPathCeilingFunction:
7183 * @ctxt: the XPath Parser context
7184 * @nargs: the number of arguments
7185 *
7186 * Implement the ceiling() XPath function
7187 * number ceiling(number)
7188 * The ceiling function returns the smallest (closest to negative infinity)
7189 * number that is not less than the argument and that is an integer.
7190 */
7191void
7192xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7193 double f;
7194
7195 CHECK_ARITY(1);
7196 CAST_TO_NUMBER;
7197 CHECK_TYPE(XPATH_NUMBER);
7198
7199#if 0
7200 ctxt->value->floatval = ceil(ctxt->value->floatval);
7201#else
7202 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007203 if (f != ctxt->value->floatval) {
7204 if (ctxt->value->floatval > 0)
7205 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007206 else {
7207 if (ctxt->value->floatval < 0 && f == 0)
7208 ctxt->value->floatval = xmlXPathNZERO;
7209 else
7210 ctxt->value->floatval = f;
7211 }
7212
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007213 }
Owen Taylor3473f882001-02-23 17:55:21 +00007214#endif
7215}
7216
7217/**
7218 * xmlXPathRoundFunction:
7219 * @ctxt: the XPath Parser context
7220 * @nargs: the number of arguments
7221 *
7222 * Implement the round() XPath function
7223 * number round(number)
7224 * The round function returns the number that is closest to the
7225 * argument and that is an integer. If there are two such numbers,
7226 * then the one that is even is returned.
7227 */
7228void
7229xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7230 double f;
7231
7232 CHECK_ARITY(1);
7233 CAST_TO_NUMBER;
7234 CHECK_TYPE(XPATH_NUMBER);
7235
Daniel Veillardcda96922001-08-21 10:56:31 +00007236 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7237 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7238 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007239 (ctxt->value->floatval == 0.0))
7240 return;
7241
Owen Taylor3473f882001-02-23 17:55:21 +00007242 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007243 if (ctxt->value->floatval < 0) {
7244 if (ctxt->value->floatval < f - 0.5)
7245 ctxt->value->floatval = f - 1;
7246 else
7247 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007248 if (ctxt->value->floatval == 0)
7249 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007250 } else {
7251 if (ctxt->value->floatval < f + 0.5)
7252 ctxt->value->floatval = f;
7253 else
7254 ctxt->value->floatval = f + 1;
7255 }
Owen Taylor3473f882001-02-23 17:55:21 +00007256}
7257
7258/************************************************************************
7259 * *
7260 * The Parser *
7261 * *
7262 ************************************************************************/
7263
7264/*
William M. Brack08171912003-12-29 02:52:11 +00007265 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007266 * implementation.
7267 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007268static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007269static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007270static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007271static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007272static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7273 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007274
7275/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007276 * xmlXPathCurrentChar:
7277 * @ctxt: the XPath parser context
7278 * @cur: pointer to the beginning of the char
7279 * @len: pointer to the length of the char read
7280 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007281 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007282 * bytes in the input buffer.
7283 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007284 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007285 */
7286
7287static int
7288xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7289 unsigned char c;
7290 unsigned int val;
7291 const xmlChar *cur;
7292
7293 if (ctxt == NULL)
7294 return(0);
7295 cur = ctxt->cur;
7296
7297 /*
7298 * We are supposed to handle UTF8, check it's valid
7299 * From rfc2044: encoding of the Unicode values on UTF-8:
7300 *
7301 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7302 * 0000 0000-0000 007F 0xxxxxxx
7303 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7304 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7305 *
7306 * Check for the 0x110000 limit too
7307 */
7308 c = *cur;
7309 if (c & 0x80) {
7310 if ((cur[1] & 0xc0) != 0x80)
7311 goto encoding_error;
7312 if ((c & 0xe0) == 0xe0) {
7313
7314 if ((cur[2] & 0xc0) != 0x80)
7315 goto encoding_error;
7316 if ((c & 0xf0) == 0xf0) {
7317 if (((c & 0xf8) != 0xf0) ||
7318 ((cur[3] & 0xc0) != 0x80))
7319 goto encoding_error;
7320 /* 4-byte code */
7321 *len = 4;
7322 val = (cur[0] & 0x7) << 18;
7323 val |= (cur[1] & 0x3f) << 12;
7324 val |= (cur[2] & 0x3f) << 6;
7325 val |= cur[3] & 0x3f;
7326 } else {
7327 /* 3-byte code */
7328 *len = 3;
7329 val = (cur[0] & 0xf) << 12;
7330 val |= (cur[1] & 0x3f) << 6;
7331 val |= cur[2] & 0x3f;
7332 }
7333 } else {
7334 /* 2-byte code */
7335 *len = 2;
7336 val = (cur[0] & 0x1f) << 6;
7337 val |= cur[1] & 0x3f;
7338 }
7339 if (!IS_CHAR(val)) {
7340 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7341 }
7342 return(val);
7343 } else {
7344 /* 1-byte code */
7345 *len = 1;
7346 return((int) *cur);
7347 }
7348encoding_error:
7349 /*
William M. Brack08171912003-12-29 02:52:11 +00007350 * If we detect an UTF8 error that probably means that the
7351 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007352 * declaration header. Report the error and switch the encoding
7353 * to ISO-Latin-1 (if you don't like this policy, just declare the
7354 * encoding !)
7355 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007356 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007357 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007358}
7359
7360/**
Owen Taylor3473f882001-02-23 17:55:21 +00007361 * xmlXPathParseNCName:
7362 * @ctxt: the XPath Parser context
7363 *
7364 * parse an XML namespace non qualified name.
7365 *
7366 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7367 *
7368 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7369 * CombiningChar | Extender
7370 *
7371 * Returns the namespace name or NULL
7372 */
7373
7374xmlChar *
7375xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007376 const xmlChar *in;
7377 xmlChar *ret;
7378 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007379
Daniel Veillarda82b1822004-11-08 16:24:57 +00007380 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007381 /*
7382 * Accelerator for simple ASCII names
7383 */
7384 in = ctxt->cur;
7385 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7386 ((*in >= 0x41) && (*in <= 0x5A)) ||
7387 (*in == '_')) {
7388 in++;
7389 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7390 ((*in >= 0x41) && (*in <= 0x5A)) ||
7391 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007392 (*in == '_') || (*in == '.') ||
7393 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007394 in++;
7395 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7396 (*in == '[') || (*in == ']') || (*in == ':') ||
7397 (*in == '@') || (*in == '*')) {
7398 count = in - ctxt->cur;
7399 if (count == 0)
7400 return(NULL);
7401 ret = xmlStrndup(ctxt->cur, count);
7402 ctxt->cur = in;
7403 return(ret);
7404 }
7405 }
7406 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007407}
7408
Daniel Veillard2156a562001-04-28 12:24:34 +00007409
Owen Taylor3473f882001-02-23 17:55:21 +00007410/**
7411 * xmlXPathParseQName:
7412 * @ctxt: the XPath Parser context
7413 * @prefix: a xmlChar **
7414 *
7415 * parse an XML qualified name
7416 *
7417 * [NS 5] QName ::= (Prefix ':')? LocalPart
7418 *
7419 * [NS 6] Prefix ::= NCName
7420 *
7421 * [NS 7] LocalPart ::= NCName
7422 *
7423 * Returns the function returns the local part, and prefix is updated
7424 * to get the Prefix if any.
7425 */
7426
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007427static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007428xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7429 xmlChar *ret = NULL;
7430
7431 *prefix = NULL;
7432 ret = xmlXPathParseNCName(ctxt);
7433 if (CUR == ':') {
7434 *prefix = ret;
7435 NEXT;
7436 ret = xmlXPathParseNCName(ctxt);
7437 }
7438 return(ret);
7439}
7440
7441/**
7442 * xmlXPathParseName:
7443 * @ctxt: the XPath Parser context
7444 *
7445 * parse an XML name
7446 *
7447 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7448 * CombiningChar | Extender
7449 *
7450 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7451 *
7452 * Returns the namespace name or NULL
7453 */
7454
7455xmlChar *
7456xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007457 const xmlChar *in;
7458 xmlChar *ret;
7459 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007460
Daniel Veillarda82b1822004-11-08 16:24:57 +00007461 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007462 /*
7463 * Accelerator for simple ASCII names
7464 */
7465 in = ctxt->cur;
7466 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7467 ((*in >= 0x41) && (*in <= 0x5A)) ||
7468 (*in == '_') || (*in == ':')) {
7469 in++;
7470 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7471 ((*in >= 0x41) && (*in <= 0x5A)) ||
7472 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007473 (*in == '_') || (*in == '-') ||
7474 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007475 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007476 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007477 count = in - ctxt->cur;
7478 ret = xmlStrndup(ctxt->cur, count);
7479 ctxt->cur = in;
7480 return(ret);
7481 }
7482 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007483 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007484}
7485
Daniel Veillard61d80a22001-04-27 17:13:01 +00007486static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007487xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007488 xmlChar buf[XML_MAX_NAMELEN + 5];
7489 int len = 0, l;
7490 int c;
7491
7492 /*
7493 * Handler for more complex cases
7494 */
7495 c = CUR_CHAR(l);
7496 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007497 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7498 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007499 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007500 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007501 return(NULL);
7502 }
7503
7504 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7505 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7506 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007507 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007508 (IS_COMBINING(c)) ||
7509 (IS_EXTENDER(c)))) {
7510 COPY_BUF(l,buf,len,c);
7511 NEXTL(l);
7512 c = CUR_CHAR(l);
7513 if (len >= XML_MAX_NAMELEN) {
7514 /*
7515 * Okay someone managed to make a huge name, so he's ready to pay
7516 * for the processing speed.
7517 */
7518 xmlChar *buffer;
7519 int max = len * 2;
7520
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007521 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007522 if (buffer == NULL) {
7523 XP_ERROR0(XPATH_MEMORY_ERROR);
7524 }
7525 memcpy(buffer, buf, len);
7526 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7527 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007528 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007529 (IS_COMBINING(c)) ||
7530 (IS_EXTENDER(c))) {
7531 if (len + 10 > max) {
7532 max *= 2;
7533 buffer = (xmlChar *) xmlRealloc(buffer,
7534 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007535 if (buffer == NULL) {
7536 XP_ERROR0(XPATH_MEMORY_ERROR);
7537 }
7538 }
7539 COPY_BUF(l,buffer,len,c);
7540 NEXTL(l);
7541 c = CUR_CHAR(l);
7542 }
7543 buffer[len] = 0;
7544 return(buffer);
7545 }
7546 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007547 if (len == 0)
7548 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007549 return(xmlStrndup(buf, len));
7550}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007551
7552#define MAX_FRAC 20
7553
William M. Brack372a4452004-02-17 13:09:23 +00007554/*
7555 * These are used as divisors for the fractional part of a number.
7556 * Since the table includes 1.0 (representing '0' fractional digits),
7557 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7558 */
7559static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007560 1.0, 10.0, 100.0, 1000.0, 10000.0,
7561 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7562 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7563 100000000000000.0,
7564 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007565 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007566};
7567
Owen Taylor3473f882001-02-23 17:55:21 +00007568/**
7569 * xmlXPathStringEvalNumber:
7570 * @str: A string to scan
7571 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007572 * [30a] Float ::= Number ('e' Digits?)?
7573 *
Owen Taylor3473f882001-02-23 17:55:21 +00007574 * [30] Number ::= Digits ('.' Digits?)?
7575 * | '.' Digits
7576 * [31] Digits ::= [0-9]+
7577 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007578 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007579 * In complement of the Number expression, this function also handles
7580 * negative values : '-' Number.
7581 *
7582 * Returns the double value.
7583 */
7584double
7585xmlXPathStringEvalNumber(const xmlChar *str) {
7586 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007587 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007588 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007589 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007590 int exponent = 0;
7591 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007592#ifdef __GNUC__
7593 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007594 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007595#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007596 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007597 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007598 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7599 return(xmlXPathNAN);
7600 }
7601 if (*cur == '-') {
7602 isneg = 1;
7603 cur++;
7604 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007605
7606#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007607 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007608 * tmp/temp is a workaround against a gcc compiler bug
7609 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007610 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007611 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007612 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007613 ret = ret * 10;
7614 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007615 ok = 1;
7616 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007617 temp = (double) tmp;
7618 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007619 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007620#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007621 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007622 while ((*cur >= '0') && (*cur <= '9')) {
7623 ret = ret * 10 + (*cur - '0');
7624 ok = 1;
7625 cur++;
7626 }
7627#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007628
Owen Taylor3473f882001-02-23 17:55:21 +00007629 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007630 int v, frac = 0;
7631 double fraction = 0;
7632
Owen Taylor3473f882001-02-23 17:55:21 +00007633 cur++;
7634 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7635 return(xmlXPathNAN);
7636 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007637 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7638 v = (*cur - '0');
7639 fraction = fraction * 10 + v;
7640 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007641 cur++;
7642 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007643 fraction /= my_pow10[frac];
7644 ret = ret + fraction;
7645 while ((*cur >= '0') && (*cur <= '9'))
7646 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007647 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007648 if ((*cur == 'e') || (*cur == 'E')) {
7649 cur++;
7650 if (*cur == '-') {
7651 is_exponent_negative = 1;
7652 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007653 } else if (*cur == '+') {
7654 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007655 }
7656 while ((*cur >= '0') && (*cur <= '9')) {
7657 exponent = exponent * 10 + (*cur - '0');
7658 cur++;
7659 }
7660 }
William M. Brack76e95df2003-10-18 16:20:14 +00007661 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007662 if (*cur != 0) return(xmlXPathNAN);
7663 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007664 if (is_exponent_negative) exponent = -exponent;
7665 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007666 return(ret);
7667}
7668
7669/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007670 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007671 * @ctxt: the XPath Parser context
7672 *
7673 * [30] Number ::= Digits ('.' Digits?)?
7674 * | '.' Digits
7675 * [31] Digits ::= [0-9]+
7676 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007677 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007678 *
7679 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007680static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007681xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7682{
Owen Taylor3473f882001-02-23 17:55:21 +00007683 double ret = 0.0;
7684 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007685 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007686 int exponent = 0;
7687 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007688#ifdef __GNUC__
7689 unsigned long tmp = 0;
7690 double temp;
7691#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007692
7693 CHECK_ERROR;
7694 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7695 XP_ERROR(XPATH_NUMBER_ERROR);
7696 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007697#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007698 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007699 * tmp/temp is a workaround against a gcc compiler bug
7700 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007701 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007702 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007703 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007704 ret = ret * 10;
7705 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007706 ok = 1;
7707 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007708 temp = (double) tmp;
7709 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007710 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007711#else
7712 ret = 0;
7713 while ((CUR >= '0') && (CUR <= '9')) {
7714 ret = ret * 10 + (CUR - '0');
7715 ok = 1;
7716 NEXT;
7717 }
7718#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007719 if (CUR == '.') {
7720 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007721 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7722 XP_ERROR(XPATH_NUMBER_ERROR);
7723 }
7724 while ((CUR >= '0') && (CUR <= '9')) {
7725 mult /= 10;
7726 ret = ret + (CUR - '0') * mult;
7727 NEXT;
7728 }
Owen Taylor3473f882001-02-23 17:55:21 +00007729 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007730 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007731 NEXT;
7732 if (CUR == '-') {
7733 is_exponent_negative = 1;
7734 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007735 } else if (CUR == '+') {
7736 NEXT;
7737 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007738 while ((CUR >= '0') && (CUR <= '9')) {
7739 exponent = exponent * 10 + (CUR - '0');
7740 NEXT;
7741 }
7742 if (is_exponent_negative)
7743 exponent = -exponent;
7744 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007745 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007746 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007747 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007748}
7749
7750/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007751 * xmlXPathParseLiteral:
7752 * @ctxt: the XPath Parser context
7753 *
7754 * Parse a Literal
7755 *
7756 * [29] Literal ::= '"' [^"]* '"'
7757 * | "'" [^']* "'"
7758 *
7759 * Returns the value found or NULL in case of error
7760 */
7761static xmlChar *
7762xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7763 const xmlChar *q;
7764 xmlChar *ret = NULL;
7765
7766 if (CUR == '"') {
7767 NEXT;
7768 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007769 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007770 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007771 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007772 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7773 } else {
7774 ret = xmlStrndup(q, CUR_PTR - q);
7775 NEXT;
7776 }
7777 } else if (CUR == '\'') {
7778 NEXT;
7779 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007780 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007781 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007782 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007783 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7784 } else {
7785 ret = xmlStrndup(q, CUR_PTR - q);
7786 NEXT;
7787 }
7788 } else {
7789 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7790 }
7791 return(ret);
7792}
7793
7794/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007795 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007796 * @ctxt: the XPath Parser context
7797 *
7798 * Parse a Literal and push it on the stack.
7799 *
7800 * [29] Literal ::= '"' [^"]* '"'
7801 * | "'" [^']* "'"
7802 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007803 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007804 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007805static void
7806xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007807 const xmlChar *q;
7808 xmlChar *ret = NULL;
7809
7810 if (CUR == '"') {
7811 NEXT;
7812 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007813 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007814 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007815 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007816 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7817 } else {
7818 ret = xmlStrndup(q, CUR_PTR - q);
7819 NEXT;
7820 }
7821 } else if (CUR == '\'') {
7822 NEXT;
7823 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007824 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007825 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007826 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007827 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7828 } else {
7829 ret = xmlStrndup(q, CUR_PTR - q);
7830 NEXT;
7831 }
7832 } else {
7833 XP_ERROR(XPATH_START_LITERAL_ERROR);
7834 }
7835 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007836 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7837 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007838 xmlFree(ret);
7839}
7840
7841/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007842 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007843 * @ctxt: the XPath Parser context
7844 *
7845 * Parse a VariableReference, evaluate it and push it on the stack.
7846 *
7847 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007848 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007849 * of any of the types that are possible for the value of an expression,
7850 * and may also be of additional types not specified here.
7851 *
7852 * Early evaluation is possible since:
7853 * The variable bindings [...] used to evaluate a subexpression are
7854 * always the same as those used to evaluate the containing expression.
7855 *
7856 * [36] VariableReference ::= '$' QName
7857 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007858static void
7859xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007860 xmlChar *name;
7861 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007862
7863 SKIP_BLANKS;
7864 if (CUR != '$') {
7865 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7866 }
7867 NEXT;
7868 name = xmlXPathParseQName(ctxt, &prefix);
7869 if (name == NULL) {
7870 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7871 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007872 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007873 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7874 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007875 SKIP_BLANKS;
7876}
7877
7878/**
7879 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007880 * @name: a name string
7881 *
7882 * Is the name given a NodeType one.
7883 *
7884 * [38] NodeType ::= 'comment'
7885 * | 'text'
7886 * | 'processing-instruction'
7887 * | 'node'
7888 *
7889 * Returns 1 if true 0 otherwise
7890 */
7891int
7892xmlXPathIsNodeType(const xmlChar *name) {
7893 if (name == NULL)
7894 return(0);
7895
Daniel Veillard1971ee22002-01-31 20:29:19 +00007896 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007897 return(1);
7898 if (xmlStrEqual(name, BAD_CAST "text"))
7899 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007900 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007901 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007902 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007903 return(1);
7904 return(0);
7905}
7906
7907/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007908 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007909 * @ctxt: the XPath Parser context
7910 *
7911 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7912 * [17] Argument ::= Expr
7913 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007914 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007915 * pushed on the stack
7916 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007917static void
7918xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007919 xmlChar *name;
7920 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007921 int nbargs = 0;
7922
7923 name = xmlXPathParseQName(ctxt, &prefix);
7924 if (name == NULL) {
7925 XP_ERROR(XPATH_EXPR_ERROR);
7926 }
7927 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007928#ifdef DEBUG_EXPR
7929 if (prefix == NULL)
7930 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7931 name);
7932 else
7933 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7934 prefix, name);
7935#endif
7936
Owen Taylor3473f882001-02-23 17:55:21 +00007937 if (CUR != '(') {
7938 XP_ERROR(XPATH_EXPR_ERROR);
7939 }
7940 NEXT;
7941 SKIP_BLANKS;
7942
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007943 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007944 if (CUR != ')') {
7945 while (CUR != 0) {
7946 int op1 = ctxt->comp->last;
7947 ctxt->comp->last = -1;
7948 xmlXPathCompileExpr(ctxt);
7949 CHECK_ERROR;
7950 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7951 nbargs++;
7952 if (CUR == ')') break;
7953 if (CUR != ',') {
7954 XP_ERROR(XPATH_EXPR_ERROR);
7955 }
7956 NEXT;
7957 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007958 }
Owen Taylor3473f882001-02-23 17:55:21 +00007959 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007960 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7961 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007962 NEXT;
7963 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007964}
7965
7966/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007967 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007968 * @ctxt: the XPath Parser context
7969 *
7970 * [15] PrimaryExpr ::= VariableReference
7971 * | '(' Expr ')'
7972 * | Literal
7973 * | Number
7974 * | FunctionCall
7975 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007976 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007977 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007978static void
7979xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007980 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007981 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007982 else if (CUR == '(') {
7983 NEXT;
7984 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007985 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007986 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007987 if (CUR != ')') {
7988 XP_ERROR(XPATH_EXPR_ERROR);
7989 }
7990 NEXT;
7991 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00007992 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007993 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007994 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007995 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007996 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007997 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007998 }
7999 SKIP_BLANKS;
8000}
8001
8002/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008003 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008004 * @ctxt: the XPath Parser context
8005 *
8006 * [20] FilterExpr ::= PrimaryExpr
8007 * | FilterExpr Predicate
8008 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008009 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008010 * Square brackets are used to filter expressions in the same way that
8011 * they are used in location paths. It is an error if the expression to
8012 * be filtered does not evaluate to a node-set. The context node list
8013 * used for evaluating the expression in square brackets is the node-set
8014 * to be filtered listed in document order.
8015 */
8016
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008017static void
8018xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8019 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008020 CHECK_ERROR;
8021 SKIP_BLANKS;
8022
8023 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008024 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008025 SKIP_BLANKS;
8026 }
8027
8028
8029}
8030
8031/**
8032 * xmlXPathScanName:
8033 * @ctxt: the XPath Parser context
8034 *
8035 * Trickery: parse an XML name but without consuming the input flow
8036 * Needed to avoid insanity in the parser state.
8037 *
8038 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8039 * CombiningChar | Extender
8040 *
8041 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8042 *
8043 * [6] Names ::= Name (S Name)*
8044 *
8045 * Returns the Name parsed or NULL
8046 */
8047
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008048static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008049xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008050 int len = 0, l;
8051 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008052 const xmlChar *cur;
8053 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008054
Daniel Veillard03226812004-11-01 14:55:21 +00008055 cur = ctxt->cur;
8056
8057 c = CUR_CHAR(l);
8058 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8059 (!IS_LETTER(c) && (c != '_') &&
8060 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008061 return(NULL);
8062 }
8063
Daniel Veillard03226812004-11-01 14:55:21 +00008064 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8065 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8066 (c == '.') || (c == '-') ||
8067 (c == '_') || (c == ':') ||
8068 (IS_COMBINING(c)) ||
8069 (IS_EXTENDER(c)))) {
8070 len += l;
8071 NEXTL(l);
8072 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008073 }
Daniel Veillard03226812004-11-01 14:55:21 +00008074 ret = xmlStrndup(cur, ctxt->cur - cur);
8075 ctxt->cur = cur;
8076 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008077}
8078
8079/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008080 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008081 * @ctxt: the XPath Parser context
8082 *
8083 * [19] PathExpr ::= LocationPath
8084 * | FilterExpr
8085 * | FilterExpr '/' RelativeLocationPath
8086 * | FilterExpr '//' RelativeLocationPath
8087 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008088 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008089 * The / operator and // operators combine an arbitrary expression
8090 * and a relative location path. It is an error if the expression
8091 * does not evaluate to a node-set.
8092 * The / operator does composition in the same way as when / is
8093 * used in a location path. As in location paths, // is short for
8094 * /descendant-or-self::node()/.
8095 */
8096
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008097static void
8098xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008099 int lc = 1; /* Should we branch to LocationPath ? */
8100 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8101
8102 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008103 if ((CUR == '$') || (CUR == '(') ||
8104 (IS_ASCII_DIGIT(CUR)) ||
8105 (CUR == '\'') || (CUR == '"') ||
8106 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008107 lc = 0;
8108 } else if (CUR == '*') {
8109 /* relative or absolute location path */
8110 lc = 1;
8111 } else if (CUR == '/') {
8112 /* relative or absolute location path */
8113 lc = 1;
8114 } else if (CUR == '@') {
8115 /* relative abbreviated attribute location path */
8116 lc = 1;
8117 } else if (CUR == '.') {
8118 /* relative abbreviated attribute location path */
8119 lc = 1;
8120 } else {
8121 /*
8122 * Problem is finding if we have a name here whether it's:
8123 * - a nodetype
8124 * - a function call in which case it's followed by '('
8125 * - an axis in which case it's followed by ':'
8126 * - a element name
8127 * We do an a priori analysis here rather than having to
8128 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008129 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008130 * read/write/debug.
8131 */
8132 SKIP_BLANKS;
8133 name = xmlXPathScanName(ctxt);
8134 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8135#ifdef DEBUG_STEP
8136 xmlGenericError(xmlGenericErrorContext,
8137 "PathExpr: Axis\n");
8138#endif
8139 lc = 1;
8140 xmlFree(name);
8141 } else if (name != NULL) {
8142 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008143
8144
8145 while (NXT(len) != 0) {
8146 if (NXT(len) == '/') {
8147 /* element name */
8148#ifdef DEBUG_STEP
8149 xmlGenericError(xmlGenericErrorContext,
8150 "PathExpr: AbbrRelLocation\n");
8151#endif
8152 lc = 1;
8153 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008154 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008155 /* ignore blanks */
8156 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008157 } else if (NXT(len) == ':') {
8158#ifdef DEBUG_STEP
8159 xmlGenericError(xmlGenericErrorContext,
8160 "PathExpr: AbbrRelLocation\n");
8161#endif
8162 lc = 1;
8163 break;
8164 } else if ((NXT(len) == '(')) {
8165 /* Note Type or Function */
8166 if (xmlXPathIsNodeType(name)) {
8167#ifdef DEBUG_STEP
8168 xmlGenericError(xmlGenericErrorContext,
8169 "PathExpr: Type search\n");
8170#endif
8171 lc = 1;
8172 } else {
8173#ifdef DEBUG_STEP
8174 xmlGenericError(xmlGenericErrorContext,
8175 "PathExpr: function call\n");
8176#endif
8177 lc = 0;
8178 }
8179 break;
8180 } else if ((NXT(len) == '[')) {
8181 /* element name */
8182#ifdef DEBUG_STEP
8183 xmlGenericError(xmlGenericErrorContext,
8184 "PathExpr: AbbrRelLocation\n");
8185#endif
8186 lc = 1;
8187 break;
8188 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8189 (NXT(len) == '=')) {
8190 lc = 1;
8191 break;
8192 } else {
8193 lc = 1;
8194 break;
8195 }
8196 len++;
8197 }
8198 if (NXT(len) == 0) {
8199#ifdef DEBUG_STEP
8200 xmlGenericError(xmlGenericErrorContext,
8201 "PathExpr: AbbrRelLocation\n");
8202#endif
8203 /* element name */
8204 lc = 1;
8205 }
8206 xmlFree(name);
8207 } else {
William M. Brack08171912003-12-29 02:52:11 +00008208 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008209 XP_ERROR(XPATH_EXPR_ERROR);
8210 }
8211 }
8212
8213 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008214 if (CUR == '/') {
8215 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8216 } else {
8217 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008218 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008219 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008220 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008221 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008222 CHECK_ERROR;
8223 if ((CUR == '/') && (NXT(1) == '/')) {
8224 SKIP(2);
8225 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008226
8227 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8228 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8229 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8230
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008231 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008232 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008233 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008234 }
8235 }
8236 SKIP_BLANKS;
8237}
8238
8239/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008240 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008241 * @ctxt: the XPath Parser context
8242 *
8243 * [18] UnionExpr ::= PathExpr
8244 * | UnionExpr '|' PathExpr
8245 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008246 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008247 */
8248
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008249static void
8250xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8251 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008252 CHECK_ERROR;
8253 SKIP_BLANKS;
8254 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008255 int op1 = ctxt->comp->last;
8256 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008257
8258 NEXT;
8259 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008260 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008261
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008262 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8263
Owen Taylor3473f882001-02-23 17:55:21 +00008264 SKIP_BLANKS;
8265 }
Owen Taylor3473f882001-02-23 17:55:21 +00008266}
8267
8268/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008269 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008270 * @ctxt: the XPath Parser context
8271 *
8272 * [27] UnaryExpr ::= UnionExpr
8273 * | '-' UnaryExpr
8274 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008275 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008276 */
8277
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008278static void
8279xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008280 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008281 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008282
8283 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008284 while (CUR == '-') {
8285 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008286 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008287 NEXT;
8288 SKIP_BLANKS;
8289 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008290
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008291 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008292 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008293 if (found) {
8294 if (minus)
8295 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8296 else
8297 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008298 }
8299}
8300
8301/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008302 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008303 * @ctxt: the XPath Parser context
8304 *
8305 * [26] MultiplicativeExpr ::= UnaryExpr
8306 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8307 * | MultiplicativeExpr 'div' UnaryExpr
8308 * | MultiplicativeExpr 'mod' UnaryExpr
8309 * [34] MultiplyOperator ::= '*'
8310 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008311 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008312 */
8313
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008314static void
8315xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8316 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008317 CHECK_ERROR;
8318 SKIP_BLANKS;
8319 while ((CUR == '*') ||
8320 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8321 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8322 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008323 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008324
8325 if (CUR == '*') {
8326 op = 0;
8327 NEXT;
8328 } else if (CUR == 'd') {
8329 op = 1;
8330 SKIP(3);
8331 } else if (CUR == 'm') {
8332 op = 2;
8333 SKIP(3);
8334 }
8335 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008336 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008337 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008338 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008339 SKIP_BLANKS;
8340 }
8341}
8342
8343/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008344 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008345 * @ctxt: the XPath Parser context
8346 *
8347 * [25] AdditiveExpr ::= MultiplicativeExpr
8348 * | AdditiveExpr '+' MultiplicativeExpr
8349 * | AdditiveExpr '-' MultiplicativeExpr
8350 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008351 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008352 */
8353
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008354static void
8355xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008356
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008357 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008358 CHECK_ERROR;
8359 SKIP_BLANKS;
8360 while ((CUR == '+') || (CUR == '-')) {
8361 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008362 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008363
8364 if (CUR == '+') plus = 1;
8365 else plus = 0;
8366 NEXT;
8367 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008368 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008369 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008370 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008371 SKIP_BLANKS;
8372 }
8373}
8374
8375/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008376 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008377 * @ctxt: the XPath Parser context
8378 *
8379 * [24] RelationalExpr ::= AdditiveExpr
8380 * | RelationalExpr '<' AdditiveExpr
8381 * | RelationalExpr '>' AdditiveExpr
8382 * | RelationalExpr '<=' AdditiveExpr
8383 * | RelationalExpr '>=' AdditiveExpr
8384 *
8385 * A <= B > C is allowed ? Answer from James, yes with
8386 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8387 * which is basically what got implemented.
8388 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008389 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008390 * on the stack
8391 */
8392
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008393static void
8394xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8395 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008396 CHECK_ERROR;
8397 SKIP_BLANKS;
8398 while ((CUR == '<') ||
8399 (CUR == '>') ||
8400 ((CUR == '<') && (NXT(1) == '=')) ||
8401 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008402 int inf, strict;
8403 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008404
8405 if (CUR == '<') inf = 1;
8406 else inf = 0;
8407 if (NXT(1) == '=') strict = 0;
8408 else strict = 1;
8409 NEXT;
8410 if (!strict) NEXT;
8411 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008412 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008413 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008414 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008415 SKIP_BLANKS;
8416 }
8417}
8418
8419/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008420 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008421 * @ctxt: the XPath Parser context
8422 *
8423 * [23] EqualityExpr ::= RelationalExpr
8424 * | EqualityExpr '=' RelationalExpr
8425 * | EqualityExpr '!=' RelationalExpr
8426 *
8427 * A != B != C is allowed ? Answer from James, yes with
8428 * (RelationalExpr = RelationalExpr) = RelationalExpr
8429 * (RelationalExpr != RelationalExpr) != RelationalExpr
8430 * which is basically what got implemented.
8431 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008432 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008433 *
8434 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008435static void
8436xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8437 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008438 CHECK_ERROR;
8439 SKIP_BLANKS;
8440 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008441 int eq;
8442 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008443
8444 if (CUR == '=') eq = 1;
8445 else eq = 0;
8446 NEXT;
8447 if (!eq) NEXT;
8448 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008449 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008450 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008451 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008452 SKIP_BLANKS;
8453 }
8454}
8455
8456/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008457 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008458 * @ctxt: the XPath Parser context
8459 *
8460 * [22] AndExpr ::= EqualityExpr
8461 * | AndExpr 'and' EqualityExpr
8462 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008463 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008464 *
8465 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008466static void
8467xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8468 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008469 CHECK_ERROR;
8470 SKIP_BLANKS;
8471 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008472 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008473 SKIP(3);
8474 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008475 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008476 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008477 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008478 SKIP_BLANKS;
8479 }
8480}
8481
8482/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008483 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008484 * @ctxt: the XPath Parser context
8485 *
8486 * [14] Expr ::= OrExpr
8487 * [21] OrExpr ::= AndExpr
8488 * | OrExpr 'or' AndExpr
8489 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008490 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008491 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008492static void
8493xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8494 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008495 CHECK_ERROR;
8496 SKIP_BLANKS;
8497 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008498 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008499 SKIP(2);
8500 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008501 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008502 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008503 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8504 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008505 SKIP_BLANKS;
8506 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008507 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8508 /* more ops could be optimized too */
8509 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8510 }
Owen Taylor3473f882001-02-23 17:55:21 +00008511}
8512
8513/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008514 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008515 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008516 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008517 *
8518 * [8] Predicate ::= '[' PredicateExpr ']'
8519 * [9] PredicateExpr ::= Expr
8520 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008521 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008522 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008523static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008524xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008525 int op1 = ctxt->comp->last;
8526
8527 SKIP_BLANKS;
8528 if (CUR != '[') {
8529 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8530 }
8531 NEXT;
8532 SKIP_BLANKS;
8533
8534 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008535 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008536 CHECK_ERROR;
8537
8538 if (CUR != ']') {
8539 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8540 }
8541
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008542 if (filter)
8543 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8544 else
8545 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008546
8547 NEXT;
8548 SKIP_BLANKS;
8549}
8550
8551/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008552 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008553 * @ctxt: the XPath Parser context
8554 * @test: pointer to a xmlXPathTestVal
8555 * @type: pointer to a xmlXPathTypeVal
8556 * @prefix: placeholder for a possible name prefix
8557 *
8558 * [7] NodeTest ::= NameTest
8559 * | NodeType '(' ')'
8560 * | 'processing-instruction' '(' Literal ')'
8561 *
8562 * [37] NameTest ::= '*'
8563 * | NCName ':' '*'
8564 * | QName
8565 * [38] NodeType ::= 'comment'
8566 * | 'text'
8567 * | 'processing-instruction'
8568 * | 'node'
8569 *
William M. Brack08171912003-12-29 02:52:11 +00008570 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008571 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008572static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008573xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8574 xmlXPathTypeVal *type, const xmlChar **prefix,
8575 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008576 int blanks;
8577
8578 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8579 STRANGE;
8580 return(NULL);
8581 }
William M. Brack78637da2003-07-31 14:47:38 +00008582 *type = (xmlXPathTypeVal) 0;
8583 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008584 *prefix = NULL;
8585 SKIP_BLANKS;
8586
8587 if ((name == NULL) && (CUR == '*')) {
8588 /*
8589 * All elements
8590 */
8591 NEXT;
8592 *test = NODE_TEST_ALL;
8593 return(NULL);
8594 }
8595
8596 if (name == NULL)
8597 name = xmlXPathParseNCName(ctxt);
8598 if (name == NULL) {
8599 XP_ERROR0(XPATH_EXPR_ERROR);
8600 }
8601
William M. Brack76e95df2003-10-18 16:20:14 +00008602 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008603 SKIP_BLANKS;
8604 if (CUR == '(') {
8605 NEXT;
8606 /*
8607 * NodeType or PI search
8608 */
8609 if (xmlStrEqual(name, BAD_CAST "comment"))
8610 *type = NODE_TYPE_COMMENT;
8611 else if (xmlStrEqual(name, BAD_CAST "node"))
8612 *type = NODE_TYPE_NODE;
8613 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8614 *type = NODE_TYPE_PI;
8615 else if (xmlStrEqual(name, BAD_CAST "text"))
8616 *type = NODE_TYPE_TEXT;
8617 else {
8618 if (name != NULL)
8619 xmlFree(name);
8620 XP_ERROR0(XPATH_EXPR_ERROR);
8621 }
8622
8623 *test = NODE_TEST_TYPE;
8624
8625 SKIP_BLANKS;
8626 if (*type == NODE_TYPE_PI) {
8627 /*
8628 * Specific case: search a PI by name.
8629 */
Owen Taylor3473f882001-02-23 17:55:21 +00008630 if (name != NULL)
8631 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008632 name = NULL;
8633 if (CUR != ')') {
8634 name = xmlXPathParseLiteral(ctxt);
8635 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008636 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008637 SKIP_BLANKS;
8638 }
Owen Taylor3473f882001-02-23 17:55:21 +00008639 }
8640 if (CUR != ')') {
8641 if (name != NULL)
8642 xmlFree(name);
8643 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8644 }
8645 NEXT;
8646 return(name);
8647 }
8648 *test = NODE_TEST_NAME;
8649 if ((!blanks) && (CUR == ':')) {
8650 NEXT;
8651
8652 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008653 * Since currently the parser context don't have a
8654 * namespace list associated:
8655 * The namespace name for this prefix can be computed
8656 * only at evaluation time. The compilation is done
8657 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008658 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008659#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008660 *prefix = xmlXPathNsLookup(ctxt->context, name);
8661 if (name != NULL)
8662 xmlFree(name);
8663 if (*prefix == NULL) {
8664 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8665 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008666#else
8667 *prefix = name;
8668#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008669
8670 if (CUR == '*') {
8671 /*
8672 * All elements
8673 */
8674 NEXT;
8675 *test = NODE_TEST_ALL;
8676 return(NULL);
8677 }
8678
8679 name = xmlXPathParseNCName(ctxt);
8680 if (name == NULL) {
8681 XP_ERROR0(XPATH_EXPR_ERROR);
8682 }
8683 }
8684 return(name);
8685}
8686
8687/**
8688 * xmlXPathIsAxisName:
8689 * @name: a preparsed name token
8690 *
8691 * [6] AxisName ::= 'ancestor'
8692 * | 'ancestor-or-self'
8693 * | 'attribute'
8694 * | 'child'
8695 * | 'descendant'
8696 * | 'descendant-or-self'
8697 * | 'following'
8698 * | 'following-sibling'
8699 * | 'namespace'
8700 * | 'parent'
8701 * | 'preceding'
8702 * | 'preceding-sibling'
8703 * | 'self'
8704 *
8705 * Returns the axis or 0
8706 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008707static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008708xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008709 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008710 switch (name[0]) {
8711 case 'a':
8712 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8713 ret = AXIS_ANCESTOR;
8714 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8715 ret = AXIS_ANCESTOR_OR_SELF;
8716 if (xmlStrEqual(name, BAD_CAST "attribute"))
8717 ret = AXIS_ATTRIBUTE;
8718 break;
8719 case 'c':
8720 if (xmlStrEqual(name, BAD_CAST "child"))
8721 ret = AXIS_CHILD;
8722 break;
8723 case 'd':
8724 if (xmlStrEqual(name, BAD_CAST "descendant"))
8725 ret = AXIS_DESCENDANT;
8726 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8727 ret = AXIS_DESCENDANT_OR_SELF;
8728 break;
8729 case 'f':
8730 if (xmlStrEqual(name, BAD_CAST "following"))
8731 ret = AXIS_FOLLOWING;
8732 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8733 ret = AXIS_FOLLOWING_SIBLING;
8734 break;
8735 case 'n':
8736 if (xmlStrEqual(name, BAD_CAST "namespace"))
8737 ret = AXIS_NAMESPACE;
8738 break;
8739 case 'p':
8740 if (xmlStrEqual(name, BAD_CAST "parent"))
8741 ret = AXIS_PARENT;
8742 if (xmlStrEqual(name, BAD_CAST "preceding"))
8743 ret = AXIS_PRECEDING;
8744 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8745 ret = AXIS_PRECEDING_SIBLING;
8746 break;
8747 case 's':
8748 if (xmlStrEqual(name, BAD_CAST "self"))
8749 ret = AXIS_SELF;
8750 break;
8751 }
8752 return(ret);
8753}
8754
8755/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008756 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008757 * @ctxt: the XPath Parser context
8758 *
8759 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8760 * | AbbreviatedStep
8761 *
8762 * [12] AbbreviatedStep ::= '.' | '..'
8763 *
8764 * [5] AxisSpecifier ::= AxisName '::'
8765 * | AbbreviatedAxisSpecifier
8766 *
8767 * [13] AbbreviatedAxisSpecifier ::= '@'?
8768 *
8769 * Modified for XPtr range support as:
8770 *
8771 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8772 * | AbbreviatedStep
8773 * | 'range-to' '(' Expr ')' Predicate*
8774 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008775 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008776 * A location step of . is short for self::node(). This is
8777 * particularly useful in conjunction with //. For example, the
8778 * location path .//para is short for
8779 * self::node()/descendant-or-self::node()/child::para
8780 * and so will select all para descendant elements of the context
8781 * node.
8782 * Similarly, a location step of .. is short for parent::node().
8783 * For example, ../title is short for parent::node()/child::title
8784 * and so will select the title children of the parent of the context
8785 * node.
8786 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008787static void
8788xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008789#ifdef LIBXML_XPTR_ENABLED
8790 int rangeto = 0;
8791 int op2 = -1;
8792#endif
8793
Owen Taylor3473f882001-02-23 17:55:21 +00008794 SKIP_BLANKS;
8795 if ((CUR == '.') && (NXT(1) == '.')) {
8796 SKIP(2);
8797 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008798 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8799 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008800 } else if (CUR == '.') {
8801 NEXT;
8802 SKIP_BLANKS;
8803 } else {
8804 xmlChar *name = NULL;
8805 const xmlChar *prefix = NULL;
8806 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008807 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008808 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008809 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008810
8811 /*
8812 * The modification needed for XPointer change to the production
8813 */
8814#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008815 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008816 name = xmlXPathParseNCName(ctxt);
8817 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008818 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008819 xmlFree(name);
8820 SKIP_BLANKS;
8821 if (CUR != '(') {
8822 XP_ERROR(XPATH_EXPR_ERROR);
8823 }
8824 NEXT;
8825 SKIP_BLANKS;
8826
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008827 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008828 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008829 CHECK_ERROR;
8830
8831 SKIP_BLANKS;
8832 if (CUR != ')') {
8833 XP_ERROR(XPATH_EXPR_ERROR);
8834 }
8835 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008836 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008837 goto eval_predicates;
8838 }
8839 }
8840#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008841 if (CUR == '*') {
8842 axis = AXIS_CHILD;
8843 } else {
8844 if (name == NULL)
8845 name = xmlXPathParseNCName(ctxt);
8846 if (name != NULL) {
8847 axis = xmlXPathIsAxisName(name);
8848 if (axis != 0) {
8849 SKIP_BLANKS;
8850 if ((CUR == ':') && (NXT(1) == ':')) {
8851 SKIP(2);
8852 xmlFree(name);
8853 name = NULL;
8854 } else {
8855 /* an element name can conflict with an axis one :-\ */
8856 axis = AXIS_CHILD;
8857 }
Owen Taylor3473f882001-02-23 17:55:21 +00008858 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008859 axis = AXIS_CHILD;
8860 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008861 } else if (CUR == '@') {
8862 NEXT;
8863 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008864 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008865 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008866 }
Owen Taylor3473f882001-02-23 17:55:21 +00008867 }
8868
8869 CHECK_ERROR;
8870
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008871 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008872 if (test == 0)
8873 return;
8874
8875#ifdef DEBUG_STEP
8876 xmlGenericError(xmlGenericErrorContext,
8877 "Basis : computing new set\n");
8878#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008879
Owen Taylor3473f882001-02-23 17:55:21 +00008880#ifdef DEBUG_STEP
8881 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008882 if (ctxt->value == NULL)
8883 xmlGenericError(xmlGenericErrorContext, "no value\n");
8884 else if (ctxt->value->nodesetval == NULL)
8885 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8886 else
8887 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008888#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008889
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008890#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008891eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008892#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008893 op1 = ctxt->comp->last;
8894 ctxt->comp->last = -1;
8895
Owen Taylor3473f882001-02-23 17:55:21 +00008896 SKIP_BLANKS;
8897 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008898 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008899 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008900
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008901#ifdef LIBXML_XPTR_ENABLED
8902 if (rangeto) {
8903 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8904 } else
8905#endif
8906 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8907 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008908
Owen Taylor3473f882001-02-23 17:55:21 +00008909 }
8910#ifdef DEBUG_STEP
8911 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008912 if (ctxt->value == NULL)
8913 xmlGenericError(xmlGenericErrorContext, "no value\n");
8914 else if (ctxt->value->nodesetval == NULL)
8915 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8916 else
8917 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8918 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008919#endif
8920}
8921
8922/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008923 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008924 * @ctxt: the XPath Parser context
8925 *
8926 * [3] RelativeLocationPath ::= Step
8927 * | RelativeLocationPath '/' Step
8928 * | AbbreviatedRelativeLocationPath
8929 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8930 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008931 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008932 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008933static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008934xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008935(xmlXPathParserContextPtr ctxt) {
8936 SKIP_BLANKS;
8937 if ((CUR == '/') && (NXT(1) == '/')) {
8938 SKIP(2);
8939 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008940 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8941 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008942 } else if (CUR == '/') {
8943 NEXT;
8944 SKIP_BLANKS;
8945 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008946 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008947 SKIP_BLANKS;
8948 while (CUR == '/') {
8949 if ((CUR == '/') && (NXT(1) == '/')) {
8950 SKIP(2);
8951 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008952 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008953 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008954 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008955 } else if (CUR == '/') {
8956 NEXT;
8957 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008958 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008959 }
8960 SKIP_BLANKS;
8961 }
8962}
8963
8964/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008965 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008966 * @ctxt: the XPath Parser context
8967 *
8968 * [1] LocationPath ::= RelativeLocationPath
8969 * | AbsoluteLocationPath
8970 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8971 * | AbbreviatedAbsoluteLocationPath
8972 * [10] AbbreviatedAbsoluteLocationPath ::=
8973 * '//' RelativeLocationPath
8974 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008975 * Compile a location path
8976 *
Owen Taylor3473f882001-02-23 17:55:21 +00008977 * // is short for /descendant-or-self::node()/. For example,
8978 * //para is short for /descendant-or-self::node()/child::para and
8979 * so will select any para element in the document (even a para element
8980 * that is a document element will be selected by //para since the
8981 * document element node is a child of the root node); div//para is
8982 * short for div/descendant-or-self::node()/child::para and so will
8983 * select all para descendants of div children.
8984 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008985static void
8986xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008987 SKIP_BLANKS;
8988 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008989 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008990 } else {
8991 while (CUR == '/') {
8992 if ((CUR == '/') && (NXT(1) == '/')) {
8993 SKIP(2);
8994 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008995 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8996 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008997 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008998 } else if (CUR == '/') {
8999 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009000 SKIP_BLANKS;
9001 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009002 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009003 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009004 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009005 }
9006 }
9007 }
9008}
9009
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009010/************************************************************************
9011 * *
9012 * XPath precompiled expression evaluation *
9013 * *
9014 ************************************************************************/
9015
Daniel Veillardf06307e2001-07-03 10:35:50 +00009016static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009017xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9018
9019/**
9020 * xmlXPathNodeCollectAndTest:
9021 * @ctxt: the XPath Parser context
9022 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009023 * @first: pointer to the first element in document order
9024 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009025 *
9026 * This is the function implementing a step: based on the current list
9027 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009028 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009029 *
9030 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009031 *
William M. Brack08171912003-12-29 02:52:11 +00009032 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009033 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009034static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009035xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009036 xmlXPathStepOpPtr op,
9037 xmlNodePtr * first, xmlNodePtr * last)
9038{
William M. Brack78637da2003-07-31 14:47:38 +00009039 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9040 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9041 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009042 const xmlChar *prefix = op->value4;
9043 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009044 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009045
9046#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009047 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009048#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009049 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009050 xmlNodeSetPtr ret, list;
9051 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009052 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009053 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009054 xmlNodePtr cur = NULL;
9055 xmlXPathObjectPtr obj;
9056 xmlNodeSetPtr nodelist;
9057 xmlNodePtr tmp;
9058
Daniel Veillardf06307e2001-07-03 10:35:50 +00009059 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009060 obj = valuePop(ctxt);
9061 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009062 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009063 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 URI = xmlXPathNsLookup(ctxt->context, prefix);
9065 if (URI == NULL)
9066 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009067 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009068#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009069 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009070#endif
9071 switch (axis) {
9072 case AXIS_ANCESTOR:
9073#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009075#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009076 first = NULL;
9077 next = xmlXPathNextAncestor;
9078 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009079 case AXIS_ANCESTOR_OR_SELF:
9080#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009081 xmlGenericError(xmlGenericErrorContext,
9082 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009083#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 first = NULL;
9085 next = xmlXPathNextAncestorOrSelf;
9086 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009087 case AXIS_ATTRIBUTE:
9088#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009090#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009091 first = NULL;
9092 last = NULL;
9093 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009094 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009095 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009096 case AXIS_CHILD:
9097#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009099#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 last = NULL;
9101 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009102 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009104 case AXIS_DESCENDANT:
9105#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009106 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009107#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 last = NULL;
9109 next = xmlXPathNextDescendant;
9110 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009111 case AXIS_DESCENDANT_OR_SELF:
9112#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009113 xmlGenericError(xmlGenericErrorContext,
9114 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009115#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009116 last = NULL;
9117 next = xmlXPathNextDescendantOrSelf;
9118 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009119 case AXIS_FOLLOWING:
9120#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009122#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123 last = NULL;
9124 next = xmlXPathNextFollowing;
9125 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126 case AXIS_FOLLOWING_SIBLING:
9127#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009128 xmlGenericError(xmlGenericErrorContext,
9129 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009130#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 last = NULL;
9132 next = xmlXPathNextFollowingSibling;
9133 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009134 case AXIS_NAMESPACE:
9135#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009137#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 first = NULL;
9139 last = NULL;
9140 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009141 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009142 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009143 case AXIS_PARENT:
9144#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009145 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009146#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009147 first = NULL;
9148 next = xmlXPathNextParent;
9149 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009150 case AXIS_PRECEDING:
9151#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009152 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009153#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009154 first = NULL;
9155 next = xmlXPathNextPrecedingInternal;
9156 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009157 case AXIS_PRECEDING_SIBLING:
9158#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009159 xmlGenericError(xmlGenericErrorContext,
9160 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009161#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009162 first = NULL;
9163 next = xmlXPathNextPrecedingSibling;
9164 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009165 case AXIS_SELF:
9166#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009167 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009168#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009169 first = NULL;
9170 last = NULL;
9171 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009172 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009173 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009174 }
9175 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009177
9178 nodelist = obj->nodesetval;
9179 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009180 xmlXPathFreeObject(obj);
9181 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9182 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009183 }
9184 addNode = xmlXPathNodeSetAddUnique;
9185 ret = NULL;
9186#ifdef DEBUG_STEP
9187 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009188 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009189 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009190 case NODE_TEST_NONE:
9191 xmlGenericError(xmlGenericErrorContext,
9192 " searching for none !!!\n");
9193 break;
9194 case NODE_TEST_TYPE:
9195 xmlGenericError(xmlGenericErrorContext,
9196 " searching for type %d\n", type);
9197 break;
9198 case NODE_TEST_PI:
9199 xmlGenericError(xmlGenericErrorContext,
9200 " searching for PI !!!\n");
9201 break;
9202 case NODE_TEST_ALL:
9203 xmlGenericError(xmlGenericErrorContext,
9204 " searching for *\n");
9205 break;
9206 case NODE_TEST_NS:
9207 xmlGenericError(xmlGenericErrorContext,
9208 " searching for namespace %s\n",
9209 prefix);
9210 break;
9211 case NODE_TEST_NAME:
9212 xmlGenericError(xmlGenericErrorContext,
9213 " searching for name %s\n", name);
9214 if (prefix != NULL)
9215 xmlGenericError(xmlGenericErrorContext,
9216 " with namespace %s\n", prefix);
9217 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009218 }
9219 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9220#endif
9221 /*
9222 * 2.3 Node Tests
9223 * - For the attribute axis, the principal node type is attribute.
9224 * - For the namespace axis, the principal node type is namespace.
9225 * - For other axes, the principal node type is element.
9226 *
9227 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009228 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009229 * select all element children of the context node
9230 */
9231 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009232 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009233 ctxt->context->node = nodelist->nodeTab[i];
9234
Daniel Veillardf06307e2001-07-03 10:35:50 +00009235 cur = NULL;
9236 list = xmlXPathNodeSetCreate(NULL);
9237 do {
9238 cur = next(ctxt, cur);
9239 if (cur == NULL)
9240 break;
9241 if ((first != NULL) && (*first == cur))
9242 break;
9243 if (((t % 256) == 0) &&
9244 (first != NULL) && (*first != NULL) &&
9245 (xmlXPathCmpNodes(*first, cur) >= 0))
9246 break;
9247 if ((last != NULL) && (*last == cur))
9248 break;
9249 if (((t % 256) == 0) &&
9250 (last != NULL) && (*last != NULL) &&
9251 (xmlXPathCmpNodes(cur, *last) >= 0))
9252 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009253 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009254#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009255 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9256#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009257 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009258 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009259 ctxt->context->node = tmp;
9260 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009261 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009262 if ((cur->type == type) ||
9263 ((type == NODE_TYPE_NODE) &&
9264 ((cur->type == XML_DOCUMENT_NODE) ||
9265 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9266 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009267 (cur->type == XML_NAMESPACE_DECL) ||
9268 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009269 (cur->type == XML_PI_NODE) ||
9270 (cur->type == XML_COMMENT_NODE) ||
9271 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009272 (cur->type == XML_TEXT_NODE))) ||
9273 ((type == NODE_TYPE_TEXT) &&
9274 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009275#ifdef DEBUG_STEP
9276 n++;
9277#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009278 addNode(list, cur);
9279 }
9280 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009281 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009282 if (cur->type == XML_PI_NODE) {
9283 if ((name != NULL) &&
9284 (!xmlStrEqual(name, cur->name)))
9285 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009286#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009287 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009288#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009289 addNode(list, cur);
9290 }
9291 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009292 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009293 if (axis == AXIS_ATTRIBUTE) {
9294 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009295#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009296 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009297#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009298 addNode(list, cur);
9299 }
9300 } else if (axis == AXIS_NAMESPACE) {
9301 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009302#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009303 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009304#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009305 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9306 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009307 }
9308 } else {
9309 if (cur->type == XML_ELEMENT_NODE) {
9310 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009311#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009312 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009313#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009314 addNode(list, cur);
9315 } else if ((cur->ns != NULL) &&
9316 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009317#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009318 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009319#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009320 addNode(list, cur);
9321 }
9322 }
9323 }
9324 break;
9325 case NODE_TEST_NS:{
9326 TODO;
9327 break;
9328 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009329 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009330 switch (cur->type) {
9331 case XML_ELEMENT_NODE:
9332 if (xmlStrEqual(name, cur->name)) {
9333 if (prefix == NULL) {
9334 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009335#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009336 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009337#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009338 addNode(list, cur);
9339 }
9340 } else {
9341 if ((cur->ns != NULL) &&
9342 (xmlStrEqual(URI,
9343 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009344#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009345 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009346#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009347 addNode(list, cur);
9348 }
9349 }
9350 }
9351 break;
9352 case XML_ATTRIBUTE_NODE:{
9353 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009354
Daniel Veillardf06307e2001-07-03 10:35:50 +00009355 if (xmlStrEqual(name, attr->name)) {
9356 if (prefix == NULL) {
9357 if ((attr->ns == NULL) ||
9358 (attr->ns->prefix == NULL)) {
9359#ifdef DEBUG_STEP
9360 n++;
9361#endif
9362 addNode(list,
9363 (xmlNodePtr) attr);
9364 }
9365 } else {
9366 if ((attr->ns != NULL) &&
9367 (xmlStrEqual(URI,
9368 attr->ns->
9369 href))) {
9370#ifdef DEBUG_STEP
9371 n++;
9372#endif
9373 addNode(list,
9374 (xmlNodePtr) attr);
9375 }
9376 }
9377 }
9378 break;
9379 }
9380 case XML_NAMESPACE_DECL:
9381 if (cur->type == XML_NAMESPACE_DECL) {
9382 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009383
Daniel Veillardf06307e2001-07-03 10:35:50 +00009384 if ((ns->prefix != NULL) && (name != NULL)
9385 && (xmlStrEqual(ns->prefix, name))) {
9386#ifdef DEBUG_STEP
9387 n++;
9388#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009389 xmlXPathNodeSetAddNs(list,
9390 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009391 }
9392 }
9393 break;
9394 default:
9395 break;
9396 }
9397 break;
9398 break;
9399 }
9400 } while (cur != NULL);
9401
9402 /*
9403 * If there is some predicate filtering do it now
9404 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009405 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009406 xmlXPathObjectPtr obj2;
9407
9408 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9409 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9410 CHECK_TYPE0(XPATH_NODESET);
9411 obj2 = valuePop(ctxt);
9412 list = obj2->nodesetval;
9413 obj2->nodesetval = NULL;
9414 xmlXPathFreeObject(obj2);
9415 }
9416 if (ret == NULL) {
9417 ret = list;
9418 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009419 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009420 xmlXPathFreeNodeSet(list);
9421 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009422 }
9423 ctxt->context->node = tmp;
9424#ifdef DEBUG_STEP
9425 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009426 "\nExamined %d nodes, found %d nodes at that step\n",
9427 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009428#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009429 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009430 if ((obj->boolval) && (obj->user != NULL)) {
9431 ctxt->value->boolval = 1;
9432 ctxt->value->user = obj->user;
9433 obj->user = NULL;
9434 obj->boolval = 0;
9435 }
9436 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009437 return(t);
9438}
9439
9440/**
9441 * xmlXPathNodeCollectAndTestNth:
9442 * @ctxt: the XPath Parser context
9443 * @op: the XPath precompiled step operation
9444 * @indx: the index to collect
9445 * @first: pointer to the first element in document order
9446 * @last: pointer to the last element in document order
9447 *
9448 * This is the function implementing a step: based on the current list
9449 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009450 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009451 *
9452 * Pushes the new NodeSet resulting from the search.
9453 * Returns the number of node traversed
9454 */
9455static int
9456xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9457 xmlXPathStepOpPtr op, int indx,
9458 xmlNodePtr * first, xmlNodePtr * last)
9459{
William M. Brack78637da2003-07-31 14:47:38 +00009460 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9461 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9462 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009463 const xmlChar *prefix = op->value4;
9464 const xmlChar *name = op->value5;
9465 const xmlChar *URI = NULL;
9466 int n = 0, t = 0;
9467
9468 int i;
9469 xmlNodeSetPtr list;
9470 xmlXPathTraversalFunction next = NULL;
9471 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9472 xmlNodePtr cur = NULL;
9473 xmlXPathObjectPtr obj;
9474 xmlNodeSetPtr nodelist;
9475 xmlNodePtr tmp;
9476
9477 CHECK_TYPE0(XPATH_NODESET);
9478 obj = valuePop(ctxt);
9479 addNode = xmlXPathNodeSetAdd;
9480 if (prefix != NULL) {
9481 URI = xmlXPathNsLookup(ctxt->context, prefix);
9482 if (URI == NULL)
9483 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9484 }
9485#ifdef DEBUG_STEP_NTH
9486 xmlGenericError(xmlGenericErrorContext, "new step : ");
9487 if (first != NULL) {
9488 if (*first != NULL)
9489 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9490 (*first)->name);
9491 else
9492 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9493 }
9494 if (last != NULL) {
9495 if (*last != NULL)
9496 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9497 (*last)->name);
9498 else
9499 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9500 }
9501#endif
9502 switch (axis) {
9503 case AXIS_ANCESTOR:
9504#ifdef DEBUG_STEP_NTH
9505 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9506#endif
9507 first = NULL;
9508 next = xmlXPathNextAncestor;
9509 break;
9510 case AXIS_ANCESTOR_OR_SELF:
9511#ifdef DEBUG_STEP_NTH
9512 xmlGenericError(xmlGenericErrorContext,
9513 "axis 'ancestors-or-self' ");
9514#endif
9515 first = NULL;
9516 next = xmlXPathNextAncestorOrSelf;
9517 break;
9518 case AXIS_ATTRIBUTE:
9519#ifdef DEBUG_STEP_NTH
9520 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9521#endif
9522 first = NULL;
9523 last = NULL;
9524 next = xmlXPathNextAttribute;
9525 break;
9526 case AXIS_CHILD:
9527#ifdef DEBUG_STEP_NTH
9528 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9529#endif
9530 last = NULL;
9531 next = xmlXPathNextChild;
9532 break;
9533 case AXIS_DESCENDANT:
9534#ifdef DEBUG_STEP_NTH
9535 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9536#endif
9537 last = NULL;
9538 next = xmlXPathNextDescendant;
9539 break;
9540 case AXIS_DESCENDANT_OR_SELF:
9541#ifdef DEBUG_STEP_NTH
9542 xmlGenericError(xmlGenericErrorContext,
9543 "axis 'descendant-or-self' ");
9544#endif
9545 last = NULL;
9546 next = xmlXPathNextDescendantOrSelf;
9547 break;
9548 case AXIS_FOLLOWING:
9549#ifdef DEBUG_STEP_NTH
9550 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9551#endif
9552 last = NULL;
9553 next = xmlXPathNextFollowing;
9554 break;
9555 case AXIS_FOLLOWING_SIBLING:
9556#ifdef DEBUG_STEP_NTH
9557 xmlGenericError(xmlGenericErrorContext,
9558 "axis 'following-siblings' ");
9559#endif
9560 last = NULL;
9561 next = xmlXPathNextFollowingSibling;
9562 break;
9563 case AXIS_NAMESPACE:
9564#ifdef DEBUG_STEP_NTH
9565 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9566#endif
9567 last = NULL;
9568 first = NULL;
9569 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9570 break;
9571 case AXIS_PARENT:
9572#ifdef DEBUG_STEP_NTH
9573 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9574#endif
9575 first = NULL;
9576 next = xmlXPathNextParent;
9577 break;
9578 case AXIS_PRECEDING:
9579#ifdef DEBUG_STEP_NTH
9580 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9581#endif
9582 first = NULL;
9583 next = xmlXPathNextPrecedingInternal;
9584 break;
9585 case AXIS_PRECEDING_SIBLING:
9586#ifdef DEBUG_STEP_NTH
9587 xmlGenericError(xmlGenericErrorContext,
9588 "axis 'preceding-sibling' ");
9589#endif
9590 first = NULL;
9591 next = xmlXPathNextPrecedingSibling;
9592 break;
9593 case AXIS_SELF:
9594#ifdef DEBUG_STEP_NTH
9595 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9596#endif
9597 first = NULL;
9598 last = NULL;
9599 next = xmlXPathNextSelf;
9600 break;
9601 }
9602 if (next == NULL)
9603 return(0);
9604
9605 nodelist = obj->nodesetval;
9606 if (nodelist == NULL) {
9607 xmlXPathFreeObject(obj);
9608 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9609 return(0);
9610 }
9611 addNode = xmlXPathNodeSetAddUnique;
9612#ifdef DEBUG_STEP_NTH
9613 xmlGenericError(xmlGenericErrorContext,
9614 " context contains %d nodes\n", nodelist->nodeNr);
9615 switch (test) {
9616 case NODE_TEST_NONE:
9617 xmlGenericError(xmlGenericErrorContext,
9618 " searching for none !!!\n");
9619 break;
9620 case NODE_TEST_TYPE:
9621 xmlGenericError(xmlGenericErrorContext,
9622 " searching for type %d\n", type);
9623 break;
9624 case NODE_TEST_PI:
9625 xmlGenericError(xmlGenericErrorContext,
9626 " searching for PI !!!\n");
9627 break;
9628 case NODE_TEST_ALL:
9629 xmlGenericError(xmlGenericErrorContext,
9630 " searching for *\n");
9631 break;
9632 case NODE_TEST_NS:
9633 xmlGenericError(xmlGenericErrorContext,
9634 " searching for namespace %s\n",
9635 prefix);
9636 break;
9637 case NODE_TEST_NAME:
9638 xmlGenericError(xmlGenericErrorContext,
9639 " searching for name %s\n", name);
9640 if (prefix != NULL)
9641 xmlGenericError(xmlGenericErrorContext,
9642 " with namespace %s\n", prefix);
9643 break;
9644 }
9645 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9646#endif
9647 /*
9648 * 2.3 Node Tests
9649 * - For the attribute axis, the principal node type is attribute.
9650 * - For the namespace axis, the principal node type is namespace.
9651 * - For other axes, the principal node type is element.
9652 *
9653 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009654 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009655 * select all element children of the context node
9656 */
9657 tmp = ctxt->context->node;
9658 list = xmlXPathNodeSetCreate(NULL);
9659 for (i = 0; i < nodelist->nodeNr; i++) {
9660 ctxt->context->node = nodelist->nodeTab[i];
9661
9662 cur = NULL;
9663 n = 0;
9664 do {
9665 cur = next(ctxt, cur);
9666 if (cur == NULL)
9667 break;
9668 if ((first != NULL) && (*first == cur))
9669 break;
9670 if (((t % 256) == 0) &&
9671 (first != NULL) && (*first != NULL) &&
9672 (xmlXPathCmpNodes(*first, cur) >= 0))
9673 break;
9674 if ((last != NULL) && (*last == cur))
9675 break;
9676 if (((t % 256) == 0) &&
9677 (last != NULL) && (*last != NULL) &&
9678 (xmlXPathCmpNodes(cur, *last) >= 0))
9679 break;
9680 t++;
9681 switch (test) {
9682 case NODE_TEST_NONE:
9683 ctxt->context->node = tmp;
9684 STRANGE return(0);
9685 case NODE_TEST_TYPE:
9686 if ((cur->type == type) ||
9687 ((type == NODE_TYPE_NODE) &&
9688 ((cur->type == XML_DOCUMENT_NODE) ||
9689 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9690 (cur->type == XML_ELEMENT_NODE) ||
9691 (cur->type == XML_PI_NODE) ||
9692 (cur->type == XML_COMMENT_NODE) ||
9693 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009694 (cur->type == XML_TEXT_NODE))) ||
9695 ((type == NODE_TYPE_TEXT) &&
9696 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009697 n++;
9698 if (n == indx)
9699 addNode(list, cur);
9700 }
9701 break;
9702 case NODE_TEST_PI:
9703 if (cur->type == XML_PI_NODE) {
9704 if ((name != NULL) &&
9705 (!xmlStrEqual(name, cur->name)))
9706 break;
9707 n++;
9708 if (n == indx)
9709 addNode(list, cur);
9710 }
9711 break;
9712 case NODE_TEST_ALL:
9713 if (axis == AXIS_ATTRIBUTE) {
9714 if (cur->type == XML_ATTRIBUTE_NODE) {
9715 n++;
9716 if (n == indx)
9717 addNode(list, cur);
9718 }
9719 } else if (axis == AXIS_NAMESPACE) {
9720 if (cur->type == XML_NAMESPACE_DECL) {
9721 n++;
9722 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009723 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9724 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009725 }
9726 } else {
9727 if (cur->type == XML_ELEMENT_NODE) {
9728 if (prefix == NULL) {
9729 n++;
9730 if (n == indx)
9731 addNode(list, cur);
9732 } else if ((cur->ns != NULL) &&
9733 (xmlStrEqual(URI, cur->ns->href))) {
9734 n++;
9735 if (n == indx)
9736 addNode(list, cur);
9737 }
9738 }
9739 }
9740 break;
9741 case NODE_TEST_NS:{
9742 TODO;
9743 break;
9744 }
9745 case NODE_TEST_NAME:
9746 switch (cur->type) {
9747 case XML_ELEMENT_NODE:
9748 if (xmlStrEqual(name, cur->name)) {
9749 if (prefix == NULL) {
9750 if (cur->ns == NULL) {
9751 n++;
9752 if (n == indx)
9753 addNode(list, cur);
9754 }
9755 } else {
9756 if ((cur->ns != NULL) &&
9757 (xmlStrEqual(URI,
9758 cur->ns->href))) {
9759 n++;
9760 if (n == indx)
9761 addNode(list, cur);
9762 }
9763 }
9764 }
9765 break;
9766 case XML_ATTRIBUTE_NODE:{
9767 xmlAttrPtr attr = (xmlAttrPtr) cur;
9768
9769 if (xmlStrEqual(name, attr->name)) {
9770 if (prefix == NULL) {
9771 if ((attr->ns == NULL) ||
9772 (attr->ns->prefix == NULL)) {
9773 n++;
9774 if (n == indx)
9775 addNode(list, cur);
9776 }
9777 } else {
9778 if ((attr->ns != NULL) &&
9779 (xmlStrEqual(URI,
9780 attr->ns->
9781 href))) {
9782 n++;
9783 if (n == indx)
9784 addNode(list, cur);
9785 }
9786 }
9787 }
9788 break;
9789 }
9790 case XML_NAMESPACE_DECL:
9791 if (cur->type == XML_NAMESPACE_DECL) {
9792 xmlNsPtr ns = (xmlNsPtr) cur;
9793
9794 if ((ns->prefix != NULL) && (name != NULL)
9795 && (xmlStrEqual(ns->prefix, name))) {
9796 n++;
9797 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009798 xmlXPathNodeSetAddNs(list,
9799 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009800 }
9801 }
9802 break;
9803 default:
9804 break;
9805 }
9806 break;
9807 break;
9808 }
9809 } while (n < indx);
9810 }
9811 ctxt->context->node = tmp;
9812#ifdef DEBUG_STEP_NTH
9813 xmlGenericError(xmlGenericErrorContext,
9814 "\nExamined %d nodes, found %d nodes at that step\n",
9815 t, list->nodeNr);
9816#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009817 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009818 if ((obj->boolval) && (obj->user != NULL)) {
9819 ctxt->value->boolval = 1;
9820 ctxt->value->user = obj->user;
9821 obj->user = NULL;
9822 obj->boolval = 0;
9823 }
9824 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009825 return(t);
9826}
9827
9828/**
9829 * xmlXPathCompOpEvalFirst:
9830 * @ctxt: the XPath parser context with the compiled expression
9831 * @op: an XPath compiled operation
9832 * @first: the first elem found so far
9833 *
9834 * Evaluate the Precompiled XPath operation searching only the first
9835 * element in document order
9836 *
9837 * Returns the number of examined objects.
9838 */
9839static int
9840xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9841 xmlXPathStepOpPtr op, xmlNodePtr * first)
9842{
9843 int total = 0, cur;
9844 xmlXPathCompExprPtr comp;
9845 xmlXPathObjectPtr arg1, arg2;
9846
Daniel Veillard556c6682001-10-06 09:59:51 +00009847 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009848 comp = ctxt->comp;
9849 switch (op->op) {
9850 case XPATH_OP_END:
9851 return (0);
9852 case XPATH_OP_UNION:
9853 total =
9854 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9855 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009856 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009857 if ((ctxt->value != NULL)
9858 && (ctxt->value->type == XPATH_NODESET)
9859 && (ctxt->value->nodesetval != NULL)
9860 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9861 /*
9862 * limit tree traversing to first node in the result
9863 */
9864 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9865 *first = ctxt->value->nodesetval->nodeTab[0];
9866 }
9867 cur =
9868 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9869 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009870 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009871 CHECK_TYPE0(XPATH_NODESET);
9872 arg2 = valuePop(ctxt);
9873
9874 CHECK_TYPE0(XPATH_NODESET);
9875 arg1 = valuePop(ctxt);
9876
9877 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9878 arg2->nodesetval);
9879 valuePush(ctxt, arg1);
9880 xmlXPathFreeObject(arg2);
9881 /* optimizer */
9882 if (total > cur)
9883 xmlXPathCompSwap(op);
9884 return (total + cur);
9885 case XPATH_OP_ROOT:
9886 xmlXPathRoot(ctxt);
9887 return (0);
9888 case XPATH_OP_NODE:
9889 if (op->ch1 != -1)
9890 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009891 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009892 if (op->ch2 != -1)
9893 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009894 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009895 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9896 return (total);
9897 case XPATH_OP_RESET:
9898 if (op->ch1 != -1)
9899 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009900 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009901 if (op->ch2 != -1)
9902 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009903 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009904 ctxt->context->node = NULL;
9905 return (total);
9906 case XPATH_OP_COLLECT:{
9907 if (op->ch1 == -1)
9908 return (total);
9909
9910 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009911 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009912
9913 /*
9914 * Optimization for [n] selection where n is a number
9915 */
9916 if ((op->ch2 != -1) &&
9917 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9918 (comp->steps[op->ch2].ch1 == -1) &&
9919 (comp->steps[op->ch2].ch2 != -1) &&
9920 (comp->steps[comp->steps[op->ch2].ch2].op ==
9921 XPATH_OP_VALUE)) {
9922 xmlXPathObjectPtr val;
9923
9924 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9925 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9926 int indx = (int) val->floatval;
9927
9928 if (val->floatval == (float) indx) {
9929 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9930 first, NULL);
9931 return (total);
9932 }
9933 }
9934 }
9935 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9936 return (total);
9937 }
9938 case XPATH_OP_VALUE:
9939 valuePush(ctxt,
9940 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9941 return (0);
9942 case XPATH_OP_SORT:
9943 if (op->ch1 != -1)
9944 total +=
9945 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9946 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009947 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 if ((ctxt->value != NULL)
9949 && (ctxt->value->type == XPATH_NODESET)
9950 && (ctxt->value->nodesetval != NULL))
9951 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9952 return (total);
9953 default:
9954 return (xmlXPathCompOpEval(ctxt, op));
9955 }
9956}
9957
9958/**
9959 * xmlXPathCompOpEvalLast:
9960 * @ctxt: the XPath parser context with the compiled expression
9961 * @op: an XPath compiled operation
9962 * @last: the last elem found so far
9963 *
9964 * Evaluate the Precompiled XPath operation searching only the last
9965 * element in document order
9966 *
William M. Brack08171912003-12-29 02:52:11 +00009967 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009968 */
9969static int
9970xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9971 xmlNodePtr * last)
9972{
9973 int total = 0, cur;
9974 xmlXPathCompExprPtr comp;
9975 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009976 xmlNodePtr bak;
9977 xmlDocPtr bakd;
9978 int pp;
9979 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980
Daniel Veillard556c6682001-10-06 09:59:51 +00009981 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009982 comp = ctxt->comp;
9983 switch (op->op) {
9984 case XPATH_OP_END:
9985 return (0);
9986 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009987 bakd = ctxt->context->doc;
9988 bak = ctxt->context->node;
9989 pp = ctxt->context->proximityPosition;
9990 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009991 total =
9992 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009993 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009994 if ((ctxt->value != NULL)
9995 && (ctxt->value->type == XPATH_NODESET)
9996 && (ctxt->value->nodesetval != NULL)
9997 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9998 /*
9999 * limit tree traversing to first node in the result
10000 */
10001 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10002 *last =
10003 ctxt->value->nodesetval->nodeTab[ctxt->value->
10004 nodesetval->nodeNr -
10005 1];
10006 }
William M. Brackce4fc562004-01-22 02:47:18 +000010007 ctxt->context->doc = bakd;
10008 ctxt->context->node = bak;
10009 ctxt->context->proximityPosition = pp;
10010 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010011 cur =
10012 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010013 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010014 if ((ctxt->value != NULL)
10015 && (ctxt->value->type == XPATH_NODESET)
10016 && (ctxt->value->nodesetval != NULL)
10017 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10018 }
10019 CHECK_TYPE0(XPATH_NODESET);
10020 arg2 = valuePop(ctxt);
10021
10022 CHECK_TYPE0(XPATH_NODESET);
10023 arg1 = valuePop(ctxt);
10024
10025 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10026 arg2->nodesetval);
10027 valuePush(ctxt, arg1);
10028 xmlXPathFreeObject(arg2);
10029 /* optimizer */
10030 if (total > cur)
10031 xmlXPathCompSwap(op);
10032 return (total + cur);
10033 case XPATH_OP_ROOT:
10034 xmlXPathRoot(ctxt);
10035 return (0);
10036 case XPATH_OP_NODE:
10037 if (op->ch1 != -1)
10038 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010039 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010040 if (op->ch2 != -1)
10041 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010042 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10044 return (total);
10045 case XPATH_OP_RESET:
10046 if (op->ch1 != -1)
10047 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010048 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010049 if (op->ch2 != -1)
10050 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010051 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010052 ctxt->context->node = NULL;
10053 return (total);
10054 case XPATH_OP_COLLECT:{
10055 if (op->ch1 == -1)
10056 return (0);
10057
10058 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010059 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010060
10061 /*
10062 * Optimization for [n] selection where n is a number
10063 */
10064 if ((op->ch2 != -1) &&
10065 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10066 (comp->steps[op->ch2].ch1 == -1) &&
10067 (comp->steps[op->ch2].ch2 != -1) &&
10068 (comp->steps[comp->steps[op->ch2].ch2].op ==
10069 XPATH_OP_VALUE)) {
10070 xmlXPathObjectPtr val;
10071
10072 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10073 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10074 int indx = (int) val->floatval;
10075
10076 if (val->floatval == (float) indx) {
10077 total +=
10078 xmlXPathNodeCollectAndTestNth(ctxt, op,
10079 indx, NULL,
10080 last);
10081 return (total);
10082 }
10083 }
10084 }
10085 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10086 return (total);
10087 }
10088 case XPATH_OP_VALUE:
10089 valuePush(ctxt,
10090 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10091 return (0);
10092 case XPATH_OP_SORT:
10093 if (op->ch1 != -1)
10094 total +=
10095 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10096 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010097 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010098 if ((ctxt->value != NULL)
10099 && (ctxt->value->type == XPATH_NODESET)
10100 && (ctxt->value->nodesetval != NULL))
10101 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10102 return (total);
10103 default:
10104 return (xmlXPathCompOpEval(ctxt, op));
10105 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010106}
10107
Owen Taylor3473f882001-02-23 17:55:21 +000010108/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010109 * xmlXPathCompOpEval:
10110 * @ctxt: the XPath parser context with the compiled expression
10111 * @op: an XPath compiled operation
10112 *
10113 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010114 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010115 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010116static int
10117xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10118{
10119 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010120 int equal, ret;
10121 xmlXPathCompExprPtr comp;
10122 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010123 xmlNodePtr bak;
10124 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010125 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010126 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010127
Daniel Veillard556c6682001-10-06 09:59:51 +000010128 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010129 comp = ctxt->comp;
10130 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010131 case XPATH_OP_END:
10132 return (0);
10133 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010134 bakd = ctxt->context->doc;
10135 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010136 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010137 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010138 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010139 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010140 xmlXPathBooleanFunction(ctxt, 1);
10141 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10142 return (total);
10143 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010144 ctxt->context->doc = bakd;
10145 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010146 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010147 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010148 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010149 if (ctxt->error) {
10150 xmlXPathFreeObject(arg2);
10151 return(0);
10152 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010153 xmlXPathBooleanFunction(ctxt, 1);
10154 arg1 = valuePop(ctxt);
10155 arg1->boolval &= arg2->boolval;
10156 valuePush(ctxt, arg1);
10157 xmlXPathFreeObject(arg2);
10158 return (total);
10159 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010160 bakd = ctxt->context->doc;
10161 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010162 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010163 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010164 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010165 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010166 xmlXPathBooleanFunction(ctxt, 1);
10167 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10168 return (total);
10169 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010170 ctxt->context->doc = bakd;
10171 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010172 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010173 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010174 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010175 if (ctxt->error) {
10176 xmlXPathFreeObject(arg2);
10177 return(0);
10178 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010179 xmlXPathBooleanFunction(ctxt, 1);
10180 arg1 = valuePop(ctxt);
10181 arg1->boolval |= arg2->boolval;
10182 valuePush(ctxt, arg1);
10183 xmlXPathFreeObject(arg2);
10184 return (total);
10185 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010186 bakd = ctxt->context->doc;
10187 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010188 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010189 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010190 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010191 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010192 ctxt->context->doc = bakd;
10193 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010194 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010195 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010196 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010197 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010198 if (op->value)
10199 equal = xmlXPathEqualValues(ctxt);
10200 else
10201 equal = xmlXPathNotEqualValues(ctxt);
10202 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010203 return (total);
10204 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010205 bakd = ctxt->context->doc;
10206 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010207 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010208 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010209 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010210 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010211 ctxt->context->doc = bakd;
10212 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010213 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010214 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010215 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010216 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010217 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10218 valuePush(ctxt, xmlXPathNewBoolean(ret));
10219 return (total);
10220 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010221 bakd = ctxt->context->doc;
10222 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010223 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010224 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010225 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010226 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010227 if (op->ch2 != -1) {
10228 ctxt->context->doc = bakd;
10229 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010230 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010231 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010232 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010233 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010234 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010235 if (op->value == 0)
10236 xmlXPathSubValues(ctxt);
10237 else if (op->value == 1)
10238 xmlXPathAddValues(ctxt);
10239 else if (op->value == 2)
10240 xmlXPathValueFlipSign(ctxt);
10241 else if (op->value == 3) {
10242 CAST_TO_NUMBER;
10243 CHECK_TYPE0(XPATH_NUMBER);
10244 }
10245 return (total);
10246 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010247 bakd = ctxt->context->doc;
10248 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010249 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010250 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010251 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010252 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010253 ctxt->context->doc = bakd;
10254 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010255 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010256 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010257 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010258 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010259 if (op->value == 0)
10260 xmlXPathMultValues(ctxt);
10261 else if (op->value == 1)
10262 xmlXPathDivValues(ctxt);
10263 else if (op->value == 2)
10264 xmlXPathModValues(ctxt);
10265 return (total);
10266 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010267 bakd = ctxt->context->doc;
10268 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010269 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010270 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010272 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010273 ctxt->context->doc = bakd;
10274 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010275 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010276 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010278 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010279 CHECK_TYPE0(XPATH_NODESET);
10280 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010281
Daniel Veillardf06307e2001-07-03 10:35:50 +000010282 CHECK_TYPE0(XPATH_NODESET);
10283 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010284
Daniel Veillardf06307e2001-07-03 10:35:50 +000010285 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10286 arg2->nodesetval);
10287 valuePush(ctxt, arg1);
10288 xmlXPathFreeObject(arg2);
10289 return (total);
10290 case XPATH_OP_ROOT:
10291 xmlXPathRoot(ctxt);
10292 return (total);
10293 case XPATH_OP_NODE:
10294 if (op->ch1 != -1)
10295 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010296 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010297 if (op->ch2 != -1)
10298 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010299 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010300 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10301 return (total);
10302 case XPATH_OP_RESET:
10303 if (op->ch1 != -1)
10304 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010305 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010306 if (op->ch2 != -1)
10307 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010308 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010309 ctxt->context->node = NULL;
10310 return (total);
10311 case XPATH_OP_COLLECT:{
10312 if (op->ch1 == -1)
10313 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010314
Daniel Veillardf06307e2001-07-03 10:35:50 +000010315 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010316 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010317
Daniel Veillardf06307e2001-07-03 10:35:50 +000010318 /*
10319 * Optimization for [n] selection where n is a number
10320 */
10321 if ((op->ch2 != -1) &&
10322 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10323 (comp->steps[op->ch2].ch1 == -1) &&
10324 (comp->steps[op->ch2].ch2 != -1) &&
10325 (comp->steps[comp->steps[op->ch2].ch2].op ==
10326 XPATH_OP_VALUE)) {
10327 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010328
Daniel Veillardf06307e2001-07-03 10:35:50 +000010329 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10330 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10331 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010332
Daniel Veillardf06307e2001-07-03 10:35:50 +000010333 if (val->floatval == (float) indx) {
10334 total +=
10335 xmlXPathNodeCollectAndTestNth(ctxt, op,
10336 indx, NULL,
10337 NULL);
10338 return (total);
10339 }
10340 }
10341 }
10342 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10343 return (total);
10344 }
10345 case XPATH_OP_VALUE:
10346 valuePush(ctxt,
10347 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10348 return (total);
10349 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010350 xmlXPathObjectPtr val;
10351
Daniel Veillardf06307e2001-07-03 10:35:50 +000010352 if (op->ch1 != -1)
10353 total +=
10354 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010355 if (op->value5 == NULL) {
10356 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10357 if (val == NULL) {
10358 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10359 return(0);
10360 }
10361 valuePush(ctxt, val);
10362 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010363 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010364
Daniel Veillardf06307e2001-07-03 10:35:50 +000010365 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10366 if (URI == NULL) {
10367 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010368 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010369 op->value4, op->value5);
10370 return (total);
10371 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010372 val = xmlXPathVariableLookupNS(ctxt->context,
10373 op->value4, URI);
10374 if (val == NULL) {
10375 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10376 return(0);
10377 }
10378 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010379 }
10380 return (total);
10381 }
10382 case XPATH_OP_FUNCTION:{
10383 xmlXPathFunction func;
10384 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010385 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010386
10387 if (op->ch1 != -1)
10388 total +=
10389 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010390 if (ctxt->valueNr < op->value) {
10391 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010392 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010393 ctxt->error = XPATH_INVALID_OPERAND;
10394 return (total);
10395 }
10396 for (i = 0; i < op->value; i++)
10397 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10398 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010399 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010400 ctxt->error = XPATH_INVALID_OPERAND;
10401 return (total);
10402 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010403 if (op->cache != NULL)
10404 func = (xmlXPathFunction) op->cache;
10405 else {
10406 const xmlChar *URI = NULL;
10407
10408 if (op->value5 == NULL)
10409 func =
10410 xmlXPathFunctionLookup(ctxt->context,
10411 op->value4);
10412 else {
10413 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10414 if (URI == NULL) {
10415 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010416 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010417 op->value4, op->value5);
10418 return (total);
10419 }
10420 func = xmlXPathFunctionLookupNS(ctxt->context,
10421 op->value4, URI);
10422 }
10423 if (func == NULL) {
10424 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010425 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010426 op->value4);
10427 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010428 }
10429 op->cache = (void *) func;
10430 op->cacheURI = (void *) URI;
10431 }
10432 oldFunc = ctxt->context->function;
10433 oldFuncURI = ctxt->context->functionURI;
10434 ctxt->context->function = op->value4;
10435 ctxt->context->functionURI = op->cacheURI;
10436 func(ctxt, op->value);
10437 ctxt->context->function = oldFunc;
10438 ctxt->context->functionURI = oldFuncURI;
10439 return (total);
10440 }
10441 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010442 bakd = ctxt->context->doc;
10443 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010444 pp = ctxt->context->proximityPosition;
10445 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010446 if (op->ch1 != -1)
10447 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010448 ctxt->context->contextSize = cs;
10449 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010450 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010451 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010452 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010453 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010454 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010455 ctxt->context->doc = bakd;
10456 ctxt->context->node = bak;
10457 CHECK_ERROR0;
10458 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010459 return (total);
10460 case XPATH_OP_PREDICATE:
10461 case XPATH_OP_FILTER:{
10462 xmlXPathObjectPtr res;
10463 xmlXPathObjectPtr obj, tmp;
10464 xmlNodeSetPtr newset = NULL;
10465 xmlNodeSetPtr oldset;
10466 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010467 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010468 int i;
10469
10470 /*
10471 * Optimization for ()[1] selection i.e. the first elem
10472 */
10473 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10474 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10475 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10476 xmlXPathObjectPtr val;
10477
10478 val = comp->steps[op->ch2].value4;
10479 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10480 (val->floatval == 1.0)) {
10481 xmlNodePtr first = NULL;
10482
10483 total +=
10484 xmlXPathCompOpEvalFirst(ctxt,
10485 &comp->steps[op->ch1],
10486 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010487 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010488 /*
10489 * The nodeset should be in document order,
10490 * Keep only the first value
10491 */
10492 if ((ctxt->value != NULL) &&
10493 (ctxt->value->type == XPATH_NODESET) &&
10494 (ctxt->value->nodesetval != NULL) &&
10495 (ctxt->value->nodesetval->nodeNr > 1))
10496 ctxt->value->nodesetval->nodeNr = 1;
10497 return (total);
10498 }
10499 }
10500 /*
10501 * Optimization for ()[last()] selection i.e. the last elem
10502 */
10503 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10504 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10505 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10506 int f = comp->steps[op->ch2].ch1;
10507
10508 if ((f != -1) &&
10509 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10510 (comp->steps[f].value5 == NULL) &&
10511 (comp->steps[f].value == 0) &&
10512 (comp->steps[f].value4 != NULL) &&
10513 (xmlStrEqual
10514 (comp->steps[f].value4, BAD_CAST "last"))) {
10515 xmlNodePtr last = NULL;
10516
10517 total +=
10518 xmlXPathCompOpEvalLast(ctxt,
10519 &comp->steps[op->ch1],
10520 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010521 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010522 /*
10523 * The nodeset should be in document order,
10524 * Keep only the last value
10525 */
10526 if ((ctxt->value != NULL) &&
10527 (ctxt->value->type == XPATH_NODESET) &&
10528 (ctxt->value->nodesetval != NULL) &&
10529 (ctxt->value->nodesetval->nodeTab != NULL) &&
10530 (ctxt->value->nodesetval->nodeNr > 1)) {
10531 ctxt->value->nodesetval->nodeTab[0] =
10532 ctxt->value->nodesetval->nodeTab[ctxt->
10533 value->
10534 nodesetval->
10535 nodeNr -
10536 1];
10537 ctxt->value->nodesetval->nodeNr = 1;
10538 }
10539 return (total);
10540 }
10541 }
10542
10543 if (op->ch1 != -1)
10544 total +=
10545 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010546 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010547 if (op->ch2 == -1)
10548 return (total);
10549 if (ctxt->value == NULL)
10550 return (total);
10551
10552 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010553
10554#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010555 /*
10556 * Hum are we filtering the result of an XPointer expression
10557 */
10558 if (ctxt->value->type == XPATH_LOCATIONSET) {
10559 xmlLocationSetPtr newlocset = NULL;
10560 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010561
Daniel Veillardf06307e2001-07-03 10:35:50 +000010562 /*
10563 * Extract the old locset, and then evaluate the result of the
10564 * expression for all the element in the locset. use it to grow
10565 * up a new locset.
10566 */
10567 CHECK_TYPE0(XPATH_LOCATIONSET);
10568 obj = valuePop(ctxt);
10569 oldlocset = obj->user;
10570 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010571
Daniel Veillardf06307e2001-07-03 10:35:50 +000010572 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10573 ctxt->context->contextSize = 0;
10574 ctxt->context->proximityPosition = 0;
10575 if (op->ch2 != -1)
10576 total +=
10577 xmlXPathCompOpEval(ctxt,
10578 &comp->steps[op->ch2]);
10579 res = valuePop(ctxt);
10580 if (res != NULL)
10581 xmlXPathFreeObject(res);
10582 valuePush(ctxt, obj);
10583 CHECK_ERROR0;
10584 return (total);
10585 }
10586 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010587
Daniel Veillardf06307e2001-07-03 10:35:50 +000010588 for (i = 0; i < oldlocset->locNr; i++) {
10589 /*
10590 * Run the evaluation with a node list made of a
10591 * single item in the nodelocset.
10592 */
10593 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010594 ctxt->context->contextSize = oldlocset->locNr;
10595 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010596 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10597 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010598
Daniel Veillardf06307e2001-07-03 10:35:50 +000010599 if (op->ch2 != -1)
10600 total +=
10601 xmlXPathCompOpEval(ctxt,
10602 &comp->steps[op->ch2]);
10603 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010604
Daniel Veillardf06307e2001-07-03 10:35:50 +000010605 /*
10606 * The result of the evaluation need to be tested to
10607 * decided whether the filter succeeded or not
10608 */
10609 res = valuePop(ctxt);
10610 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10611 xmlXPtrLocationSetAdd(newlocset,
10612 xmlXPathObjectCopy
10613 (oldlocset->locTab[i]));
10614 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010615
Daniel Veillardf06307e2001-07-03 10:35:50 +000010616 /*
10617 * Cleanup
10618 */
10619 if (res != NULL)
10620 xmlXPathFreeObject(res);
10621 if (ctxt->value == tmp) {
10622 res = valuePop(ctxt);
10623 xmlXPathFreeObject(res);
10624 }
10625
10626 ctxt->context->node = NULL;
10627 }
10628
10629 /*
10630 * The result is used as the new evaluation locset.
10631 */
10632 xmlXPathFreeObject(obj);
10633 ctxt->context->node = NULL;
10634 ctxt->context->contextSize = -1;
10635 ctxt->context->proximityPosition = -1;
10636 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10637 ctxt->context->node = oldnode;
10638 return (total);
10639 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010640#endif /* LIBXML_XPTR_ENABLED */
10641
Daniel Veillardf06307e2001-07-03 10:35:50 +000010642 /*
10643 * Extract the old set, and then evaluate the result of the
10644 * expression for all the element in the set. use it to grow
10645 * up a new set.
10646 */
10647 CHECK_TYPE0(XPATH_NODESET);
10648 obj = valuePop(ctxt);
10649 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010650
Daniel Veillardf06307e2001-07-03 10:35:50 +000010651 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010652 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010653 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010654
Daniel Veillardf06307e2001-07-03 10:35:50 +000010655 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10656 ctxt->context->contextSize = 0;
10657 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010658/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010659 if (op->ch2 != -1)
10660 total +=
10661 xmlXPathCompOpEval(ctxt,
10662 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010663 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010664 res = valuePop(ctxt);
10665 if (res != NULL)
10666 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010667*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010668 valuePush(ctxt, obj);
10669 ctxt->context->node = oldnode;
10670 CHECK_ERROR0;
10671 } else {
10672 /*
10673 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010674 * Also set the xpath document in case things like
10675 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010676 */
10677 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010678
Daniel Veillardf06307e2001-07-03 10:35:50 +000010679 for (i = 0; i < oldset->nodeNr; i++) {
10680 /*
10681 * Run the evaluation with a node list made of
10682 * a single item in the nodeset.
10683 */
10684 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010685 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10686 (oldset->nodeTab[i]->doc != NULL))
10687 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010688 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10689 valuePush(ctxt, tmp);
10690 ctxt->context->contextSize = oldset->nodeNr;
10691 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010692
Daniel Veillardf06307e2001-07-03 10:35:50 +000010693 if (op->ch2 != -1)
10694 total +=
10695 xmlXPathCompOpEval(ctxt,
10696 &comp->steps[op->ch2]);
10697 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010698
Daniel Veillardf06307e2001-07-03 10:35:50 +000010699 /*
William M. Brack08171912003-12-29 02:52:11 +000010700 * The result of the evaluation needs to be tested to
10701 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010702 */
10703 res = valuePop(ctxt);
10704 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10705 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10706 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010707
Daniel Veillardf06307e2001-07-03 10:35:50 +000010708 /*
10709 * Cleanup
10710 */
10711 if (res != NULL)
10712 xmlXPathFreeObject(res);
10713 if (ctxt->value == tmp) {
10714 res = valuePop(ctxt);
10715 xmlXPathFreeObject(res);
10716 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010717
Daniel Veillardf06307e2001-07-03 10:35:50 +000010718 ctxt->context->node = NULL;
10719 }
10720
10721 /*
10722 * The result is used as the new evaluation set.
10723 */
10724 xmlXPathFreeObject(obj);
10725 ctxt->context->node = NULL;
10726 ctxt->context->contextSize = -1;
10727 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010728 /* may want to move this past the '}' later */
10729 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010730 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10731 }
10732 ctxt->context->node = oldnode;
10733 return (total);
10734 }
10735 case XPATH_OP_SORT:
10736 if (op->ch1 != -1)
10737 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010738 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010739 if ((ctxt->value != NULL) &&
10740 (ctxt->value->type == XPATH_NODESET) &&
10741 (ctxt->value->nodesetval != NULL))
10742 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10743 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010744#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010745 case XPATH_OP_RANGETO:{
10746 xmlXPathObjectPtr range;
10747 xmlXPathObjectPtr res, obj;
10748 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010749 xmlLocationSetPtr newlocset = NULL;
10750 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010751 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010752 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010753
Daniel Veillardf06307e2001-07-03 10:35:50 +000010754 if (op->ch1 != -1)
10755 total +=
10756 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10757 if (op->ch2 == -1)
10758 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010759
William M. Brack08171912003-12-29 02:52:11 +000010760 if (ctxt->value->type == XPATH_LOCATIONSET) {
10761 /*
10762 * Extract the old locset, and then evaluate the result of the
10763 * expression for all the element in the locset. use it to grow
10764 * up a new locset.
10765 */
10766 CHECK_TYPE0(XPATH_LOCATIONSET);
10767 obj = valuePop(ctxt);
10768 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010769
William M. Brack08171912003-12-29 02:52:11 +000010770 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010771 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010772 ctxt->context->contextSize = 0;
10773 ctxt->context->proximityPosition = 0;
10774 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10775 res = valuePop(ctxt);
10776 if (res != NULL)
10777 xmlXPathFreeObject(res);
10778 valuePush(ctxt, obj);
10779 CHECK_ERROR0;
10780 return (total);
10781 }
10782 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010783
William M. Brack08171912003-12-29 02:52:11 +000010784 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010785 /*
William M. Brack08171912003-12-29 02:52:11 +000010786 * Run the evaluation with a node list made of a
10787 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010788 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010789 ctxt->context->node = oldlocset->locTab[i]->user;
10790 ctxt->context->contextSize = oldlocset->locNr;
10791 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010792 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10793 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010794
Daniel Veillardf06307e2001-07-03 10:35:50 +000010795 if (op->ch2 != -1)
10796 total +=
10797 xmlXPathCompOpEval(ctxt,
10798 &comp->steps[op->ch2]);
10799 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010800
Daniel Veillardf06307e2001-07-03 10:35:50 +000010801 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010802 if (res->type == XPATH_LOCATIONSET) {
10803 xmlLocationSetPtr rloc =
10804 (xmlLocationSetPtr)res->user;
10805 for (j=0; j<rloc->locNr; j++) {
10806 range = xmlXPtrNewRange(
10807 oldlocset->locTab[i]->user,
10808 oldlocset->locTab[i]->index,
10809 rloc->locTab[j]->user2,
10810 rloc->locTab[j]->index2);
10811 if (range != NULL) {
10812 xmlXPtrLocationSetAdd(newlocset, range);
10813 }
10814 }
10815 } else {
10816 range = xmlXPtrNewRangeNodeObject(
10817 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10818 if (range != NULL) {
10819 xmlXPtrLocationSetAdd(newlocset,range);
10820 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010821 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010822
Daniel Veillardf06307e2001-07-03 10:35:50 +000010823 /*
10824 * Cleanup
10825 */
10826 if (res != NULL)
10827 xmlXPathFreeObject(res);
10828 if (ctxt->value == tmp) {
10829 res = valuePop(ctxt);
10830 xmlXPathFreeObject(res);
10831 }
10832
10833 ctxt->context->node = NULL;
10834 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010835 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010836 CHECK_TYPE0(XPATH_NODESET);
10837 obj = valuePop(ctxt);
10838 oldset = obj->nodesetval;
10839 ctxt->context->node = NULL;
10840
10841 newlocset = xmlXPtrLocationSetCreate(NULL);
10842
10843 if (oldset != NULL) {
10844 for (i = 0; i < oldset->nodeNr; i++) {
10845 /*
10846 * Run the evaluation with a node list made of a single item
10847 * in the nodeset.
10848 */
10849 ctxt->context->node = oldset->nodeTab[i];
10850 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10851 valuePush(ctxt, tmp);
10852
10853 if (op->ch2 != -1)
10854 total +=
10855 xmlXPathCompOpEval(ctxt,
10856 &comp->steps[op->ch2]);
10857 CHECK_ERROR0;
10858
William M. Brack08171912003-12-29 02:52:11 +000010859 res = valuePop(ctxt);
10860 range =
10861 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10862 res);
10863 if (range != NULL) {
10864 xmlXPtrLocationSetAdd(newlocset, range);
10865 }
10866
10867 /*
10868 * Cleanup
10869 */
10870 if (res != NULL)
10871 xmlXPathFreeObject(res);
10872 if (ctxt->value == tmp) {
10873 res = valuePop(ctxt);
10874 xmlXPathFreeObject(res);
10875 }
10876
10877 ctxt->context->node = NULL;
10878 }
10879 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010880 }
10881
10882 /*
10883 * The result is used as the new evaluation set.
10884 */
10885 xmlXPathFreeObject(obj);
10886 ctxt->context->node = NULL;
10887 ctxt->context->contextSize = -1;
10888 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010889 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010890 return (total);
10891 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010892#endif /* LIBXML_XPTR_ENABLED */
10893 }
10894 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010895 "XPath: unknown precompiled operation %d\n", op->op);
10896 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010897}
10898
10899/**
10900 * xmlXPathRunEval:
10901 * @ctxt: the XPath parser context with the compiled expression
10902 *
10903 * Evaluate the Precompiled XPath expression in the given context.
10904 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010905static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010906xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10907 xmlXPathCompExprPtr comp;
10908
10909 if ((ctxt == NULL) || (ctxt->comp == NULL))
10910 return;
10911
10912 if (ctxt->valueTab == NULL) {
10913 /* Allocate the value stack */
10914 ctxt->valueTab = (xmlXPathObjectPtr *)
10915 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10916 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010917 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010918 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010919 }
10920 ctxt->valueNr = 0;
10921 ctxt->valueMax = 10;
10922 ctxt->value = NULL;
10923 }
10924 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010925 if(comp->last < 0) {
10926 xmlGenericError(xmlGenericErrorContext,
10927 "xmlXPathRunEval: last is less than zero\n");
10928 return;
10929 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010930 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10931}
10932
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010933/************************************************************************
10934 * *
10935 * Public interfaces *
10936 * *
10937 ************************************************************************/
10938
10939/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010940 * xmlXPathEvalPredicate:
10941 * @ctxt: the XPath context
10942 * @res: the Predicate Expression evaluation result
10943 *
10944 * Evaluate a predicate result for the current node.
10945 * A PredicateExpr is evaluated by evaluating the Expr and converting
10946 * the result to a boolean. If the result is a number, the result will
10947 * be converted to true if the number is equal to the position of the
10948 * context node in the context node list (as returned by the position
10949 * function) and will be converted to false otherwise; if the result
10950 * is not a number, then the result will be converted as if by a call
10951 * to the boolean function.
10952 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010953 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010954 */
10955int
10956xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010957 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010958 switch (res->type) {
10959 case XPATH_BOOLEAN:
10960 return(res->boolval);
10961 case XPATH_NUMBER:
10962 return(res->floatval == ctxt->proximityPosition);
10963 case XPATH_NODESET:
10964 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010965 if (res->nodesetval == NULL)
10966 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010967 return(res->nodesetval->nodeNr != 0);
10968 case XPATH_STRING:
10969 return((res->stringval != NULL) &&
10970 (xmlStrlen(res->stringval) != 0));
10971 default:
10972 STRANGE
10973 }
10974 return(0);
10975}
10976
10977/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010978 * xmlXPathEvaluatePredicateResult:
10979 * @ctxt: the XPath Parser context
10980 * @res: the Predicate Expression evaluation result
10981 *
10982 * Evaluate a predicate result for the current node.
10983 * A PredicateExpr is evaluated by evaluating the Expr and converting
10984 * the result to a boolean. If the result is a number, the result will
10985 * be converted to true if the number is equal to the position of the
10986 * context node in the context node list (as returned by the position
10987 * function) and will be converted to false otherwise; if the result
10988 * is not a number, then the result will be converted as if by a call
10989 * to the boolean function.
10990 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010991 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010992 */
10993int
10994xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10995 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010996 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010997 switch (res->type) {
10998 case XPATH_BOOLEAN:
10999 return(res->boolval);
11000 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000011001#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000011002 return((res->floatval == ctxt->context->proximityPosition) &&
11003 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011004#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011005 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011006#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011007 case XPATH_NODESET:
11008 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011009 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011010 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011011 return(res->nodesetval->nodeNr != 0);
11012 case XPATH_STRING:
11013 return((res->stringval != NULL) &&
11014 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011015#ifdef LIBXML_XPTR_ENABLED
11016 case XPATH_LOCATIONSET:{
11017 xmlLocationSetPtr ptr = res->user;
11018 if (ptr == NULL)
11019 return(0);
11020 return (ptr->locNr != 0);
11021 }
11022#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011023 default:
11024 STRANGE
11025 }
11026 return(0);
11027}
11028
11029/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011030 * xmlXPathCtxtCompile:
11031 * @ctxt: an XPath context
11032 * @str: the XPath expression
11033 *
11034 * Compile an XPath expression
11035 *
11036 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11037 * the caller has to free the object.
11038 */
11039xmlXPathCompExprPtr
11040xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11041 xmlXPathParserContextPtr pctxt;
11042 xmlXPathCompExprPtr comp;
11043
11044 xmlXPathInit();
11045
11046 pctxt = xmlXPathNewParserContext(str, ctxt);
11047 xmlXPathCompileExpr(pctxt);
11048
11049 if( pctxt->error != XPATH_EXPRESSION_OK )
11050 {
11051 xmlXPathFreeParserContext(pctxt);
11052 return (0);
11053 }
11054
11055 if (*pctxt->cur != 0) {
11056 /*
11057 * aleksey: in some cases this line prints *second* error message
11058 * (see bug #78858) and probably this should be fixed.
11059 * However, we are not sure that all error messages are printed
11060 * out in other places. It's not critical so we leave it as-is for now
11061 */
11062 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11063 comp = NULL;
11064 } else {
11065 comp = pctxt->comp;
11066 pctxt->comp = NULL;
11067 }
11068 xmlXPathFreeParserContext(pctxt);
11069 if (comp != NULL) {
11070 comp->expr = xmlStrdup(str);
11071#ifdef DEBUG_EVAL_COUNTS
11072 comp->string = xmlStrdup(str);
11073 comp->nb = 0;
11074#endif
11075 }
11076 return(comp);
11077}
11078
11079/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011080 * xmlXPathCompile:
11081 * @str: the XPath expression
11082 *
11083 * Compile an XPath expression
11084 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011085 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011086 * the caller has to free the object.
11087 */
11088xmlXPathCompExprPtr
11089xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011090 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011091}
11092
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011093/**
11094 * xmlXPathCompiledEval:
11095 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011096 * @ctx: the XPath context
11097 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011098 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011099 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011100 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011101 * the caller has to free the object.
11102 */
11103xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011104xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011105 xmlXPathParserContextPtr ctxt;
11106 xmlXPathObjectPtr res, tmp, init = NULL;
11107 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011108#ifndef LIBXML_THREAD_ENABLED
11109 static int reentance = 0;
11110#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011111
William M. Brackf13f77f2004-11-12 16:03:48 +000011112 CHECK_CTXT(ctx)
11113
11114 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011115 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011116 xmlXPathInit();
11117
Daniel Veillard81463942001-10-16 12:34:39 +000011118#ifndef LIBXML_THREAD_ENABLED
11119 reentance++;
11120 if (reentance > 1)
11121 xmlXPathDisableOptimizer = 1;
11122#endif
11123
Daniel Veillardf06307e2001-07-03 10:35:50 +000011124#ifdef DEBUG_EVAL_COUNTS
11125 comp->nb++;
11126 if ((comp->string != NULL) && (comp->nb > 100)) {
11127 fprintf(stderr, "100 x %s\n", comp->string);
11128 comp->nb = 0;
11129 }
11130#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011131 ctxt = xmlXPathCompParserContext(comp, ctx);
11132 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011133
11134 if (ctxt->value == NULL) {
11135 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011136 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011137 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011138 } else {
11139 res = valuePop(ctxt);
11140 }
11141
Daniel Veillardf06307e2001-07-03 10:35:50 +000011142
Owen Taylor3473f882001-02-23 17:55:21 +000011143 do {
11144 tmp = valuePop(ctxt);
11145 if (tmp != NULL) {
11146 if (tmp != init)
11147 stack++;
11148 xmlXPathFreeObject(tmp);
11149 }
11150 } while (tmp != NULL);
11151 if ((stack != 0) && (res != NULL)) {
11152 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011153 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011154 stack);
11155 }
11156 if (ctxt->error != XPATH_EXPRESSION_OK) {
11157 xmlXPathFreeObject(res);
11158 res = NULL;
11159 }
11160
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011161
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011162 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011163 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011164#ifndef LIBXML_THREAD_ENABLED
11165 reentance--;
11166#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011167 return(res);
11168}
11169
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011170/**
11171 * xmlXPathEvalExpr:
11172 * @ctxt: the XPath Parser context
11173 *
11174 * Parse and evaluate an XPath expression in the given context,
11175 * then push the result on the context stack
11176 */
11177void
11178xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +000011179 if (ctxt == NULL) return;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011180 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011181 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011182 xmlXPathRunEval(ctxt);
11183}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011184
11185/**
11186 * xmlXPathEval:
11187 * @str: the XPath expression
11188 * @ctx: the XPath context
11189 *
11190 * Evaluate the XPath Location Path in the given context.
11191 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011192 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011193 * the caller has to free the object.
11194 */
11195xmlXPathObjectPtr
11196xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11197 xmlXPathParserContextPtr ctxt;
11198 xmlXPathObjectPtr res, tmp, init = NULL;
11199 int stack = 0;
11200
William M. Brackf13f77f2004-11-12 16:03:48 +000011201 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011202
William M. Brackf13f77f2004-11-12 16:03:48 +000011203 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011204
11205 ctxt = xmlXPathNewParserContext(str, ctx);
11206 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011207
11208 if (ctxt->value == NULL) {
11209 xmlGenericError(xmlGenericErrorContext,
11210 "xmlXPathEval: evaluation failed\n");
11211 res = NULL;
11212 } else if (*ctxt->cur != 0) {
11213 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11214 res = NULL;
11215 } else {
11216 res = valuePop(ctxt);
11217 }
11218
11219 do {
11220 tmp = valuePop(ctxt);
11221 if (tmp != NULL) {
11222 if (tmp != init)
11223 stack++;
11224 xmlXPathFreeObject(tmp);
11225 }
11226 } while (tmp != NULL);
11227 if ((stack != 0) && (res != NULL)) {
11228 xmlGenericError(xmlGenericErrorContext,
11229 "xmlXPathEval: %d object left on the stack\n",
11230 stack);
11231 }
11232 if (ctxt->error != XPATH_EXPRESSION_OK) {
11233 xmlXPathFreeObject(res);
11234 res = NULL;
11235 }
11236
Owen Taylor3473f882001-02-23 17:55:21 +000011237 xmlXPathFreeParserContext(ctxt);
11238 return(res);
11239}
11240
11241/**
11242 * xmlXPathEvalExpression:
11243 * @str: the XPath expression
11244 * @ctxt: the XPath context
11245 *
11246 * Evaluate the XPath expression in the given context.
11247 *
11248 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11249 * the caller has to free the object.
11250 */
11251xmlXPathObjectPtr
11252xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11253 xmlXPathParserContextPtr pctxt;
11254 xmlXPathObjectPtr res, tmp;
11255 int stack = 0;
11256
William M. Brackf13f77f2004-11-12 16:03:48 +000011257 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000011258
William M. Brackf13f77f2004-11-12 16:03:48 +000011259 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000011260
11261 pctxt = xmlXPathNewParserContext(str, ctxt);
11262 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011263
11264 if (*pctxt->cur != 0) {
11265 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11266 res = NULL;
11267 } else {
11268 res = valuePop(pctxt);
11269 }
11270 do {
11271 tmp = valuePop(pctxt);
11272 if (tmp != NULL) {
11273 xmlXPathFreeObject(tmp);
11274 stack++;
11275 }
11276 } while (tmp != NULL);
11277 if ((stack != 0) && (res != NULL)) {
11278 xmlGenericError(xmlGenericErrorContext,
11279 "xmlXPathEvalExpression: %d object left on the stack\n",
11280 stack);
11281 }
11282 xmlXPathFreeParserContext(pctxt);
11283 return(res);
11284}
11285
Daniel Veillard42766c02002-08-22 20:52:17 +000011286/************************************************************************
11287 * *
11288 * Extra functions not pertaining to the XPath spec *
11289 * *
11290 ************************************************************************/
11291/**
11292 * xmlXPathEscapeUriFunction:
11293 * @ctxt: the XPath Parser context
11294 * @nargs: the number of arguments
11295 *
11296 * Implement the escape-uri() XPath function
11297 * string escape-uri(string $str, bool $escape-reserved)
11298 *
11299 * This function applies the URI escaping rules defined in section 2 of [RFC
11300 * 2396] to the string supplied as $uri-part, which typically represents all
11301 * or part of a URI. The effect of the function is to replace any special
11302 * character in the string by an escape sequence of the form %xx%yy...,
11303 * where xxyy... is the hexadecimal representation of the octets used to
11304 * represent the character in UTF-8.
11305 *
11306 * The set of characters that are escaped depends on the setting of the
11307 * boolean argument $escape-reserved.
11308 *
11309 * If $escape-reserved is true, all characters are escaped other than lower
11310 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11311 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11312 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11313 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11314 * A-F).
11315 *
11316 * If $escape-reserved is false, the behavior differs in that characters
11317 * referred to in [RFC 2396] as reserved characters are not escaped. These
11318 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11319 *
11320 * [RFC 2396] does not define whether escaped URIs should use lower case or
11321 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11322 * compared using string comparison functions, this function must always use
11323 * the upper-case letters A-F.
11324 *
11325 * Generally, $escape-reserved should be set to true when escaping a string
11326 * that is to form a single part of a URI, and to false when escaping an
11327 * entire URI or URI reference.
11328 *
11329 * In the case of non-ascii characters, the string is encoded according to
11330 * utf-8 and then converted according to RFC 2396.
11331 *
11332 * Examples
11333 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11334 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11335 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11336 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11337 *
11338 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011339static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011340xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11341 xmlXPathObjectPtr str;
11342 int escape_reserved;
11343 xmlBufferPtr target;
11344 xmlChar *cptr;
11345 xmlChar escape[4];
11346
11347 CHECK_ARITY(2);
11348
11349 escape_reserved = xmlXPathPopBoolean(ctxt);
11350
11351 CAST_TO_STRING;
11352 str = valuePop(ctxt);
11353
11354 target = xmlBufferCreate();
11355
11356 escape[0] = '%';
11357 escape[3] = 0;
11358
11359 if (target) {
11360 for (cptr = str->stringval; *cptr; cptr++) {
11361 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11362 (*cptr >= 'a' && *cptr <= 'z') ||
11363 (*cptr >= '0' && *cptr <= '9') ||
11364 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11365 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11366 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11367 (*cptr == '%' &&
11368 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11369 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11370 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11371 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11372 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11373 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11374 (!escape_reserved &&
11375 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11376 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11377 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11378 *cptr == ','))) {
11379 xmlBufferAdd(target, cptr, 1);
11380 } else {
11381 if ((*cptr >> 4) < 10)
11382 escape[1] = '0' + (*cptr >> 4);
11383 else
11384 escape[1] = 'A' - 10 + (*cptr >> 4);
11385 if ((*cptr & 0xF) < 10)
11386 escape[2] = '0' + (*cptr & 0xF);
11387 else
11388 escape[2] = 'A' - 10 + (*cptr & 0xF);
11389
11390 xmlBufferAdd(target, &escape[0], 3);
11391 }
11392 }
11393 }
11394 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11395 xmlBufferFree(target);
11396 xmlXPathFreeObject(str);
11397}
11398
Owen Taylor3473f882001-02-23 17:55:21 +000011399/**
11400 * xmlXPathRegisterAllFunctions:
11401 * @ctxt: the XPath context
11402 *
11403 * Registers all default XPath functions in this context
11404 */
11405void
11406xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11407{
11408 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11409 xmlXPathBooleanFunction);
11410 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11411 xmlXPathCeilingFunction);
11412 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11413 xmlXPathCountFunction);
11414 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11415 xmlXPathConcatFunction);
11416 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11417 xmlXPathContainsFunction);
11418 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11419 xmlXPathIdFunction);
11420 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11421 xmlXPathFalseFunction);
11422 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11423 xmlXPathFloorFunction);
11424 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11425 xmlXPathLastFunction);
11426 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11427 xmlXPathLangFunction);
11428 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11429 xmlXPathLocalNameFunction);
11430 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11431 xmlXPathNotFunction);
11432 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11433 xmlXPathNameFunction);
11434 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11435 xmlXPathNamespaceURIFunction);
11436 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11437 xmlXPathNormalizeFunction);
11438 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11439 xmlXPathNumberFunction);
11440 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11441 xmlXPathPositionFunction);
11442 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11443 xmlXPathRoundFunction);
11444 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11445 xmlXPathStringFunction);
11446 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11447 xmlXPathStringLengthFunction);
11448 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11449 xmlXPathStartsWithFunction);
11450 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11451 xmlXPathSubstringFunction);
11452 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11453 xmlXPathSubstringBeforeFunction);
11454 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11455 xmlXPathSubstringAfterFunction);
11456 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11457 xmlXPathSumFunction);
11458 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11459 xmlXPathTrueFunction);
11460 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11461 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011462
11463 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11464 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11465 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011466}
11467
11468#endif /* LIBXML_XPATH_ENABLED */