blob: 20e38f4861c20ce0b358f22ea0dfa33753420faf [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) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003920 if (ctxt == NULL) return;
3921
Owen Taylor3473f882001-02-23 17:55:21 +00003922 xmlXPathRegisteredNsCleanup(ctxt);
3923 xmlXPathRegisteredFuncsCleanup(ctxt);
3924 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003925 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00003926 xmlFree(ctxt);
3927}
3928
3929/************************************************************************
3930 * *
3931 * Routines to handle XPath parser contexts *
3932 * *
3933 ************************************************************************/
3934
3935#define CHECK_CTXT(ctxt) \
3936 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00003937 __xmlRaiseError(NULL, NULL, NULL, \
3938 NULL, NULL, XML_FROM_XPATH, \
3939 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
3940 __FILE__, __LINE__, \
3941 NULL, NULL, NULL, 0, 0, \
3942 "NULL context pointer\n"); \
3943 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00003944 } \
3945
3946
3947#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00003948 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
3949 (ctxt->doc->children == NULL)) { \
3950 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003951 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00003952 }
Owen Taylor3473f882001-02-23 17:55:21 +00003953
3954
3955/**
3956 * xmlXPathNewParserContext:
3957 * @str: the XPath expression
3958 * @ctxt: the XPath context
3959 *
3960 * Create a new xmlXPathParserContext
3961 *
3962 * Returns the xmlXPathParserContext just allocated.
3963 */
3964xmlXPathParserContextPtr
3965xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3966 xmlXPathParserContextPtr ret;
3967
3968 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3969 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003970 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003971 return(NULL);
3972 }
3973 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3974 ret->cur = ret->base = str;
3975 ret->context = ctxt;
3976
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003977 ret->comp = xmlXPathNewCompExpr();
3978 if (ret->comp == NULL) {
3979 xmlFree(ret->valueTab);
3980 xmlFree(ret);
3981 return(NULL);
3982 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003983 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3984 ret->comp->dict = ctxt->dict;
3985 xmlDictReference(ret->comp->dict);
3986 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003987
3988 return(ret);
3989}
3990
3991/**
3992 * xmlXPathCompParserContext:
3993 * @comp: the XPath compiled expression
3994 * @ctxt: the XPath context
3995 *
3996 * Create a new xmlXPathParserContext when processing a compiled expression
3997 *
3998 * Returns the xmlXPathParserContext just allocated.
3999 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004000static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004001xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4002 xmlXPathParserContextPtr ret;
4003
4004 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4005 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004006 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004007 return(NULL);
4008 }
4009 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4010
Owen Taylor3473f882001-02-23 17:55:21 +00004011 /* Allocate the value stack */
4012 ret->valueTab = (xmlXPathObjectPtr *)
4013 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004014 if (ret->valueTab == NULL) {
4015 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004016 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004017 return(NULL);
4018 }
Owen Taylor3473f882001-02-23 17:55:21 +00004019 ret->valueNr = 0;
4020 ret->valueMax = 10;
4021 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004022
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004023 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004024 ret->comp = comp;
4025
Owen Taylor3473f882001-02-23 17:55:21 +00004026 return(ret);
4027}
4028
4029/**
4030 * xmlXPathFreeParserContext:
4031 * @ctxt: the context to free
4032 *
4033 * Free up an xmlXPathParserContext
4034 */
4035void
4036xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4037 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004038 xmlFree(ctxt->valueTab);
4039 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004040 if (ctxt->comp)
4041 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00004042 xmlFree(ctxt);
4043}
4044
4045/************************************************************************
4046 * *
4047 * The implicit core function library *
4048 * *
4049 ************************************************************************/
4050
Owen Taylor3473f882001-02-23 17:55:21 +00004051/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004052 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004053 * @node: a node pointer
4054 *
4055 * Function computing the beginning of the string value of the node,
4056 * used to speed up comparisons
4057 *
4058 * Returns an int usable as a hash
4059 */
4060static unsigned int
4061xmlXPathNodeValHash(xmlNodePtr node) {
4062 int len = 2;
4063 const xmlChar * string = NULL;
4064 xmlNodePtr tmp = NULL;
4065 unsigned int ret = 0;
4066
4067 if (node == NULL)
4068 return(0);
4069
Daniel Veillard9adc0462003-03-24 18:39:54 +00004070 if (node->type == XML_DOCUMENT_NODE) {
4071 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4072 if (tmp == NULL)
4073 node = node->children;
4074 else
4075 node = tmp;
4076
4077 if (node == NULL)
4078 return(0);
4079 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004080
4081 switch (node->type) {
4082 case XML_COMMENT_NODE:
4083 case XML_PI_NODE:
4084 case XML_CDATA_SECTION_NODE:
4085 case XML_TEXT_NODE:
4086 string = node->content;
4087 if (string == NULL)
4088 return(0);
4089 if (string[0] == 0)
4090 return(0);
4091 return(((unsigned int) string[0]) +
4092 (((unsigned int) string[1]) << 8));
4093 case XML_NAMESPACE_DECL:
4094 string = ((xmlNsPtr)node)->href;
4095 if (string == NULL)
4096 return(0);
4097 if (string[0] == 0)
4098 return(0);
4099 return(((unsigned int) string[0]) +
4100 (((unsigned int) string[1]) << 8));
4101 case XML_ATTRIBUTE_NODE:
4102 tmp = ((xmlAttrPtr) node)->children;
4103 break;
4104 case XML_ELEMENT_NODE:
4105 tmp = node->children;
4106 break;
4107 default:
4108 return(0);
4109 }
4110 while (tmp != NULL) {
4111 switch (tmp->type) {
4112 case XML_COMMENT_NODE:
4113 case XML_PI_NODE:
4114 case XML_CDATA_SECTION_NODE:
4115 case XML_TEXT_NODE:
4116 string = tmp->content;
4117 break;
4118 case XML_NAMESPACE_DECL:
4119 string = ((xmlNsPtr)tmp)->href;
4120 break;
4121 default:
4122 break;
4123 }
4124 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004125 if (len == 1) {
4126 return(ret + (((unsigned int) string[0]) << 8));
4127 }
4128 if (string[1] == 0) {
4129 len = 1;
4130 ret = (unsigned int) string[0];
4131 } else {
4132 return(((unsigned int) string[0]) +
4133 (((unsigned int) string[1]) << 8));
4134 }
4135 }
4136 /*
4137 * Skip to next node
4138 */
4139 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4140 if (tmp->children->type != XML_ENTITY_DECL) {
4141 tmp = tmp->children;
4142 continue;
4143 }
4144 }
4145 if (tmp == node)
4146 break;
4147
4148 if (tmp->next != NULL) {
4149 tmp = tmp->next;
4150 continue;
4151 }
4152
4153 do {
4154 tmp = tmp->parent;
4155 if (tmp == NULL)
4156 break;
4157 if (tmp == node) {
4158 tmp = NULL;
4159 break;
4160 }
4161 if (tmp->next != NULL) {
4162 tmp = tmp->next;
4163 break;
4164 }
4165 } while (tmp != NULL);
4166 }
4167 return(ret);
4168}
4169
4170/**
4171 * xmlXPathStringHash:
4172 * @string: a string
4173 *
4174 * Function computing the beginning of the string value of the node,
4175 * used to speed up comparisons
4176 *
4177 * Returns an int usable as a hash
4178 */
4179static unsigned int
4180xmlXPathStringHash(const xmlChar * string) {
4181 if (string == NULL)
4182 return((unsigned int) 0);
4183 if (string[0] == 0)
4184 return(0);
4185 return(((unsigned int) string[0]) +
4186 (((unsigned int) string[1]) << 8));
4187}
4188
4189/**
Owen Taylor3473f882001-02-23 17:55:21 +00004190 * xmlXPathCompareNodeSetFloat:
4191 * @ctxt: the XPath Parser context
4192 * @inf: less than (1) or greater than (0)
4193 * @strict: is the comparison strict
4194 * @arg: the node set
4195 * @f: the value
4196 *
4197 * Implement the compare operation between a nodeset and a number
4198 * @ns < @val (1, 1, ...
4199 * @ns <= @val (1, 0, ...
4200 * @ns > @val (0, 1, ...
4201 * @ns >= @val (0, 0, ...
4202 *
4203 * If one object to be compared is a node-set and the other is a number,
4204 * then the comparison will be true if and only if there is a node in the
4205 * node-set such that the result of performing the comparison on the number
4206 * to be compared and on the result of converting the string-value of that
4207 * node to a number using the number function is true.
4208 *
4209 * Returns 0 or 1 depending on the results of the test.
4210 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004211static int
Owen Taylor3473f882001-02-23 17:55:21 +00004212xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4213 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4214 int i, ret = 0;
4215 xmlNodeSetPtr ns;
4216 xmlChar *str2;
4217
4218 if ((f == NULL) || (arg == NULL) ||
4219 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4220 xmlXPathFreeObject(arg);
4221 xmlXPathFreeObject(f);
4222 return(0);
4223 }
4224 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004225 if (ns != NULL) {
4226 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004227 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004228 if (str2 != NULL) {
4229 valuePush(ctxt,
4230 xmlXPathNewString(str2));
4231 xmlFree(str2);
4232 xmlXPathNumberFunction(ctxt, 1);
4233 valuePush(ctxt, xmlXPathObjectCopy(f));
4234 ret = xmlXPathCompareValues(ctxt, inf, strict);
4235 if (ret)
4236 break;
4237 }
4238 }
Owen Taylor3473f882001-02-23 17:55:21 +00004239 }
4240 xmlXPathFreeObject(arg);
4241 xmlXPathFreeObject(f);
4242 return(ret);
4243}
4244
4245/**
4246 * xmlXPathCompareNodeSetString:
4247 * @ctxt: the XPath Parser context
4248 * @inf: less than (1) or greater than (0)
4249 * @strict: is the comparison strict
4250 * @arg: the node set
4251 * @s: the value
4252 *
4253 * Implement the compare operation between a nodeset and a string
4254 * @ns < @val (1, 1, ...
4255 * @ns <= @val (1, 0, ...
4256 * @ns > @val (0, 1, ...
4257 * @ns >= @val (0, 0, ...
4258 *
4259 * If one object to be compared is a node-set and the other is a string,
4260 * then the comparison will be true if and only if there is a node in
4261 * the node-set such that the result of performing the comparison on the
4262 * string-value of the node and the other string is true.
4263 *
4264 * Returns 0 or 1 depending on the results of the test.
4265 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004266static int
Owen Taylor3473f882001-02-23 17:55:21 +00004267xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4268 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4269 int i, ret = 0;
4270 xmlNodeSetPtr ns;
4271 xmlChar *str2;
4272
4273 if ((s == NULL) || (arg == NULL) ||
4274 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4275 xmlXPathFreeObject(arg);
4276 xmlXPathFreeObject(s);
4277 return(0);
4278 }
4279 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004280 if (ns != NULL) {
4281 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004282 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004283 if (str2 != NULL) {
4284 valuePush(ctxt,
4285 xmlXPathNewString(str2));
4286 xmlFree(str2);
4287 valuePush(ctxt, xmlXPathObjectCopy(s));
4288 ret = xmlXPathCompareValues(ctxt, inf, strict);
4289 if (ret)
4290 break;
4291 }
4292 }
Owen Taylor3473f882001-02-23 17:55:21 +00004293 }
4294 xmlXPathFreeObject(arg);
4295 xmlXPathFreeObject(s);
4296 return(ret);
4297}
4298
4299/**
4300 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004301 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004302 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004303 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004304 * @arg2: the second node set object
4305 *
4306 * Implement the compare operation on nodesets:
4307 *
4308 * If both objects to be compared are node-sets, then the comparison
4309 * will be true if and only if there is a node in the first node-set
4310 * and a node in the second node-set such that the result of performing
4311 * the comparison on the string-values of the two nodes is true.
4312 * ....
4313 * When neither object to be compared is a node-set and the operator
4314 * is <=, <, >= or >, then the objects are compared by converting both
4315 * objects to numbers and comparing the numbers according to IEEE 754.
4316 * ....
4317 * The number function converts its argument to a number as follows:
4318 * - a string that consists of optional whitespace followed by an
4319 * optional minus sign followed by a Number followed by whitespace
4320 * is converted to the IEEE 754 number that is nearest (according
4321 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4322 * represented by the string; any other string is converted to NaN
4323 *
4324 * Conclusion all nodes need to be converted first to their string value
4325 * and then the comparison must be done when possible
4326 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004327static int
4328xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004329 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4330 int i, j, init = 0;
4331 double val1;
4332 double *values2;
4333 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004334 xmlNodeSetPtr ns1;
4335 xmlNodeSetPtr ns2;
4336
4337 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004338 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4339 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004340 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004341 }
Owen Taylor3473f882001-02-23 17:55:21 +00004342 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004343 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4344 xmlXPathFreeObject(arg1);
4345 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004346 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004347 }
Owen Taylor3473f882001-02-23 17:55:21 +00004348
4349 ns1 = arg1->nodesetval;
4350 ns2 = arg2->nodesetval;
4351
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004352 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004353 xmlXPathFreeObject(arg1);
4354 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004355 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004356 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004357 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004358 xmlXPathFreeObject(arg1);
4359 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004360 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004361 }
Owen Taylor3473f882001-02-23 17:55:21 +00004362
4363 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4364 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004365 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004366 xmlXPathFreeObject(arg1);
4367 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004368 return(0);
4369 }
4370 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004371 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004372 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004373 continue;
4374 for (j = 0;j < ns2->nodeNr;j++) {
4375 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004376 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004377 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004378 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004379 continue;
4380 if (inf && strict)
4381 ret = (val1 < values2[j]);
4382 else if (inf && !strict)
4383 ret = (val1 <= values2[j]);
4384 else if (!inf && strict)
4385 ret = (val1 > values2[j]);
4386 else if (!inf && !strict)
4387 ret = (val1 >= values2[j]);
4388 if (ret)
4389 break;
4390 }
4391 if (ret)
4392 break;
4393 init = 1;
4394 }
4395 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004396 xmlXPathFreeObject(arg1);
4397 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004398 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004399}
4400
4401/**
4402 * xmlXPathCompareNodeSetValue:
4403 * @ctxt: the XPath Parser context
4404 * @inf: less than (1) or greater than (0)
4405 * @strict: is the comparison strict
4406 * @arg: the node set
4407 * @val: the value
4408 *
4409 * Implement the compare operation between a nodeset and a value
4410 * @ns < @val (1, 1, ...
4411 * @ns <= @val (1, 0, ...
4412 * @ns > @val (0, 1, ...
4413 * @ns >= @val (0, 0, ...
4414 *
4415 * If one object to be compared is a node-set and the other is a boolean,
4416 * then the comparison will be true if and only if the result of performing
4417 * the comparison on the boolean and on the result of converting
4418 * the node-set to a boolean using the boolean function is true.
4419 *
4420 * Returns 0 or 1 depending on the results of the test.
4421 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004422static int
Owen Taylor3473f882001-02-23 17:55:21 +00004423xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4424 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4425 if ((val == NULL) || (arg == NULL) ||
4426 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4427 return(0);
4428
4429 switch(val->type) {
4430 case XPATH_NUMBER:
4431 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4432 case XPATH_NODESET:
4433 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004434 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004435 case XPATH_STRING:
4436 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4437 case XPATH_BOOLEAN:
4438 valuePush(ctxt, arg);
4439 xmlXPathBooleanFunction(ctxt, 1);
4440 valuePush(ctxt, val);
4441 return(xmlXPathCompareValues(ctxt, inf, strict));
4442 default:
4443 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004444 }
4445 return(0);
4446}
4447
4448/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004449 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004450 * @arg: the nodeset object argument
4451 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004452 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004453 *
4454 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4455 * If one object to be compared is a node-set and the other is a string,
4456 * then the comparison will be true if and only if there is a node in
4457 * the node-set such that the result of performing the comparison on the
4458 * string-value of the node and the other string is true.
4459 *
4460 * Returns 0 or 1 depending on the results of the test.
4461 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004462static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004463xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004464{
Owen Taylor3473f882001-02-23 17:55:21 +00004465 int i;
4466 xmlNodeSetPtr ns;
4467 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004468 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004469
4470 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004471 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4472 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004473 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004474 /*
4475 * A NULL nodeset compared with a string is always false
4476 * (since there is no node equal, and no node not equal)
4477 */
4478 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004479 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004480 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004481 for (i = 0; i < ns->nodeNr; i++) {
4482 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4483 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4484 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4485 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004486 if (neq)
4487 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004488 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004489 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4490 if (neq)
4491 continue;
4492 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004493 } else if (neq) {
4494 if (str2 != NULL)
4495 xmlFree(str2);
4496 return (1);
4497 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004498 if (str2 != NULL)
4499 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004500 } else if (neq)
4501 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004502 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004503 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004504}
4505
4506/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004507 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004508 * @arg: the nodeset object argument
4509 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004510 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004511 *
4512 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4513 * If one object to be compared is a node-set and the other is a number,
4514 * then the comparison will be true if and only if there is a node in
4515 * the node-set such that the result of performing the comparison on the
4516 * number to be compared and on the result of converting the string-value
4517 * of that node to a number using the number function is true.
4518 *
4519 * Returns 0 or 1 depending on the results of the test.
4520 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004521static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004522xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4523 xmlXPathObjectPtr arg, double f, int neq) {
4524 int i, ret=0;
4525 xmlNodeSetPtr ns;
4526 xmlChar *str2;
4527 xmlXPathObjectPtr val;
4528 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004529
4530 if ((arg == NULL) ||
4531 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4532 return(0);
4533
William M. Brack0c022ad2002-07-12 00:56:01 +00004534 ns = arg->nodesetval;
4535 if (ns != NULL) {
4536 for (i=0;i<ns->nodeNr;i++) {
4537 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4538 if (str2 != NULL) {
4539 valuePush(ctxt, xmlXPathNewString(str2));
4540 xmlFree(str2);
4541 xmlXPathNumberFunction(ctxt, 1);
4542 val = valuePop(ctxt);
4543 v = val->floatval;
4544 xmlXPathFreeObject(val);
4545 if (!xmlXPathIsNaN(v)) {
4546 if ((!neq) && (v==f)) {
4547 ret = 1;
4548 break;
4549 } else if ((neq) && (v!=f)) {
4550 ret = 1;
4551 break;
4552 }
4553 }
4554 }
4555 }
4556 }
4557
4558 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004559}
4560
4561
4562/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004563 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004564 * @arg1: first nodeset object argument
4565 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004566 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004567 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004568 * Implement the equal / not equal operation on XPath nodesets:
4569 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004570 * If both objects to be compared are node-sets, then the comparison
4571 * will be true if and only if there is a node in the first node-set and
4572 * a node in the second node-set such that the result of performing the
4573 * comparison on the string-values of the two nodes is true.
4574 *
4575 * (needless to say, this is a costly operation)
4576 *
4577 * Returns 0 or 1 depending on the results of the test.
4578 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004579static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004580xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004581 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004582 unsigned int *hashs1;
4583 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004584 xmlChar **values1;
4585 xmlChar **values2;
4586 int ret = 0;
4587 xmlNodeSetPtr ns1;
4588 xmlNodeSetPtr ns2;
4589
4590 if ((arg1 == NULL) ||
4591 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4592 return(0);
4593 if ((arg2 == NULL) ||
4594 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4595 return(0);
4596
4597 ns1 = arg1->nodesetval;
4598 ns2 = arg2->nodesetval;
4599
Daniel Veillard911f49a2001-04-07 15:39:35 +00004600 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004601 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004602 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004603 return(0);
4604
4605 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004606 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004607 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004608 if (neq == 0)
4609 for (i = 0;i < ns1->nodeNr;i++)
4610 for (j = 0;j < ns2->nodeNr;j++)
4611 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4612 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004613
4614 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004615 if (values1 == NULL) {
4616 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004617 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004618 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004619 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4620 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004621 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004622 xmlFree(values1);
4623 return(0);
4624 }
Owen Taylor3473f882001-02-23 17:55:21 +00004625 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4626 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4627 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004628 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004629 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004630 xmlFree(values1);
4631 return(0);
4632 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004633 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4634 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004635 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004636 xmlFree(hashs1);
4637 xmlFree(values1);
4638 xmlFree(values2);
4639 return(0);
4640 }
Owen Taylor3473f882001-02-23 17:55:21 +00004641 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4642 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004643 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004644 for (j = 0;j < ns2->nodeNr;j++) {
4645 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004646 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004647 if (hashs1[i] != hashs2[j]) {
4648 if (neq) {
4649 ret = 1;
4650 break;
4651 }
4652 }
4653 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004654 if (values1[i] == NULL)
4655 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4656 if (values2[j] == NULL)
4657 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004658 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004659 if (ret)
4660 break;
4661 }
Owen Taylor3473f882001-02-23 17:55:21 +00004662 }
4663 if (ret)
4664 break;
4665 }
4666 for (i = 0;i < ns1->nodeNr;i++)
4667 if (values1[i] != NULL)
4668 xmlFree(values1[i]);
4669 for (j = 0;j < ns2->nodeNr;j++)
4670 if (values2[j] != NULL)
4671 xmlFree(values2[j]);
4672 xmlFree(values1);
4673 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004674 xmlFree(hashs1);
4675 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004676 return(ret);
4677}
4678
William M. Brack0c022ad2002-07-12 00:56:01 +00004679static int
4680xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4681 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004682 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004683 /*
4684 *At this point we are assured neither arg1 nor arg2
4685 *is a nodeset, so we can just pick the appropriate routine.
4686 */
Owen Taylor3473f882001-02-23 17:55:21 +00004687 switch (arg1->type) {
4688 case XPATH_UNDEFINED:
4689#ifdef DEBUG_EXPR
4690 xmlGenericError(xmlGenericErrorContext,
4691 "Equal: undefined\n");
4692#endif
4693 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004694 case XPATH_BOOLEAN:
4695 switch (arg2->type) {
4696 case XPATH_UNDEFINED:
4697#ifdef DEBUG_EXPR
4698 xmlGenericError(xmlGenericErrorContext,
4699 "Equal: undefined\n");
4700#endif
4701 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004702 case XPATH_BOOLEAN:
4703#ifdef DEBUG_EXPR
4704 xmlGenericError(xmlGenericErrorContext,
4705 "Equal: %d boolean %d \n",
4706 arg1->boolval, arg2->boolval);
4707#endif
4708 ret = (arg1->boolval == arg2->boolval);
4709 break;
4710 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004711 ret = (arg1->boolval ==
4712 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004713 break;
4714 case XPATH_STRING:
4715 if ((arg2->stringval == NULL) ||
4716 (arg2->stringval[0] == 0)) ret = 0;
4717 else
4718 ret = 1;
4719 ret = (arg1->boolval == ret);
4720 break;
4721 case XPATH_USERS:
4722 case XPATH_POINT:
4723 case XPATH_RANGE:
4724 case XPATH_LOCATIONSET:
4725 TODO
4726 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004727 case XPATH_NODESET:
4728 case XPATH_XSLT_TREE:
4729 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004730 }
4731 break;
4732 case XPATH_NUMBER:
4733 switch (arg2->type) {
4734 case XPATH_UNDEFINED:
4735#ifdef DEBUG_EXPR
4736 xmlGenericError(xmlGenericErrorContext,
4737 "Equal: undefined\n");
4738#endif
4739 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004740 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004741 ret = (arg2->boolval==
4742 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004743 break;
4744 case XPATH_STRING:
4745 valuePush(ctxt, arg2);
4746 xmlXPathNumberFunction(ctxt, 1);
4747 arg2 = valuePop(ctxt);
4748 /* no break on purpose */
4749 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004750 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004751 if (xmlXPathIsNaN(arg1->floatval) ||
4752 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004753 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004754 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4755 if (xmlXPathIsInf(arg2->floatval) == 1)
4756 ret = 1;
4757 else
4758 ret = 0;
4759 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4760 if (xmlXPathIsInf(arg2->floatval) == -1)
4761 ret = 1;
4762 else
4763 ret = 0;
4764 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4765 if (xmlXPathIsInf(arg1->floatval) == 1)
4766 ret = 1;
4767 else
4768 ret = 0;
4769 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4770 if (xmlXPathIsInf(arg1->floatval) == -1)
4771 ret = 1;
4772 else
4773 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004774 } else {
4775 ret = (arg1->floatval == arg2->floatval);
4776 }
Owen Taylor3473f882001-02-23 17:55:21 +00004777 break;
4778 case XPATH_USERS:
4779 case XPATH_POINT:
4780 case XPATH_RANGE:
4781 case XPATH_LOCATIONSET:
4782 TODO
4783 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004784 case XPATH_NODESET:
4785 case XPATH_XSLT_TREE:
4786 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004787 }
4788 break;
4789 case XPATH_STRING:
4790 switch (arg2->type) {
4791 case XPATH_UNDEFINED:
4792#ifdef DEBUG_EXPR
4793 xmlGenericError(xmlGenericErrorContext,
4794 "Equal: undefined\n");
4795#endif
4796 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004797 case XPATH_BOOLEAN:
4798 if ((arg1->stringval == NULL) ||
4799 (arg1->stringval[0] == 0)) ret = 0;
4800 else
4801 ret = 1;
4802 ret = (arg2->boolval == ret);
4803 break;
4804 case XPATH_STRING:
4805 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4806 break;
4807 case XPATH_NUMBER:
4808 valuePush(ctxt, arg1);
4809 xmlXPathNumberFunction(ctxt, 1);
4810 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004811 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004812 if (xmlXPathIsNaN(arg1->floatval) ||
4813 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004814 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004815 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4816 if (xmlXPathIsInf(arg2->floatval) == 1)
4817 ret = 1;
4818 else
4819 ret = 0;
4820 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4821 if (xmlXPathIsInf(arg2->floatval) == -1)
4822 ret = 1;
4823 else
4824 ret = 0;
4825 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4826 if (xmlXPathIsInf(arg1->floatval) == 1)
4827 ret = 1;
4828 else
4829 ret = 0;
4830 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4831 if (xmlXPathIsInf(arg1->floatval) == -1)
4832 ret = 1;
4833 else
4834 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004835 } else {
4836 ret = (arg1->floatval == arg2->floatval);
4837 }
Owen Taylor3473f882001-02-23 17:55:21 +00004838 break;
4839 case XPATH_USERS:
4840 case XPATH_POINT:
4841 case XPATH_RANGE:
4842 case XPATH_LOCATIONSET:
4843 TODO
4844 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004845 case XPATH_NODESET:
4846 case XPATH_XSLT_TREE:
4847 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004848 }
4849 break;
4850 case XPATH_USERS:
4851 case XPATH_POINT:
4852 case XPATH_RANGE:
4853 case XPATH_LOCATIONSET:
4854 TODO
4855 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004856 case XPATH_NODESET:
4857 case XPATH_XSLT_TREE:
4858 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004859 }
4860 xmlXPathFreeObject(arg1);
4861 xmlXPathFreeObject(arg2);
4862 return(ret);
4863}
4864
William M. Brack0c022ad2002-07-12 00:56:01 +00004865/**
4866 * xmlXPathEqualValues:
4867 * @ctxt: the XPath Parser context
4868 *
4869 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4870 *
4871 * Returns 0 or 1 depending on the results of the test.
4872 */
4873int
4874xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4875 xmlXPathObjectPtr arg1, arg2, argtmp;
4876 int ret = 0;
4877
Daniel Veillard6128c012004-11-08 17:16:15 +00004878 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004879 arg2 = valuePop(ctxt);
4880 arg1 = valuePop(ctxt);
4881 if ((arg1 == NULL) || (arg2 == NULL)) {
4882 if (arg1 != NULL)
4883 xmlXPathFreeObject(arg1);
4884 else
4885 xmlXPathFreeObject(arg2);
4886 XP_ERROR0(XPATH_INVALID_OPERAND);
4887 }
4888
4889 if (arg1 == arg2) {
4890#ifdef DEBUG_EXPR
4891 xmlGenericError(xmlGenericErrorContext,
4892 "Equal: by pointer\n");
4893#endif
4894 return(1);
4895 }
4896
4897 /*
4898 *If either argument is a nodeset, it's a 'special case'
4899 */
4900 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4901 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4902 /*
4903 *Hack it to assure arg1 is the nodeset
4904 */
4905 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4906 argtmp = arg2;
4907 arg2 = arg1;
4908 arg1 = argtmp;
4909 }
4910 switch (arg2->type) {
4911 case XPATH_UNDEFINED:
4912#ifdef DEBUG_EXPR
4913 xmlGenericError(xmlGenericErrorContext,
4914 "Equal: undefined\n");
4915#endif
4916 break;
4917 case XPATH_NODESET:
4918 case XPATH_XSLT_TREE:
4919 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4920 break;
4921 case XPATH_BOOLEAN:
4922 if ((arg1->nodesetval == NULL) ||
4923 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4924 else
4925 ret = 1;
4926 ret = (ret == arg2->boolval);
4927 break;
4928 case XPATH_NUMBER:
4929 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4930 break;
4931 case XPATH_STRING:
4932 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4933 break;
4934 case XPATH_USERS:
4935 case XPATH_POINT:
4936 case XPATH_RANGE:
4937 case XPATH_LOCATIONSET:
4938 TODO
4939 break;
4940 }
4941 xmlXPathFreeObject(arg1);
4942 xmlXPathFreeObject(arg2);
4943 return(ret);
4944 }
4945
4946 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4947}
4948
4949/**
4950 * xmlXPathNotEqualValues:
4951 * @ctxt: the XPath Parser context
4952 *
4953 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4954 *
4955 * Returns 0 or 1 depending on the results of the test.
4956 */
4957int
4958xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4959 xmlXPathObjectPtr arg1, arg2, argtmp;
4960 int ret = 0;
4961
Daniel Veillard6128c012004-11-08 17:16:15 +00004962 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004963 arg2 = valuePop(ctxt);
4964 arg1 = valuePop(ctxt);
4965 if ((arg1 == NULL) || (arg2 == NULL)) {
4966 if (arg1 != NULL)
4967 xmlXPathFreeObject(arg1);
4968 else
4969 xmlXPathFreeObject(arg2);
4970 XP_ERROR0(XPATH_INVALID_OPERAND);
4971 }
4972
4973 if (arg1 == arg2) {
4974#ifdef DEBUG_EXPR
4975 xmlGenericError(xmlGenericErrorContext,
4976 "NotEqual: by pointer\n");
4977#endif
4978 return(0);
4979 }
4980
4981 /*
4982 *If either argument is a nodeset, it's a 'special case'
4983 */
4984 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4985 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4986 /*
4987 *Hack it to assure arg1 is the nodeset
4988 */
4989 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4990 argtmp = arg2;
4991 arg2 = arg1;
4992 arg1 = argtmp;
4993 }
4994 switch (arg2->type) {
4995 case XPATH_UNDEFINED:
4996#ifdef DEBUG_EXPR
4997 xmlGenericError(xmlGenericErrorContext,
4998 "NotEqual: undefined\n");
4999#endif
5000 break;
5001 case XPATH_NODESET:
5002 case XPATH_XSLT_TREE:
5003 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5004 break;
5005 case XPATH_BOOLEAN:
5006 if ((arg1->nodesetval == NULL) ||
5007 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5008 else
5009 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005010 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005011 break;
5012 case XPATH_NUMBER:
5013 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5014 break;
5015 case XPATH_STRING:
5016 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5017 break;
5018 case XPATH_USERS:
5019 case XPATH_POINT:
5020 case XPATH_RANGE:
5021 case XPATH_LOCATIONSET:
5022 TODO
5023 break;
5024 }
5025 xmlXPathFreeObject(arg1);
5026 xmlXPathFreeObject(arg2);
5027 return(ret);
5028 }
5029
5030 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5031}
Owen Taylor3473f882001-02-23 17:55:21 +00005032
5033/**
5034 * xmlXPathCompareValues:
5035 * @ctxt: the XPath Parser context
5036 * @inf: less than (1) or greater than (0)
5037 * @strict: is the comparison strict
5038 *
5039 * Implement the compare operation on XPath objects:
5040 * @arg1 < @arg2 (1, 1, ...
5041 * @arg1 <= @arg2 (1, 0, ...
5042 * @arg1 > @arg2 (0, 1, ...
5043 * @arg1 >= @arg2 (0, 0, ...
5044 *
5045 * When neither object to be compared is a node-set and the operator is
5046 * <=, <, >=, >, then the objects are compared by converted both objects
5047 * to numbers and comparing the numbers according to IEEE 754. The <
5048 * comparison will be true if and only if the first number is less than the
5049 * second number. The <= comparison will be true if and only if the first
5050 * number is less than or equal to the second number. The > comparison
5051 * will be true if and only if the first number is greater than the second
5052 * number. The >= comparison will be true if and only if the first number
5053 * is greater than or equal to the second number.
5054 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005055 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005056 */
5057int
5058xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005059 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005060 xmlXPathObjectPtr arg1, arg2;
5061
Daniel Veillard6128c012004-11-08 17:16:15 +00005062 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005063 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005064 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005065 if ((arg1 == NULL) || (arg2 == NULL)) {
5066 if (arg1 != NULL)
5067 xmlXPathFreeObject(arg1);
5068 else
5069 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005070 XP_ERROR0(XPATH_INVALID_OPERAND);
5071 }
5072
William M. Brack0c022ad2002-07-12 00:56:01 +00005073 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5074 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5075 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5076 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005077 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005078 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005079 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005080 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5081 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005082 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005083 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5084 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005085 }
5086 }
5087 return(ret);
5088 }
5089
5090 if (arg1->type != XPATH_NUMBER) {
5091 valuePush(ctxt, arg1);
5092 xmlXPathNumberFunction(ctxt, 1);
5093 arg1 = valuePop(ctxt);
5094 }
5095 if (arg1->type != XPATH_NUMBER) {
5096 xmlXPathFreeObject(arg1);
5097 xmlXPathFreeObject(arg2);
5098 XP_ERROR0(XPATH_INVALID_OPERAND);
5099 }
5100 if (arg2->type != XPATH_NUMBER) {
5101 valuePush(ctxt, arg2);
5102 xmlXPathNumberFunction(ctxt, 1);
5103 arg2 = valuePop(ctxt);
5104 }
5105 if (arg2->type != XPATH_NUMBER) {
5106 xmlXPathFreeObject(arg1);
5107 xmlXPathFreeObject(arg2);
5108 XP_ERROR0(XPATH_INVALID_OPERAND);
5109 }
5110 /*
5111 * Add tests for infinity and nan
5112 * => feedback on 3.4 for Inf and NaN
5113 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005114 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005115 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005116 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005117 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005118 arg1i=xmlXPathIsInf(arg1->floatval);
5119 arg2i=xmlXPathIsInf(arg2->floatval);
5120 if (inf && strict) {
5121 if ((arg1i == -1 && arg2i != -1) ||
5122 (arg2i == 1 && arg1i != 1)) {
5123 ret = 1;
5124 } else if (arg1i == 0 && arg2i == 0) {
5125 ret = (arg1->floatval < arg2->floatval);
5126 } else {
5127 ret = 0;
5128 }
5129 }
5130 else if (inf && !strict) {
5131 if (arg1i == -1 || arg2i == 1) {
5132 ret = 1;
5133 } else if (arg1i == 0 && arg2i == 0) {
5134 ret = (arg1->floatval <= arg2->floatval);
5135 } else {
5136 ret = 0;
5137 }
5138 }
5139 else if (!inf && strict) {
5140 if ((arg1i == 1 && arg2i != 1) ||
5141 (arg2i == -1 && arg1i != -1)) {
5142 ret = 1;
5143 } else if (arg1i == 0 && arg2i == 0) {
5144 ret = (arg1->floatval > arg2->floatval);
5145 } else {
5146 ret = 0;
5147 }
5148 }
5149 else if (!inf && !strict) {
5150 if (arg1i == 1 || arg2i == -1) {
5151 ret = 1;
5152 } else if (arg1i == 0 && arg2i == 0) {
5153 ret = (arg1->floatval >= arg2->floatval);
5154 } else {
5155 ret = 0;
5156 }
5157 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005158 }
Owen Taylor3473f882001-02-23 17:55:21 +00005159 xmlXPathFreeObject(arg1);
5160 xmlXPathFreeObject(arg2);
5161 return(ret);
5162}
5163
5164/**
5165 * xmlXPathValueFlipSign:
5166 * @ctxt: the XPath Parser context
5167 *
5168 * Implement the unary - operation on an XPath object
5169 * The numeric operators convert their operands to numbers as if
5170 * by calling the number function.
5171 */
5172void
5173xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005174 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005175 CAST_TO_NUMBER;
5176 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005177 if (xmlXPathIsNaN(ctxt->value->floatval))
5178 ctxt->value->floatval=xmlXPathNAN;
5179 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5180 ctxt->value->floatval=xmlXPathNINF;
5181 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5182 ctxt->value->floatval=xmlXPathPINF;
5183 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005184 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5185 ctxt->value->floatval = xmlXPathNZERO;
5186 else
5187 ctxt->value->floatval = 0;
5188 }
5189 else
5190 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005191}
5192
5193/**
5194 * xmlXPathAddValues:
5195 * @ctxt: the XPath Parser context
5196 *
5197 * Implement the add operation on XPath objects:
5198 * The numeric operators convert their operands to numbers as if
5199 * by calling the number function.
5200 */
5201void
5202xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5203 xmlXPathObjectPtr arg;
5204 double val;
5205
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005206 arg = valuePop(ctxt);
5207 if (arg == NULL)
5208 XP_ERROR(XPATH_INVALID_OPERAND);
5209 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005210 xmlXPathFreeObject(arg);
5211
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005212 CAST_TO_NUMBER;
5213 CHECK_TYPE(XPATH_NUMBER);
5214 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005215}
5216
5217/**
5218 * xmlXPathSubValues:
5219 * @ctxt: the XPath Parser context
5220 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005221 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005222 * The numeric operators convert their operands to numbers as if
5223 * by calling the number function.
5224 */
5225void
5226xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5227 xmlXPathObjectPtr arg;
5228 double val;
5229
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005230 arg = valuePop(ctxt);
5231 if (arg == NULL)
5232 XP_ERROR(XPATH_INVALID_OPERAND);
5233 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005234 xmlXPathFreeObject(arg);
5235
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005236 CAST_TO_NUMBER;
5237 CHECK_TYPE(XPATH_NUMBER);
5238 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005239}
5240
5241/**
5242 * xmlXPathMultValues:
5243 * @ctxt: the XPath Parser context
5244 *
5245 * Implement the multiply operation on XPath objects:
5246 * The numeric operators convert their operands to numbers as if
5247 * by calling the number function.
5248 */
5249void
5250xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5251 xmlXPathObjectPtr arg;
5252 double val;
5253
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005254 arg = valuePop(ctxt);
5255 if (arg == NULL)
5256 XP_ERROR(XPATH_INVALID_OPERAND);
5257 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005258 xmlXPathFreeObject(arg);
5259
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005260 CAST_TO_NUMBER;
5261 CHECK_TYPE(XPATH_NUMBER);
5262 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005263}
5264
5265/**
5266 * xmlXPathDivValues:
5267 * @ctxt: the XPath Parser context
5268 *
5269 * Implement the div operation on XPath objects @arg1 / @arg2:
5270 * The numeric operators convert their operands to numbers as if
5271 * by calling the number function.
5272 */
5273void
5274xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5275 xmlXPathObjectPtr arg;
5276 double val;
5277
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005278 arg = valuePop(ctxt);
5279 if (arg == NULL)
5280 XP_ERROR(XPATH_INVALID_OPERAND);
5281 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005282 xmlXPathFreeObject(arg);
5283
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005284 CAST_TO_NUMBER;
5285 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005286 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5287 ctxt->value->floatval = xmlXPathNAN;
5288 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005289 if (ctxt->value->floatval == 0)
5290 ctxt->value->floatval = xmlXPathNAN;
5291 else if (ctxt->value->floatval > 0)
5292 ctxt->value->floatval = xmlXPathNINF;
5293 else if (ctxt->value->floatval < 0)
5294 ctxt->value->floatval = xmlXPathPINF;
5295 }
5296 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005297 if (ctxt->value->floatval == 0)
5298 ctxt->value->floatval = xmlXPathNAN;
5299 else if (ctxt->value->floatval > 0)
5300 ctxt->value->floatval = xmlXPathPINF;
5301 else if (ctxt->value->floatval < 0)
5302 ctxt->value->floatval = xmlXPathNINF;
5303 } else
5304 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005305}
5306
5307/**
5308 * xmlXPathModValues:
5309 * @ctxt: the XPath Parser context
5310 *
5311 * Implement the mod operation on XPath objects: @arg1 / @arg2
5312 * The numeric operators convert their operands to numbers as if
5313 * by calling the number function.
5314 */
5315void
5316xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5317 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005318 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005319
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005320 arg = valuePop(ctxt);
5321 if (arg == NULL)
5322 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005323 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005324 xmlXPathFreeObject(arg);
5325
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005326 CAST_TO_NUMBER;
5327 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005328 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005329 if (arg2 == 0)
5330 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005331 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005332 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005333 }
Owen Taylor3473f882001-02-23 17:55:21 +00005334}
5335
5336/************************************************************************
5337 * *
5338 * The traversal functions *
5339 * *
5340 ************************************************************************/
5341
Owen Taylor3473f882001-02-23 17:55:21 +00005342/*
5343 * A traversal function enumerates nodes along an axis.
5344 * Initially it must be called with NULL, and it indicates
5345 * termination on the axis by returning NULL.
5346 */
5347typedef xmlNodePtr (*xmlXPathTraversalFunction)
5348 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5349
5350/**
5351 * xmlXPathNextSelf:
5352 * @ctxt: the XPath Parser context
5353 * @cur: the current node in the traversal
5354 *
5355 * Traversal function for the "self" direction
5356 * The self axis contains just the context node itself
5357 *
5358 * Returns the next element following that axis
5359 */
5360xmlNodePtr
5361xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005362 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005363 if (cur == NULL)
5364 return(ctxt->context->node);
5365 return(NULL);
5366}
5367
5368/**
5369 * xmlXPathNextChild:
5370 * @ctxt: the XPath Parser context
5371 * @cur: the current node in the traversal
5372 *
5373 * Traversal function for the "child" direction
5374 * The child axis contains the children of the context node in document order.
5375 *
5376 * Returns the next element following that axis
5377 */
5378xmlNodePtr
5379xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005380 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005381 if (cur == NULL) {
5382 if (ctxt->context->node == NULL) return(NULL);
5383 switch (ctxt->context->node->type) {
5384 case XML_ELEMENT_NODE:
5385 case XML_TEXT_NODE:
5386 case XML_CDATA_SECTION_NODE:
5387 case XML_ENTITY_REF_NODE:
5388 case XML_ENTITY_NODE:
5389 case XML_PI_NODE:
5390 case XML_COMMENT_NODE:
5391 case XML_NOTATION_NODE:
5392 case XML_DTD_NODE:
5393 return(ctxt->context->node->children);
5394 case XML_DOCUMENT_NODE:
5395 case XML_DOCUMENT_TYPE_NODE:
5396 case XML_DOCUMENT_FRAG_NODE:
5397 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005398#ifdef LIBXML_DOCB_ENABLED
5399 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005400#endif
5401 return(((xmlDocPtr) ctxt->context->node)->children);
5402 case XML_ELEMENT_DECL:
5403 case XML_ATTRIBUTE_DECL:
5404 case XML_ENTITY_DECL:
5405 case XML_ATTRIBUTE_NODE:
5406 case XML_NAMESPACE_DECL:
5407 case XML_XINCLUDE_START:
5408 case XML_XINCLUDE_END:
5409 return(NULL);
5410 }
5411 return(NULL);
5412 }
5413 if ((cur->type == XML_DOCUMENT_NODE) ||
5414 (cur->type == XML_HTML_DOCUMENT_NODE))
5415 return(NULL);
5416 return(cur->next);
5417}
5418
5419/**
5420 * xmlXPathNextDescendant:
5421 * @ctxt: the XPath Parser context
5422 * @cur: the current node in the traversal
5423 *
5424 * Traversal function for the "descendant" direction
5425 * the descendant axis contains the descendants of the context node in document
5426 * order; a descendant is a child or a child of a child and so on.
5427 *
5428 * Returns the next element following that axis
5429 */
5430xmlNodePtr
5431xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005432 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005433 if (cur == NULL) {
5434 if (ctxt->context->node == NULL)
5435 return(NULL);
5436 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5437 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5438 return(NULL);
5439
5440 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5441 return(ctxt->context->doc->children);
5442 return(ctxt->context->node->children);
5443 }
5444
Daniel Veillard567e1b42001-08-01 15:53:47 +00005445 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005446 /*
5447 * Do not descend on entities declarations
5448 */
5449 if (cur->children->type != XML_ENTITY_DECL) {
5450 cur = cur->children;
5451 /*
5452 * Skip DTDs
5453 */
5454 if (cur->type != XML_DTD_NODE)
5455 return(cur);
5456 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005457 }
5458
5459 if (cur == ctxt->context->node) return(NULL);
5460
Daniel Veillard68e9e742002-11-16 15:35:11 +00005461 while (cur->next != NULL) {
5462 cur = cur->next;
5463 if ((cur->type != XML_ENTITY_DECL) &&
5464 (cur->type != XML_DTD_NODE))
5465 return(cur);
5466 }
Owen Taylor3473f882001-02-23 17:55:21 +00005467
5468 do {
5469 cur = cur->parent;
5470 if (cur == NULL) return(NULL);
5471 if (cur == ctxt->context->node) return(NULL);
5472 if (cur->next != NULL) {
5473 cur = cur->next;
5474 return(cur);
5475 }
5476 } while (cur != NULL);
5477 return(cur);
5478}
5479
5480/**
5481 * xmlXPathNextDescendantOrSelf:
5482 * @ctxt: the XPath Parser context
5483 * @cur: the current node in the traversal
5484 *
5485 * Traversal function for the "descendant-or-self" direction
5486 * the descendant-or-self axis contains the context node and the descendants
5487 * of the context node in document order; thus the context node is the first
5488 * node on the axis, and the first child of the context node is the second node
5489 * on the axis
5490 *
5491 * Returns the next element following that axis
5492 */
5493xmlNodePtr
5494xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005495 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005496 if (cur == NULL) {
5497 if (ctxt->context->node == NULL)
5498 return(NULL);
5499 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5500 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5501 return(NULL);
5502 return(ctxt->context->node);
5503 }
5504
5505 return(xmlXPathNextDescendant(ctxt, cur));
5506}
5507
5508/**
5509 * xmlXPathNextParent:
5510 * @ctxt: the XPath Parser context
5511 * @cur: the current node in the traversal
5512 *
5513 * Traversal function for the "parent" direction
5514 * The parent axis contains the parent of the context node, if there is one.
5515 *
5516 * Returns the next element following that axis
5517 */
5518xmlNodePtr
5519xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005520 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005521 /*
5522 * the parent of an attribute or namespace node is the element
5523 * to which the attribute or namespace node is attached
5524 * Namespace handling !!!
5525 */
5526 if (cur == NULL) {
5527 if (ctxt->context->node == NULL) return(NULL);
5528 switch (ctxt->context->node->type) {
5529 case XML_ELEMENT_NODE:
5530 case XML_TEXT_NODE:
5531 case XML_CDATA_SECTION_NODE:
5532 case XML_ENTITY_REF_NODE:
5533 case XML_ENTITY_NODE:
5534 case XML_PI_NODE:
5535 case XML_COMMENT_NODE:
5536 case XML_NOTATION_NODE:
5537 case XML_DTD_NODE:
5538 case XML_ELEMENT_DECL:
5539 case XML_ATTRIBUTE_DECL:
5540 case XML_XINCLUDE_START:
5541 case XML_XINCLUDE_END:
5542 case XML_ENTITY_DECL:
5543 if (ctxt->context->node->parent == NULL)
5544 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005545 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005546 ((ctxt->context->node->parent->name[0] == ' ') ||
5547 (xmlStrEqual(ctxt->context->node->parent->name,
5548 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005549 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005550 return(ctxt->context->node->parent);
5551 case XML_ATTRIBUTE_NODE: {
5552 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5553
5554 return(att->parent);
5555 }
5556 case XML_DOCUMENT_NODE:
5557 case XML_DOCUMENT_TYPE_NODE:
5558 case XML_DOCUMENT_FRAG_NODE:
5559 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005560#ifdef LIBXML_DOCB_ENABLED
5561 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005562#endif
5563 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005564 case XML_NAMESPACE_DECL: {
5565 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5566
5567 if ((ns->next != NULL) &&
5568 (ns->next->type != XML_NAMESPACE_DECL))
5569 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005570 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005571 }
Owen Taylor3473f882001-02-23 17:55:21 +00005572 }
5573 }
5574 return(NULL);
5575}
5576
5577/**
5578 * xmlXPathNextAncestor:
5579 * @ctxt: the XPath Parser context
5580 * @cur: the current node in the traversal
5581 *
5582 * Traversal function for the "ancestor" direction
5583 * the ancestor axis contains the ancestors of the context node; the ancestors
5584 * of the context node consist of the parent of context node and the parent's
5585 * parent and so on; the nodes are ordered in reverse document order; thus the
5586 * parent is the first node on the axis, and the parent's parent is the second
5587 * node on the axis
5588 *
5589 * Returns the next element following that axis
5590 */
5591xmlNodePtr
5592xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005593 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005594 /*
5595 * the parent of an attribute or namespace node is the element
5596 * to which the attribute or namespace node is attached
5597 * !!!!!!!!!!!!!
5598 */
5599 if (cur == NULL) {
5600 if (ctxt->context->node == NULL) return(NULL);
5601 switch (ctxt->context->node->type) {
5602 case XML_ELEMENT_NODE:
5603 case XML_TEXT_NODE:
5604 case XML_CDATA_SECTION_NODE:
5605 case XML_ENTITY_REF_NODE:
5606 case XML_ENTITY_NODE:
5607 case XML_PI_NODE:
5608 case XML_COMMENT_NODE:
5609 case XML_DTD_NODE:
5610 case XML_ELEMENT_DECL:
5611 case XML_ATTRIBUTE_DECL:
5612 case XML_ENTITY_DECL:
5613 case XML_NOTATION_NODE:
5614 case XML_XINCLUDE_START:
5615 case XML_XINCLUDE_END:
5616 if (ctxt->context->node->parent == NULL)
5617 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005618 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005619 ((ctxt->context->node->parent->name[0] == ' ') ||
5620 (xmlStrEqual(ctxt->context->node->parent->name,
5621 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005622 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005623 return(ctxt->context->node->parent);
5624 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005625 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005626
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005627 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005628 }
5629 case XML_DOCUMENT_NODE:
5630 case XML_DOCUMENT_TYPE_NODE:
5631 case XML_DOCUMENT_FRAG_NODE:
5632 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005633#ifdef LIBXML_DOCB_ENABLED
5634 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005635#endif
5636 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005637 case XML_NAMESPACE_DECL: {
5638 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5639
5640 if ((ns->next != NULL) &&
5641 (ns->next->type != XML_NAMESPACE_DECL))
5642 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005643 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005644 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005645 }
Owen Taylor3473f882001-02-23 17:55:21 +00005646 }
5647 return(NULL);
5648 }
5649 if (cur == ctxt->context->doc->children)
5650 return((xmlNodePtr) ctxt->context->doc);
5651 if (cur == (xmlNodePtr) ctxt->context->doc)
5652 return(NULL);
5653 switch (cur->type) {
5654 case XML_ELEMENT_NODE:
5655 case XML_TEXT_NODE:
5656 case XML_CDATA_SECTION_NODE:
5657 case XML_ENTITY_REF_NODE:
5658 case XML_ENTITY_NODE:
5659 case XML_PI_NODE:
5660 case XML_COMMENT_NODE:
5661 case XML_NOTATION_NODE:
5662 case XML_DTD_NODE:
5663 case XML_ELEMENT_DECL:
5664 case XML_ATTRIBUTE_DECL:
5665 case XML_ENTITY_DECL:
5666 case XML_XINCLUDE_START:
5667 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005668 if (cur->parent == NULL)
5669 return(NULL);
5670 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005671 ((cur->parent->name[0] == ' ') ||
5672 (xmlStrEqual(cur->parent->name,
5673 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005674 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005675 return(cur->parent);
5676 case XML_ATTRIBUTE_NODE: {
5677 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5678
5679 return(att->parent);
5680 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005681 case XML_NAMESPACE_DECL: {
5682 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5683
5684 if ((ns->next != NULL) &&
5685 (ns->next->type != XML_NAMESPACE_DECL))
5686 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005687 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005688 return(NULL);
5689 }
Owen Taylor3473f882001-02-23 17:55:21 +00005690 case XML_DOCUMENT_NODE:
5691 case XML_DOCUMENT_TYPE_NODE:
5692 case XML_DOCUMENT_FRAG_NODE:
5693 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005694#ifdef LIBXML_DOCB_ENABLED
5695 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005696#endif
5697 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005698 }
5699 return(NULL);
5700}
5701
5702/**
5703 * xmlXPathNextAncestorOrSelf:
5704 * @ctxt: the XPath Parser context
5705 * @cur: the current node in the traversal
5706 *
5707 * Traversal function for the "ancestor-or-self" direction
5708 * he ancestor-or-self axis contains the context node and ancestors of
5709 * the context node in reverse document order; thus the context node is
5710 * the first node on the axis, and the context node's parent the second;
5711 * parent here is defined the same as with the parent axis.
5712 *
5713 * Returns the next element following that axis
5714 */
5715xmlNodePtr
5716xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005717 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005718 if (cur == NULL)
5719 return(ctxt->context->node);
5720 return(xmlXPathNextAncestor(ctxt, cur));
5721}
5722
5723/**
5724 * xmlXPathNextFollowingSibling:
5725 * @ctxt: the XPath Parser context
5726 * @cur: the current node in the traversal
5727 *
5728 * Traversal function for the "following-sibling" direction
5729 * The following-sibling axis contains the following siblings of the context
5730 * node in document order.
5731 *
5732 * Returns the next element following that axis
5733 */
5734xmlNodePtr
5735xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005736 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005737 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5738 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5739 return(NULL);
5740 if (cur == (xmlNodePtr) ctxt->context->doc)
5741 return(NULL);
5742 if (cur == NULL)
5743 return(ctxt->context->node->next);
5744 return(cur->next);
5745}
5746
5747/**
5748 * xmlXPathNextPrecedingSibling:
5749 * @ctxt: the XPath Parser context
5750 * @cur: the current node in the traversal
5751 *
5752 * Traversal function for the "preceding-sibling" direction
5753 * The preceding-sibling axis contains the preceding siblings of the context
5754 * node in reverse document order; the first preceding sibling is first on the
5755 * axis; the sibling preceding that node is the second on the axis and so on.
5756 *
5757 * Returns the next element following that axis
5758 */
5759xmlNodePtr
5760xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005761 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005762 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5763 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5764 return(NULL);
5765 if (cur == (xmlNodePtr) ctxt->context->doc)
5766 return(NULL);
5767 if (cur == NULL)
5768 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005769 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5770 cur = cur->prev;
5771 if (cur == NULL)
5772 return(ctxt->context->node->prev);
5773 }
Owen Taylor3473f882001-02-23 17:55:21 +00005774 return(cur->prev);
5775}
5776
5777/**
5778 * xmlXPathNextFollowing:
5779 * @ctxt: the XPath Parser context
5780 * @cur: the current node in the traversal
5781 *
5782 * Traversal function for the "following" direction
5783 * The following axis contains all nodes in the same document as the context
5784 * node that are after the context node in document order, excluding any
5785 * descendants and excluding attribute nodes and namespace nodes; the nodes
5786 * are ordered in document order
5787 *
5788 * Returns the next element following that axis
5789 */
5790xmlNodePtr
5791xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005792 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005793 if (cur != NULL && cur->children != NULL)
5794 return cur->children ;
5795 if (cur == NULL) cur = ctxt->context->node;
5796 if (cur == NULL) return(NULL) ; /* ERROR */
5797 if (cur->next != NULL) return(cur->next) ;
5798 do {
5799 cur = cur->parent;
5800 if (cur == NULL) return(NULL);
5801 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5802 if (cur->next != NULL) return(cur->next);
5803 } while (cur != NULL);
5804 return(cur);
5805}
5806
5807/*
5808 * xmlXPathIsAncestor:
5809 * @ancestor: the ancestor node
5810 * @node: the current node
5811 *
5812 * Check that @ancestor is a @node's ancestor
5813 *
5814 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5815 */
5816static int
5817xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5818 if ((ancestor == NULL) || (node == NULL)) return(0);
5819 /* nodes need to be in the same document */
5820 if (ancestor->doc != node->doc) return(0);
5821 /* avoid searching if ancestor or node is the root node */
5822 if (ancestor == (xmlNodePtr) node->doc) return(1);
5823 if (node == (xmlNodePtr) ancestor->doc) return(0);
5824 while (node->parent != NULL) {
5825 if (node->parent == ancestor)
5826 return(1);
5827 node = node->parent;
5828 }
5829 return(0);
5830}
5831
5832/**
5833 * xmlXPathNextPreceding:
5834 * @ctxt: the XPath Parser context
5835 * @cur: the current node in the traversal
5836 *
5837 * Traversal function for the "preceding" direction
5838 * the preceding axis contains all nodes in the same document as the context
5839 * node that are before the context node in document order, excluding any
5840 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5841 * ordered in reverse document order
5842 *
5843 * Returns the next element following that axis
5844 */
5845xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005846xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5847{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005848 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005849 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005850 cur = ctxt->context->node;
5851 if (cur == NULL)
5852 return (NULL);
5853 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5854 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005855 do {
5856 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005857 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5858 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005859 }
5860
5861 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005862 if (cur == NULL)
5863 return (NULL);
5864 if (cur == ctxt->context->doc->children)
5865 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005866 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005867 return (cur);
5868}
5869
5870/**
5871 * xmlXPathNextPrecedingInternal:
5872 * @ctxt: the XPath Parser context
5873 * @cur: the current node in the traversal
5874 *
5875 * Traversal function for the "preceding" direction
5876 * the preceding axis contains all nodes in the same document as the context
5877 * node that are before the context node in document order, excluding any
5878 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5879 * ordered in reverse document order
5880 * This is a faster implementation but internal only since it requires a
5881 * state kept in the parser context: ctxt->ancestor.
5882 *
5883 * Returns the next element following that axis
5884 */
5885static xmlNodePtr
5886xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5887 xmlNodePtr cur)
5888{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005889 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005890 if (cur == NULL) {
5891 cur = ctxt->context->node;
5892 if (cur == NULL)
5893 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005894 if (cur->type == XML_NAMESPACE_DECL)
5895 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005896 ctxt->ancestor = cur->parent;
5897 }
5898 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5899 cur = cur->prev;
5900 while (cur->prev == NULL) {
5901 cur = cur->parent;
5902 if (cur == NULL)
5903 return (NULL);
5904 if (cur == ctxt->context->doc->children)
5905 return (NULL);
5906 if (cur != ctxt->ancestor)
5907 return (cur);
5908 ctxt->ancestor = cur->parent;
5909 }
5910 cur = cur->prev;
5911 while (cur->last != NULL)
5912 cur = cur->last;
5913 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005914}
5915
5916/**
5917 * xmlXPathNextNamespace:
5918 * @ctxt: the XPath Parser context
5919 * @cur: the current attribute in the traversal
5920 *
5921 * Traversal function for the "namespace" direction
5922 * the namespace axis contains the namespace nodes of the context node;
5923 * the order of nodes on this axis is implementation-defined; the axis will
5924 * be empty unless the context node is an element
5925 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005926 * We keep the XML namespace node at the end of the list.
5927 *
Owen Taylor3473f882001-02-23 17:55:21 +00005928 * Returns the next element following that axis
5929 */
5930xmlNodePtr
5931xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005932 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005933 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005934 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005935 if (ctxt->context->tmpNsList != NULL)
5936 xmlFree(ctxt->context->tmpNsList);
5937 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005938 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005939 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005940 if (ctxt->context->tmpNsList != NULL) {
5941 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5942 ctxt->context->tmpNsNr++;
5943 }
5944 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005945 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005946 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005947 if (ctxt->context->tmpNsNr > 0) {
5948 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5949 } else {
5950 if (ctxt->context->tmpNsList != NULL)
5951 xmlFree(ctxt->context->tmpNsList);
5952 ctxt->context->tmpNsList = NULL;
5953 return(NULL);
5954 }
Owen Taylor3473f882001-02-23 17:55:21 +00005955}
5956
5957/**
5958 * xmlXPathNextAttribute:
5959 * @ctxt: the XPath Parser context
5960 * @cur: the current attribute in the traversal
5961 *
5962 * Traversal function for the "attribute" direction
5963 * TODO: support DTD inherited default attributes
5964 *
5965 * Returns the next element following that axis
5966 */
5967xmlNodePtr
5968xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005969 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00005970 if (ctxt->context->node == NULL)
5971 return(NULL);
5972 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5973 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005974 if (cur == NULL) {
5975 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5976 return(NULL);
5977 return((xmlNodePtr)ctxt->context->node->properties);
5978 }
5979 return((xmlNodePtr)cur->next);
5980}
5981
5982/************************************************************************
5983 * *
5984 * NodeTest Functions *
5985 * *
5986 ************************************************************************/
5987
Owen Taylor3473f882001-02-23 17:55:21 +00005988#define IS_FUNCTION 200
5989
Owen Taylor3473f882001-02-23 17:55:21 +00005990
5991/************************************************************************
5992 * *
5993 * Implicit tree core function library *
5994 * *
5995 ************************************************************************/
5996
5997/**
5998 * xmlXPathRoot:
5999 * @ctxt: the XPath Parser context
6000 *
6001 * Initialize the context to the root of the document
6002 */
6003void
6004xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006005 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006006 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6007 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6008}
6009
6010/************************************************************************
6011 * *
6012 * The explicit core function library *
6013 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6014 * *
6015 ************************************************************************/
6016
6017
6018/**
6019 * xmlXPathLastFunction:
6020 * @ctxt: the XPath Parser context
6021 * @nargs: the number of arguments
6022 *
6023 * Implement the last() XPath function
6024 * number last()
6025 * The last function returns the number of nodes in the context node list.
6026 */
6027void
6028xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6029 CHECK_ARITY(0);
6030 if (ctxt->context->contextSize >= 0) {
6031 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6032#ifdef DEBUG_EXPR
6033 xmlGenericError(xmlGenericErrorContext,
6034 "last() : %d\n", ctxt->context->contextSize);
6035#endif
6036 } else {
6037 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6038 }
6039}
6040
6041/**
6042 * xmlXPathPositionFunction:
6043 * @ctxt: the XPath Parser context
6044 * @nargs: the number of arguments
6045 *
6046 * Implement the position() XPath function
6047 * number position()
6048 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006049 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006050 * will be equal to last().
6051 */
6052void
6053xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6054 CHECK_ARITY(0);
6055 if (ctxt->context->proximityPosition >= 0) {
6056 valuePush(ctxt,
6057 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6058#ifdef DEBUG_EXPR
6059 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6060 ctxt->context->proximityPosition);
6061#endif
6062 } else {
6063 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6064 }
6065}
6066
6067/**
6068 * xmlXPathCountFunction:
6069 * @ctxt: the XPath Parser context
6070 * @nargs: the number of arguments
6071 *
6072 * Implement the count() XPath function
6073 * number count(node-set)
6074 */
6075void
6076xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6077 xmlXPathObjectPtr cur;
6078
6079 CHECK_ARITY(1);
6080 if ((ctxt->value == NULL) ||
6081 ((ctxt->value->type != XPATH_NODESET) &&
6082 (ctxt->value->type != XPATH_XSLT_TREE)))
6083 XP_ERROR(XPATH_INVALID_TYPE);
6084 cur = valuePop(ctxt);
6085
Daniel Veillard911f49a2001-04-07 15:39:35 +00006086 if ((cur == NULL) || (cur->nodesetval == NULL))
6087 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006088 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006089 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006090 } else {
6091 if ((cur->nodesetval->nodeNr != 1) ||
6092 (cur->nodesetval->nodeTab == NULL)) {
6093 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6094 } else {
6095 xmlNodePtr tmp;
6096 int i = 0;
6097
6098 tmp = cur->nodesetval->nodeTab[0];
6099 if (tmp != NULL) {
6100 tmp = tmp->children;
6101 while (tmp != NULL) {
6102 tmp = tmp->next;
6103 i++;
6104 }
6105 }
6106 valuePush(ctxt, xmlXPathNewFloat((double) i));
6107 }
6108 }
Owen Taylor3473f882001-02-23 17:55:21 +00006109 xmlXPathFreeObject(cur);
6110}
6111
6112/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006113 * xmlXPathGetElementsByIds:
6114 * @doc: the document
6115 * @ids: a whitespace separated list of IDs
6116 *
6117 * Selects elements by their unique ID.
6118 *
6119 * Returns a node-set of selected elements.
6120 */
6121static xmlNodeSetPtr
6122xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6123 xmlNodeSetPtr ret;
6124 const xmlChar *cur = ids;
6125 xmlChar *ID;
6126 xmlAttrPtr attr;
6127 xmlNodePtr elem = NULL;
6128
Daniel Veillard7a985a12003-07-06 17:57:42 +00006129 if (ids == NULL) return(NULL);
6130
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006131 ret = xmlXPathNodeSetCreate(NULL);
6132
William M. Brack76e95df2003-10-18 16:20:14 +00006133 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006134 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006135 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006136 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006137
6138 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006139 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006140 /*
6141 * We used to check the fact that the value passed
6142 * was an NCName, but this generated much troubles for
6143 * me and Aleksey Sanin, people blatantly violated that
6144 * constaint, like Visa3D spec.
6145 * if (xmlValidateNCName(ID, 1) == 0)
6146 */
6147 attr = xmlGetID(doc, ID);
6148 if (attr != NULL) {
6149 if (attr->type == XML_ATTRIBUTE_NODE)
6150 elem = attr->parent;
6151 else if (attr->type == XML_ELEMENT_NODE)
6152 elem = (xmlNodePtr) attr;
6153 else
6154 elem = NULL;
6155 if (elem != NULL)
6156 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006157 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006158 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006159 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006160
William M. Brack76e95df2003-10-18 16:20:14 +00006161 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006162 ids = cur;
6163 }
6164 return(ret);
6165}
6166
6167/**
Owen Taylor3473f882001-02-23 17:55:21 +00006168 * xmlXPathIdFunction:
6169 * @ctxt: the XPath Parser context
6170 * @nargs: the number of arguments
6171 *
6172 * Implement the id() XPath function
6173 * node-set id(object)
6174 * The id function selects elements by their unique ID
6175 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6176 * then the result is the union of the result of applying id to the
6177 * string value of each of the nodes in the argument node-set. When the
6178 * argument to id is of any other type, the argument is converted to a
6179 * string as if by a call to the string function; the string is split
6180 * into a whitespace-separated list of tokens (whitespace is any sequence
6181 * of characters matching the production S); the result is a node-set
6182 * containing the elements in the same document as the context node that
6183 * have a unique ID equal to any of the tokens in the list.
6184 */
6185void
6186xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006187 xmlChar *tokens;
6188 xmlNodeSetPtr ret;
6189 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006190
6191 CHECK_ARITY(1);
6192 obj = valuePop(ctxt);
6193 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006194 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006195 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006196 int i;
6197
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006198 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006199
Daniel Veillard911f49a2001-04-07 15:39:35 +00006200 if (obj->nodesetval != NULL) {
6201 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006202 tokens =
6203 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6204 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6205 ret = xmlXPathNodeSetMerge(ret, ns);
6206 xmlXPathFreeNodeSet(ns);
6207 if (tokens != NULL)
6208 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006209 }
Owen Taylor3473f882001-02-23 17:55:21 +00006210 }
6211
6212 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006213 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006214 return;
6215 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006216 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006217
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006218 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6219 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006220
Owen Taylor3473f882001-02-23 17:55:21 +00006221 xmlXPathFreeObject(obj);
6222 return;
6223}
6224
6225/**
6226 * xmlXPathLocalNameFunction:
6227 * @ctxt: the XPath Parser context
6228 * @nargs: the number of arguments
6229 *
6230 * Implement the local-name() XPath function
6231 * string local-name(node-set?)
6232 * The local-name function returns a string containing the local part
6233 * of the name of the node in the argument node-set that is first in
6234 * document order. If the node-set is empty or the first node has no
6235 * name, an empty string is returned. If the argument is omitted it
6236 * defaults to the context node.
6237 */
6238void
6239xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6240 xmlXPathObjectPtr cur;
6241
Daniel Veillarda82b1822004-11-08 16:24:57 +00006242 if (ctxt == NULL) return;
6243
Owen Taylor3473f882001-02-23 17:55:21 +00006244 if (nargs == 0) {
6245 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6246 nargs = 1;
6247 }
6248
6249 CHECK_ARITY(1);
6250 if ((ctxt->value == NULL) ||
6251 ((ctxt->value->type != XPATH_NODESET) &&
6252 (ctxt->value->type != XPATH_XSLT_TREE)))
6253 XP_ERROR(XPATH_INVALID_TYPE);
6254 cur = valuePop(ctxt);
6255
Daniel Veillard911f49a2001-04-07 15:39:35 +00006256 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006257 valuePush(ctxt, xmlXPathNewCString(""));
6258 } else {
6259 int i = 0; /* Should be first in document order !!!!! */
6260 switch (cur->nodesetval->nodeTab[i]->type) {
6261 case XML_ELEMENT_NODE:
6262 case XML_ATTRIBUTE_NODE:
6263 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006264 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6265 valuePush(ctxt, xmlXPathNewCString(""));
6266 else
6267 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006268 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6269 break;
6270 case XML_NAMESPACE_DECL:
6271 valuePush(ctxt, xmlXPathNewString(
6272 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6273 break;
6274 default:
6275 valuePush(ctxt, xmlXPathNewCString(""));
6276 }
6277 }
6278 xmlXPathFreeObject(cur);
6279}
6280
6281/**
6282 * xmlXPathNamespaceURIFunction:
6283 * @ctxt: the XPath Parser context
6284 * @nargs: the number of arguments
6285 *
6286 * Implement the namespace-uri() XPath function
6287 * string namespace-uri(node-set?)
6288 * The namespace-uri function returns a string containing the
6289 * namespace URI of the expanded name of the node in the argument
6290 * node-set that is first in document order. If the node-set is empty,
6291 * the first node has no name, or the expanded name has no namespace
6292 * URI, an empty string is returned. If the argument is omitted it
6293 * defaults to the context node.
6294 */
6295void
6296xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6297 xmlXPathObjectPtr cur;
6298
Daniel Veillarda82b1822004-11-08 16:24:57 +00006299 if (ctxt == NULL) return;
6300
Owen Taylor3473f882001-02-23 17:55:21 +00006301 if (nargs == 0) {
6302 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6303 nargs = 1;
6304 }
6305 CHECK_ARITY(1);
6306 if ((ctxt->value == NULL) ||
6307 ((ctxt->value->type != XPATH_NODESET) &&
6308 (ctxt->value->type != XPATH_XSLT_TREE)))
6309 XP_ERROR(XPATH_INVALID_TYPE);
6310 cur = valuePop(ctxt);
6311
Daniel Veillard911f49a2001-04-07 15:39:35 +00006312 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006313 valuePush(ctxt, xmlXPathNewCString(""));
6314 } else {
6315 int i = 0; /* Should be first in document order !!!!! */
6316 switch (cur->nodesetval->nodeTab[i]->type) {
6317 case XML_ELEMENT_NODE:
6318 case XML_ATTRIBUTE_NODE:
6319 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6320 valuePush(ctxt, xmlXPathNewCString(""));
6321 else
6322 valuePush(ctxt, xmlXPathNewString(
6323 cur->nodesetval->nodeTab[i]->ns->href));
6324 break;
6325 default:
6326 valuePush(ctxt, xmlXPathNewCString(""));
6327 }
6328 }
6329 xmlXPathFreeObject(cur);
6330}
6331
6332/**
6333 * xmlXPathNameFunction:
6334 * @ctxt: the XPath Parser context
6335 * @nargs: the number of arguments
6336 *
6337 * Implement the name() XPath function
6338 * string name(node-set?)
6339 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006340 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006341 * order. The QName must represent the name with respect to the namespace
6342 * declarations in effect on the node whose name is being represented.
6343 * Typically, this will be the form in which the name occurred in the XML
6344 * source. This need not be the case if there are namespace declarations
6345 * in effect on the node that associate multiple prefixes with the same
6346 * namespace. However, an implementation may include information about
6347 * the original prefix in its representation of nodes; in this case, an
6348 * implementation can ensure that the returned string is always the same
6349 * as the QName used in the XML source. If the argument it omitted it
6350 * defaults to the context node.
6351 * Libxml keep the original prefix so the "real qualified name" used is
6352 * returned.
6353 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006354static void
Daniel Veillard04383752001-07-08 14:27:15 +00006355xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6356{
Owen Taylor3473f882001-02-23 17:55:21 +00006357 xmlXPathObjectPtr cur;
6358
6359 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006360 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6361 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006362 }
6363
6364 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006365 if ((ctxt->value == NULL) ||
6366 ((ctxt->value->type != XPATH_NODESET) &&
6367 (ctxt->value->type != XPATH_XSLT_TREE)))
6368 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006369 cur = valuePop(ctxt);
6370
Daniel Veillard911f49a2001-04-07 15:39:35 +00006371 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006372 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006373 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006374 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006375
Daniel Veillard04383752001-07-08 14:27:15 +00006376 switch (cur->nodesetval->nodeTab[i]->type) {
6377 case XML_ELEMENT_NODE:
6378 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006379 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6380 valuePush(ctxt, xmlXPathNewCString(""));
6381 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6382 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006383 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006384 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006385
Daniel Veillard652d8a92003-02-04 19:28:49 +00006386 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006387 xmlChar *fullname;
6388
6389 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6390 cur->nodesetval->nodeTab[i]->ns->prefix,
6391 NULL, 0);
6392 if (fullname == cur->nodesetval->nodeTab[i]->name)
6393 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6394 if (fullname == NULL) {
6395 XP_ERROR(XPATH_MEMORY_ERROR);
6396 }
6397 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006398 }
6399 break;
6400 default:
6401 valuePush(ctxt,
6402 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6403 xmlXPathLocalNameFunction(ctxt, 1);
6404 }
Owen Taylor3473f882001-02-23 17:55:21 +00006405 }
6406 xmlXPathFreeObject(cur);
6407}
6408
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006409
6410/**
Owen Taylor3473f882001-02-23 17:55:21 +00006411 * xmlXPathStringFunction:
6412 * @ctxt: the XPath Parser context
6413 * @nargs: the number of arguments
6414 *
6415 * Implement the string() XPath function
6416 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006417 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006418 * - A node-set is converted to a string by returning the value of
6419 * the node in the node-set that is first in document order.
6420 * If the node-set is empty, an empty string is returned.
6421 * - A number is converted to a string as follows
6422 * + NaN is converted to the string NaN
6423 * + positive zero is converted to the string 0
6424 * + negative zero is converted to the string 0
6425 * + positive infinity is converted to the string Infinity
6426 * + negative infinity is converted to the string -Infinity
6427 * + if the number is an integer, the number is represented in
6428 * decimal form as a Number with no decimal point and no leading
6429 * zeros, preceded by a minus sign (-) if the number is negative
6430 * + otherwise, the number is represented in decimal form as a
6431 * Number including a decimal point with at least one digit
6432 * before the decimal point and at least one digit after the
6433 * decimal point, preceded by a minus sign (-) if the number
6434 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006435 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006436 * before the decimal point; beyond the one required digit
6437 * after the decimal point there must be as many, but only as
6438 * many, more digits as are needed to uniquely distinguish the
6439 * number from all other IEEE 754 numeric values.
6440 * - The boolean false value is converted to the string false.
6441 * The boolean true value is converted to the string true.
6442 *
6443 * If the argument is omitted, it defaults to a node-set with the
6444 * context node as its only member.
6445 */
6446void
6447xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6448 xmlXPathObjectPtr cur;
6449
Daniel Veillarda82b1822004-11-08 16:24:57 +00006450 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006451 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006452 valuePush(ctxt,
6453 xmlXPathWrapString(
6454 xmlXPathCastNodeToString(ctxt->context->node)));
6455 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006456 }
6457
6458 CHECK_ARITY(1);
6459 cur = valuePop(ctxt);
6460 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006461 cur = xmlXPathConvertString(cur);
6462 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006463}
6464
6465/**
6466 * xmlXPathStringLengthFunction:
6467 * @ctxt: the XPath Parser context
6468 * @nargs: the number of arguments
6469 *
6470 * Implement the string-length() XPath function
6471 * number string-length(string?)
6472 * The string-length returns the number of characters in the string
6473 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6474 * the context node converted to a string, in other words the value
6475 * of the context node.
6476 */
6477void
6478xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6479 xmlXPathObjectPtr cur;
6480
6481 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006482 if ((ctxt == NULL) || (ctxt->context == NULL))
6483 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006484 if (ctxt->context->node == NULL) {
6485 valuePush(ctxt, xmlXPathNewFloat(0));
6486 } else {
6487 xmlChar *content;
6488
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006489 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006490 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006491 xmlFree(content);
6492 }
6493 return;
6494 }
6495 CHECK_ARITY(1);
6496 CAST_TO_STRING;
6497 CHECK_TYPE(XPATH_STRING);
6498 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006499 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006500 xmlXPathFreeObject(cur);
6501}
6502
6503/**
6504 * xmlXPathConcatFunction:
6505 * @ctxt: the XPath Parser context
6506 * @nargs: the number of arguments
6507 *
6508 * Implement the concat() XPath function
6509 * string concat(string, string, string*)
6510 * The concat function returns the concatenation of its arguments.
6511 */
6512void
6513xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6514 xmlXPathObjectPtr cur, newobj;
6515 xmlChar *tmp;
6516
Daniel Veillarda82b1822004-11-08 16:24:57 +00006517 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006518 if (nargs < 2) {
6519 CHECK_ARITY(2);
6520 }
6521
6522 CAST_TO_STRING;
6523 cur = valuePop(ctxt);
6524 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6525 xmlXPathFreeObject(cur);
6526 return;
6527 }
6528 nargs--;
6529
6530 while (nargs > 0) {
6531 CAST_TO_STRING;
6532 newobj = valuePop(ctxt);
6533 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6534 xmlXPathFreeObject(newobj);
6535 xmlXPathFreeObject(cur);
6536 XP_ERROR(XPATH_INVALID_TYPE);
6537 }
6538 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6539 newobj->stringval = cur->stringval;
6540 cur->stringval = tmp;
6541
6542 xmlXPathFreeObject(newobj);
6543 nargs--;
6544 }
6545 valuePush(ctxt, cur);
6546}
6547
6548/**
6549 * xmlXPathContainsFunction:
6550 * @ctxt: the XPath Parser context
6551 * @nargs: the number of arguments
6552 *
6553 * Implement the contains() XPath function
6554 * boolean contains(string, string)
6555 * The contains function returns true if the first argument string
6556 * contains the second argument string, and otherwise returns false.
6557 */
6558void
6559xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6560 xmlXPathObjectPtr hay, needle;
6561
6562 CHECK_ARITY(2);
6563 CAST_TO_STRING;
6564 CHECK_TYPE(XPATH_STRING);
6565 needle = valuePop(ctxt);
6566 CAST_TO_STRING;
6567 hay = valuePop(ctxt);
6568 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6569 xmlXPathFreeObject(hay);
6570 xmlXPathFreeObject(needle);
6571 XP_ERROR(XPATH_INVALID_TYPE);
6572 }
6573 if (xmlStrstr(hay->stringval, needle->stringval))
6574 valuePush(ctxt, xmlXPathNewBoolean(1));
6575 else
6576 valuePush(ctxt, xmlXPathNewBoolean(0));
6577 xmlXPathFreeObject(hay);
6578 xmlXPathFreeObject(needle);
6579}
6580
6581/**
6582 * xmlXPathStartsWithFunction:
6583 * @ctxt: the XPath Parser context
6584 * @nargs: the number of arguments
6585 *
6586 * Implement the starts-with() XPath function
6587 * boolean starts-with(string, string)
6588 * The starts-with function returns true if the first argument string
6589 * starts with the second argument string, and otherwise returns false.
6590 */
6591void
6592xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6593 xmlXPathObjectPtr hay, needle;
6594 int n;
6595
6596 CHECK_ARITY(2);
6597 CAST_TO_STRING;
6598 CHECK_TYPE(XPATH_STRING);
6599 needle = valuePop(ctxt);
6600 CAST_TO_STRING;
6601 hay = valuePop(ctxt);
6602 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6603 xmlXPathFreeObject(hay);
6604 xmlXPathFreeObject(needle);
6605 XP_ERROR(XPATH_INVALID_TYPE);
6606 }
6607 n = xmlStrlen(needle->stringval);
6608 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6609 valuePush(ctxt, xmlXPathNewBoolean(0));
6610 else
6611 valuePush(ctxt, xmlXPathNewBoolean(1));
6612 xmlXPathFreeObject(hay);
6613 xmlXPathFreeObject(needle);
6614}
6615
6616/**
6617 * xmlXPathSubstringFunction:
6618 * @ctxt: the XPath Parser context
6619 * @nargs: the number of arguments
6620 *
6621 * Implement the substring() XPath function
6622 * string substring(string, number, number?)
6623 * The substring function returns the substring of the first argument
6624 * starting at the position specified in the second argument with
6625 * length specified in the third argument. For example,
6626 * substring("12345",2,3) returns "234". If the third argument is not
6627 * specified, it returns the substring starting at the position specified
6628 * in the second argument and continuing to the end of the string. For
6629 * example, substring("12345",2) returns "2345". More precisely, each
6630 * character in the string (see [3.6 Strings]) is considered to have a
6631 * numeric position: the position of the first character is 1, the position
6632 * of the second character is 2 and so on. The returned substring contains
6633 * those characters for which the position of the character is greater than
6634 * or equal to the second argument and, if the third argument is specified,
6635 * less than the sum of the second and third arguments; the comparisons
6636 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6637 * - substring("12345", 1.5, 2.6) returns "234"
6638 * - substring("12345", 0, 3) returns "12"
6639 * - substring("12345", 0 div 0, 3) returns ""
6640 * - substring("12345", 1, 0 div 0) returns ""
6641 * - substring("12345", -42, 1 div 0) returns "12345"
6642 * - substring("12345", -1 div 0, 1 div 0) returns ""
6643 */
6644void
6645xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6646 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006647 double le=0, in;
6648 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006649 xmlChar *ret;
6650
Owen Taylor3473f882001-02-23 17:55:21 +00006651 if (nargs < 2) {
6652 CHECK_ARITY(2);
6653 }
6654 if (nargs > 3) {
6655 CHECK_ARITY(3);
6656 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006657 /*
6658 * take care of possible last (position) argument
6659 */
Owen Taylor3473f882001-02-23 17:55:21 +00006660 if (nargs == 3) {
6661 CAST_TO_NUMBER;
6662 CHECK_TYPE(XPATH_NUMBER);
6663 len = valuePop(ctxt);
6664 le = len->floatval;
6665 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006666 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006667
Owen Taylor3473f882001-02-23 17:55:21 +00006668 CAST_TO_NUMBER;
6669 CHECK_TYPE(XPATH_NUMBER);
6670 start = valuePop(ctxt);
6671 in = start->floatval;
6672 xmlXPathFreeObject(start);
6673 CAST_TO_STRING;
6674 CHECK_TYPE(XPATH_STRING);
6675 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006676 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006677
Daniel Veillard97ac1312001-05-30 19:14:17 +00006678 /*
6679 * If last pos not present, calculate last position
6680 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006681 if (nargs != 3) {
6682 le = (double)m;
6683 if (in < 1.0)
6684 in = 1.0;
6685 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006686
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006687 /* Need to check for the special cases where either
6688 * the index is NaN, the length is NaN, or both
6689 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006690 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006691 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006692 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006693 * To meet the requirements of the spec, the arguments
6694 * must be converted to integer format before
6695 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006696 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006697 * First we go to integer form, rounding up
6698 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006699 */
6700 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006701 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006702
Daniel Veillard9e412302002-06-10 15:59:44 +00006703 if (xmlXPathIsInf(le) == 1) {
6704 l = m;
6705 if (i < 1)
6706 i = 1;
6707 }
6708 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6709 l = 0;
6710 else {
6711 l = (int) le;
6712 if (((double)l)+0.5 <= le) l++;
6713 }
6714
6715 /* Now we normalize inidices */
6716 i -= 1;
6717 l += i;
6718 if (i < 0)
6719 i = 0;
6720 if (l > m)
6721 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006722
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006723 /* number of chars to copy */
6724 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006725
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006726 ret = xmlUTF8Strsub(str->stringval, i, l);
6727 }
6728 else {
6729 ret = NULL;
6730 }
6731
Owen Taylor3473f882001-02-23 17:55:21 +00006732 if (ret == NULL)
6733 valuePush(ctxt, xmlXPathNewCString(""));
6734 else {
6735 valuePush(ctxt, xmlXPathNewString(ret));
6736 xmlFree(ret);
6737 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006738
Owen Taylor3473f882001-02-23 17:55:21 +00006739 xmlXPathFreeObject(str);
6740}
6741
6742/**
6743 * xmlXPathSubstringBeforeFunction:
6744 * @ctxt: the XPath Parser context
6745 * @nargs: the number of arguments
6746 *
6747 * Implement the substring-before() XPath function
6748 * string substring-before(string, string)
6749 * The substring-before function returns the substring of the first
6750 * argument string that precedes the first occurrence of the second
6751 * argument string in the first argument string, or the empty string
6752 * if the first argument string does not contain the second argument
6753 * string. For example, substring-before("1999/04/01","/") returns 1999.
6754 */
6755void
6756xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6757 xmlXPathObjectPtr str;
6758 xmlXPathObjectPtr find;
6759 xmlBufferPtr target;
6760 const xmlChar *point;
6761 int offset;
6762
6763 CHECK_ARITY(2);
6764 CAST_TO_STRING;
6765 find = valuePop(ctxt);
6766 CAST_TO_STRING;
6767 str = valuePop(ctxt);
6768
6769 target = xmlBufferCreate();
6770 if (target) {
6771 point = xmlStrstr(str->stringval, find->stringval);
6772 if (point) {
6773 offset = (int)(point - str->stringval);
6774 xmlBufferAdd(target, str->stringval, offset);
6775 }
6776 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6777 xmlBufferFree(target);
6778 }
6779
6780 xmlXPathFreeObject(str);
6781 xmlXPathFreeObject(find);
6782}
6783
6784/**
6785 * xmlXPathSubstringAfterFunction:
6786 * @ctxt: the XPath Parser context
6787 * @nargs: the number of arguments
6788 *
6789 * Implement the substring-after() XPath function
6790 * string substring-after(string, string)
6791 * The substring-after function returns the substring of the first
6792 * argument string that follows the first occurrence of the second
6793 * argument string in the first argument string, or the empty stringi
6794 * if the first argument string does not contain the second argument
6795 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6796 * and substring-after("1999/04/01","19") returns 99/04/01.
6797 */
6798void
6799xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6800 xmlXPathObjectPtr str;
6801 xmlXPathObjectPtr find;
6802 xmlBufferPtr target;
6803 const xmlChar *point;
6804 int offset;
6805
6806 CHECK_ARITY(2);
6807 CAST_TO_STRING;
6808 find = valuePop(ctxt);
6809 CAST_TO_STRING;
6810 str = valuePop(ctxt);
6811
6812 target = xmlBufferCreate();
6813 if (target) {
6814 point = xmlStrstr(str->stringval, find->stringval);
6815 if (point) {
6816 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6817 xmlBufferAdd(target, &str->stringval[offset],
6818 xmlStrlen(str->stringval) - offset);
6819 }
6820 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6821 xmlBufferFree(target);
6822 }
6823
6824 xmlXPathFreeObject(str);
6825 xmlXPathFreeObject(find);
6826}
6827
6828/**
6829 * xmlXPathNormalizeFunction:
6830 * @ctxt: the XPath Parser context
6831 * @nargs: the number of arguments
6832 *
6833 * Implement the normalize-space() XPath function
6834 * string normalize-space(string?)
6835 * The normalize-space function returns the argument string with white
6836 * space normalized by stripping leading and trailing whitespace
6837 * and replacing sequences of whitespace characters by a single
6838 * space. Whitespace characters are the same allowed by the S production
6839 * in XML. If the argument is omitted, it defaults to the context
6840 * node converted to a string, in other words the value of the context node.
6841 */
6842void
6843xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6844 xmlXPathObjectPtr obj = NULL;
6845 xmlChar *source = NULL;
6846 xmlBufferPtr target;
6847 xmlChar blank;
6848
Daniel Veillarda82b1822004-11-08 16:24:57 +00006849 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006850 if (nargs == 0) {
6851 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006852 valuePush(ctxt,
6853 xmlXPathWrapString(
6854 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006855 nargs = 1;
6856 }
6857
6858 CHECK_ARITY(1);
6859 CAST_TO_STRING;
6860 CHECK_TYPE(XPATH_STRING);
6861 obj = valuePop(ctxt);
6862 source = obj->stringval;
6863
6864 target = xmlBufferCreate();
6865 if (target && source) {
6866
6867 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006868 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006869 source++;
6870
6871 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6872 blank = 0;
6873 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006874 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006875 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006876 } else {
6877 if (blank) {
6878 xmlBufferAdd(target, &blank, 1);
6879 blank = 0;
6880 }
6881 xmlBufferAdd(target, source, 1);
6882 }
6883 source++;
6884 }
6885
6886 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6887 xmlBufferFree(target);
6888 }
6889 xmlXPathFreeObject(obj);
6890}
6891
6892/**
6893 * xmlXPathTranslateFunction:
6894 * @ctxt: the XPath Parser context
6895 * @nargs: the number of arguments
6896 *
6897 * Implement the translate() XPath function
6898 * string translate(string, string, string)
6899 * The translate function returns the first argument string with
6900 * occurrences of characters in the second argument string replaced
6901 * by the character at the corresponding position in the third argument
6902 * string. For example, translate("bar","abc","ABC") returns the string
6903 * BAr. If there is a character in the second argument string with no
6904 * character at a corresponding position in the third argument string
6905 * (because the second argument string is longer than the third argument
6906 * string), then occurrences of that character in the first argument
6907 * string are removed. For example, translate("--aaa--","abc-","ABC")
6908 * returns "AAA". If a character occurs more than once in second
6909 * argument string, then the first occurrence determines the replacement
6910 * character. If the third argument string is longer than the second
6911 * argument string, then excess characters are ignored.
6912 */
6913void
6914xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006915 xmlXPathObjectPtr str;
6916 xmlXPathObjectPtr from;
6917 xmlXPathObjectPtr to;
6918 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006919 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006920 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006921 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006922 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006923
Daniel Veillarde043ee12001-04-16 14:08:07 +00006924 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006925
Daniel Veillarde043ee12001-04-16 14:08:07 +00006926 CAST_TO_STRING;
6927 to = valuePop(ctxt);
6928 CAST_TO_STRING;
6929 from = valuePop(ctxt);
6930 CAST_TO_STRING;
6931 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006932
Daniel Veillarde043ee12001-04-16 14:08:07 +00006933 target = xmlBufferCreate();
6934 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006935 max = xmlUTF8Strlen(to->stringval);
6936 for (cptr = str->stringval; (ch=*cptr); ) {
6937 offset = xmlUTF8Strloc(from->stringval, cptr);
6938 if (offset >= 0) {
6939 if (offset < max) {
6940 point = xmlUTF8Strpos(to->stringval, offset);
6941 if (point)
6942 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6943 }
6944 } else
6945 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6946
6947 /* Step to next character in input */
6948 cptr++;
6949 if ( ch & 0x80 ) {
6950 /* if not simple ascii, verify proper format */
6951 if ( (ch & 0xc0) != 0xc0 ) {
6952 xmlGenericError(xmlGenericErrorContext,
6953 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6954 break;
6955 }
6956 /* then skip over remaining bytes for this char */
6957 while ( (ch <<= 1) & 0x80 )
6958 if ( (*cptr++ & 0xc0) != 0x80 ) {
6959 xmlGenericError(xmlGenericErrorContext,
6960 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6961 break;
6962 }
6963 if (ch & 0x80) /* must have had error encountered */
6964 break;
6965 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006966 }
Owen Taylor3473f882001-02-23 17:55:21 +00006967 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006968 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6969 xmlBufferFree(target);
6970 xmlXPathFreeObject(str);
6971 xmlXPathFreeObject(from);
6972 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006973}
6974
6975/**
6976 * xmlXPathBooleanFunction:
6977 * @ctxt: the XPath Parser context
6978 * @nargs: the number of arguments
6979 *
6980 * Implement the boolean() XPath function
6981 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006982 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006983 * - a number is true if and only if it is neither positive or
6984 * negative zero nor NaN
6985 * - a node-set is true if and only if it is non-empty
6986 * - a string is true if and only if its length is non-zero
6987 */
6988void
6989xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6990 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006991
6992 CHECK_ARITY(1);
6993 cur = valuePop(ctxt);
6994 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006995 cur = xmlXPathConvertBoolean(cur);
6996 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006997}
6998
6999/**
7000 * xmlXPathNotFunction:
7001 * @ctxt: the XPath Parser context
7002 * @nargs: the number of arguments
7003 *
7004 * Implement the not() XPath function
7005 * boolean not(boolean)
7006 * The not function returns true if its argument is false,
7007 * and false otherwise.
7008 */
7009void
7010xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7011 CHECK_ARITY(1);
7012 CAST_TO_BOOLEAN;
7013 CHECK_TYPE(XPATH_BOOLEAN);
7014 ctxt->value->boolval = ! ctxt->value->boolval;
7015}
7016
7017/**
7018 * xmlXPathTrueFunction:
7019 * @ctxt: the XPath Parser context
7020 * @nargs: the number of arguments
7021 *
7022 * Implement the true() XPath function
7023 * boolean true()
7024 */
7025void
7026xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7027 CHECK_ARITY(0);
7028 valuePush(ctxt, xmlXPathNewBoolean(1));
7029}
7030
7031/**
7032 * xmlXPathFalseFunction:
7033 * @ctxt: the XPath Parser context
7034 * @nargs: the number of arguments
7035 *
7036 * Implement the false() XPath function
7037 * boolean false()
7038 */
7039void
7040xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7041 CHECK_ARITY(0);
7042 valuePush(ctxt, xmlXPathNewBoolean(0));
7043}
7044
7045/**
7046 * xmlXPathLangFunction:
7047 * @ctxt: the XPath Parser context
7048 * @nargs: the number of arguments
7049 *
7050 * Implement the lang() XPath function
7051 * boolean lang(string)
7052 * The lang function returns true or false depending on whether the
7053 * language of the context node as specified by xml:lang attributes
7054 * is the same as or is a sublanguage of the language specified by
7055 * the argument string. The language of the context node is determined
7056 * by the value of the xml:lang attribute on the context node, or, if
7057 * the context node has no xml:lang attribute, by the value of the
7058 * xml:lang attribute on the nearest ancestor of the context node that
7059 * has an xml:lang attribute. If there is no such attribute, then lang
7060 * returns false. If there is such an attribute, then lang returns
7061 * true if the attribute value is equal to the argument ignoring case,
7062 * or if there is some suffix starting with - such that the attribute
7063 * value is equal to the argument ignoring that suffix of the attribute
7064 * value and ignoring case.
7065 */
7066void
7067xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7068 xmlXPathObjectPtr val;
7069 const xmlChar *theLang;
7070 const xmlChar *lang;
7071 int ret = 0;
7072 int i;
7073
7074 CHECK_ARITY(1);
7075 CAST_TO_STRING;
7076 CHECK_TYPE(XPATH_STRING);
7077 val = valuePop(ctxt);
7078 lang = val->stringval;
7079 theLang = xmlNodeGetLang(ctxt->context->node);
7080 if ((theLang != NULL) && (lang != NULL)) {
7081 for (i = 0;lang[i] != 0;i++)
7082 if (toupper(lang[i]) != toupper(theLang[i]))
7083 goto not_equal;
7084 ret = 1;
7085 }
7086not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007087 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007088 xmlXPathFreeObject(val);
7089 valuePush(ctxt, xmlXPathNewBoolean(ret));
7090}
7091
7092/**
7093 * xmlXPathNumberFunction:
7094 * @ctxt: the XPath Parser context
7095 * @nargs: the number of arguments
7096 *
7097 * Implement the number() XPath function
7098 * number number(object?)
7099 */
7100void
7101xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7102 xmlXPathObjectPtr cur;
7103 double res;
7104
Daniel Veillarda82b1822004-11-08 16:24:57 +00007105 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007106 if (nargs == 0) {
7107 if (ctxt->context->node == NULL) {
7108 valuePush(ctxt, xmlXPathNewFloat(0.0));
7109 } else {
7110 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7111
7112 res = xmlXPathStringEvalNumber(content);
7113 valuePush(ctxt, xmlXPathNewFloat(res));
7114 xmlFree(content);
7115 }
7116 return;
7117 }
7118
7119 CHECK_ARITY(1);
7120 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007121 cur = xmlXPathConvertNumber(cur);
7122 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007123}
7124
7125/**
7126 * xmlXPathSumFunction:
7127 * @ctxt: the XPath Parser context
7128 * @nargs: the number of arguments
7129 *
7130 * Implement the sum() XPath function
7131 * number sum(node-set)
7132 * The sum function returns the sum of the values of the nodes in
7133 * the argument node-set.
7134 */
7135void
7136xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7137 xmlXPathObjectPtr cur;
7138 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007139 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007140
7141 CHECK_ARITY(1);
7142 if ((ctxt->value == NULL) ||
7143 ((ctxt->value->type != XPATH_NODESET) &&
7144 (ctxt->value->type != XPATH_XSLT_TREE)))
7145 XP_ERROR(XPATH_INVALID_TYPE);
7146 cur = valuePop(ctxt);
7147
William M. Brack08171912003-12-29 02:52:11 +00007148 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007149 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7150 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007151 }
7152 }
William M. Brack08171912003-12-29 02:52:11 +00007153 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007154 xmlXPathFreeObject(cur);
7155}
7156
7157/**
7158 * xmlXPathFloorFunction:
7159 * @ctxt: the XPath Parser context
7160 * @nargs: the number of arguments
7161 *
7162 * Implement the floor() XPath function
7163 * number floor(number)
7164 * The floor function returns the largest (closest to positive infinity)
7165 * number that is not greater than the argument and that is an integer.
7166 */
7167void
7168xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007169 double f;
7170
Owen Taylor3473f882001-02-23 17:55:21 +00007171 CHECK_ARITY(1);
7172 CAST_TO_NUMBER;
7173 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007174
7175 f = (double)((int) ctxt->value->floatval);
7176 if (f != ctxt->value->floatval) {
7177 if (ctxt->value->floatval > 0)
7178 ctxt->value->floatval = f;
7179 else
7180 ctxt->value->floatval = f - 1;
7181 }
Owen Taylor3473f882001-02-23 17:55:21 +00007182}
7183
7184/**
7185 * xmlXPathCeilingFunction:
7186 * @ctxt: the XPath Parser context
7187 * @nargs: the number of arguments
7188 *
7189 * Implement the ceiling() XPath function
7190 * number ceiling(number)
7191 * The ceiling function returns the smallest (closest to negative infinity)
7192 * number that is not less than the argument and that is an integer.
7193 */
7194void
7195xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7196 double f;
7197
7198 CHECK_ARITY(1);
7199 CAST_TO_NUMBER;
7200 CHECK_TYPE(XPATH_NUMBER);
7201
7202#if 0
7203 ctxt->value->floatval = ceil(ctxt->value->floatval);
7204#else
7205 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007206 if (f != ctxt->value->floatval) {
7207 if (ctxt->value->floatval > 0)
7208 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007209 else {
7210 if (ctxt->value->floatval < 0 && f == 0)
7211 ctxt->value->floatval = xmlXPathNZERO;
7212 else
7213 ctxt->value->floatval = f;
7214 }
7215
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007216 }
Owen Taylor3473f882001-02-23 17:55:21 +00007217#endif
7218}
7219
7220/**
7221 * xmlXPathRoundFunction:
7222 * @ctxt: the XPath Parser context
7223 * @nargs: the number of arguments
7224 *
7225 * Implement the round() XPath function
7226 * number round(number)
7227 * The round function returns the number that is closest to the
7228 * argument and that is an integer. If there are two such numbers,
7229 * then the one that is even is returned.
7230 */
7231void
7232xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7233 double f;
7234
7235 CHECK_ARITY(1);
7236 CAST_TO_NUMBER;
7237 CHECK_TYPE(XPATH_NUMBER);
7238
Daniel Veillardcda96922001-08-21 10:56:31 +00007239 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7240 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7241 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007242 (ctxt->value->floatval == 0.0))
7243 return;
7244
Owen Taylor3473f882001-02-23 17:55:21 +00007245 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007246 if (ctxt->value->floatval < 0) {
7247 if (ctxt->value->floatval < f - 0.5)
7248 ctxt->value->floatval = f - 1;
7249 else
7250 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007251 if (ctxt->value->floatval == 0)
7252 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007253 } else {
7254 if (ctxt->value->floatval < f + 0.5)
7255 ctxt->value->floatval = f;
7256 else
7257 ctxt->value->floatval = f + 1;
7258 }
Owen Taylor3473f882001-02-23 17:55:21 +00007259}
7260
7261/************************************************************************
7262 * *
7263 * The Parser *
7264 * *
7265 ************************************************************************/
7266
7267/*
William M. Brack08171912003-12-29 02:52:11 +00007268 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007269 * implementation.
7270 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007271static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007272static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007273static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007274static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007275static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7276 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007277
7278/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007279 * xmlXPathCurrentChar:
7280 * @ctxt: the XPath parser context
7281 * @cur: pointer to the beginning of the char
7282 * @len: pointer to the length of the char read
7283 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007284 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007285 * bytes in the input buffer.
7286 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007287 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007288 */
7289
7290static int
7291xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7292 unsigned char c;
7293 unsigned int val;
7294 const xmlChar *cur;
7295
7296 if (ctxt == NULL)
7297 return(0);
7298 cur = ctxt->cur;
7299
7300 /*
7301 * We are supposed to handle UTF8, check it's valid
7302 * From rfc2044: encoding of the Unicode values on UTF-8:
7303 *
7304 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7305 * 0000 0000-0000 007F 0xxxxxxx
7306 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7307 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7308 *
7309 * Check for the 0x110000 limit too
7310 */
7311 c = *cur;
7312 if (c & 0x80) {
7313 if ((cur[1] & 0xc0) != 0x80)
7314 goto encoding_error;
7315 if ((c & 0xe0) == 0xe0) {
7316
7317 if ((cur[2] & 0xc0) != 0x80)
7318 goto encoding_error;
7319 if ((c & 0xf0) == 0xf0) {
7320 if (((c & 0xf8) != 0xf0) ||
7321 ((cur[3] & 0xc0) != 0x80))
7322 goto encoding_error;
7323 /* 4-byte code */
7324 *len = 4;
7325 val = (cur[0] & 0x7) << 18;
7326 val |= (cur[1] & 0x3f) << 12;
7327 val |= (cur[2] & 0x3f) << 6;
7328 val |= cur[3] & 0x3f;
7329 } else {
7330 /* 3-byte code */
7331 *len = 3;
7332 val = (cur[0] & 0xf) << 12;
7333 val |= (cur[1] & 0x3f) << 6;
7334 val |= cur[2] & 0x3f;
7335 }
7336 } else {
7337 /* 2-byte code */
7338 *len = 2;
7339 val = (cur[0] & 0x1f) << 6;
7340 val |= cur[1] & 0x3f;
7341 }
7342 if (!IS_CHAR(val)) {
7343 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7344 }
7345 return(val);
7346 } else {
7347 /* 1-byte code */
7348 *len = 1;
7349 return((int) *cur);
7350 }
7351encoding_error:
7352 /*
William M. Brack08171912003-12-29 02:52:11 +00007353 * If we detect an UTF8 error that probably means that the
7354 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007355 * declaration header. Report the error and switch the encoding
7356 * to ISO-Latin-1 (if you don't like this policy, just declare the
7357 * encoding !)
7358 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007359 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007360 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007361}
7362
7363/**
Owen Taylor3473f882001-02-23 17:55:21 +00007364 * xmlXPathParseNCName:
7365 * @ctxt: the XPath Parser context
7366 *
7367 * parse an XML namespace non qualified name.
7368 *
7369 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7370 *
7371 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7372 * CombiningChar | Extender
7373 *
7374 * Returns the namespace name or NULL
7375 */
7376
7377xmlChar *
7378xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007379 const xmlChar *in;
7380 xmlChar *ret;
7381 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007382
Daniel Veillarda82b1822004-11-08 16:24:57 +00007383 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007384 /*
7385 * Accelerator for simple ASCII names
7386 */
7387 in = ctxt->cur;
7388 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7389 ((*in >= 0x41) && (*in <= 0x5A)) ||
7390 (*in == '_')) {
7391 in++;
7392 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7393 ((*in >= 0x41) && (*in <= 0x5A)) ||
7394 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007395 (*in == '_') || (*in == '.') ||
7396 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007397 in++;
7398 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7399 (*in == '[') || (*in == ']') || (*in == ':') ||
7400 (*in == '@') || (*in == '*')) {
7401 count = in - ctxt->cur;
7402 if (count == 0)
7403 return(NULL);
7404 ret = xmlStrndup(ctxt->cur, count);
7405 ctxt->cur = in;
7406 return(ret);
7407 }
7408 }
7409 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007410}
7411
Daniel Veillard2156a562001-04-28 12:24:34 +00007412
Owen Taylor3473f882001-02-23 17:55:21 +00007413/**
7414 * xmlXPathParseQName:
7415 * @ctxt: the XPath Parser context
7416 * @prefix: a xmlChar **
7417 *
7418 * parse an XML qualified name
7419 *
7420 * [NS 5] QName ::= (Prefix ':')? LocalPart
7421 *
7422 * [NS 6] Prefix ::= NCName
7423 *
7424 * [NS 7] LocalPart ::= NCName
7425 *
7426 * Returns the function returns the local part, and prefix is updated
7427 * to get the Prefix if any.
7428 */
7429
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007430static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007431xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7432 xmlChar *ret = NULL;
7433
7434 *prefix = NULL;
7435 ret = xmlXPathParseNCName(ctxt);
7436 if (CUR == ':') {
7437 *prefix = ret;
7438 NEXT;
7439 ret = xmlXPathParseNCName(ctxt);
7440 }
7441 return(ret);
7442}
7443
7444/**
7445 * xmlXPathParseName:
7446 * @ctxt: the XPath Parser context
7447 *
7448 * parse an XML name
7449 *
7450 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7451 * CombiningChar | Extender
7452 *
7453 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7454 *
7455 * Returns the namespace name or NULL
7456 */
7457
7458xmlChar *
7459xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007460 const xmlChar *in;
7461 xmlChar *ret;
7462 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007463
Daniel Veillarda82b1822004-11-08 16:24:57 +00007464 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007465 /*
7466 * Accelerator for simple ASCII names
7467 */
7468 in = ctxt->cur;
7469 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7470 ((*in >= 0x41) && (*in <= 0x5A)) ||
7471 (*in == '_') || (*in == ':')) {
7472 in++;
7473 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7474 ((*in >= 0x41) && (*in <= 0x5A)) ||
7475 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007476 (*in == '_') || (*in == '-') ||
7477 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007478 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007479 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007480 count = in - ctxt->cur;
7481 ret = xmlStrndup(ctxt->cur, count);
7482 ctxt->cur = in;
7483 return(ret);
7484 }
7485 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007486 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007487}
7488
Daniel Veillard61d80a22001-04-27 17:13:01 +00007489static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007490xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007491 xmlChar buf[XML_MAX_NAMELEN + 5];
7492 int len = 0, l;
7493 int c;
7494
7495 /*
7496 * Handler for more complex cases
7497 */
7498 c = CUR_CHAR(l);
7499 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007500 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7501 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007502 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007503 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007504 return(NULL);
7505 }
7506
7507 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7508 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7509 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007510 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007511 (IS_COMBINING(c)) ||
7512 (IS_EXTENDER(c)))) {
7513 COPY_BUF(l,buf,len,c);
7514 NEXTL(l);
7515 c = CUR_CHAR(l);
7516 if (len >= XML_MAX_NAMELEN) {
7517 /*
7518 * Okay someone managed to make a huge name, so he's ready to pay
7519 * for the processing speed.
7520 */
7521 xmlChar *buffer;
7522 int max = len * 2;
7523
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007524 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007525 if (buffer == NULL) {
7526 XP_ERROR0(XPATH_MEMORY_ERROR);
7527 }
7528 memcpy(buffer, buf, len);
7529 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7530 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007531 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007532 (IS_COMBINING(c)) ||
7533 (IS_EXTENDER(c))) {
7534 if (len + 10 > max) {
7535 max *= 2;
7536 buffer = (xmlChar *) xmlRealloc(buffer,
7537 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007538 if (buffer == NULL) {
7539 XP_ERROR0(XPATH_MEMORY_ERROR);
7540 }
7541 }
7542 COPY_BUF(l,buffer,len,c);
7543 NEXTL(l);
7544 c = CUR_CHAR(l);
7545 }
7546 buffer[len] = 0;
7547 return(buffer);
7548 }
7549 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007550 if (len == 0)
7551 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007552 return(xmlStrndup(buf, len));
7553}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007554
7555#define MAX_FRAC 20
7556
William M. Brack372a4452004-02-17 13:09:23 +00007557/*
7558 * These are used as divisors for the fractional part of a number.
7559 * Since the table includes 1.0 (representing '0' fractional digits),
7560 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7561 */
7562static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007563 1.0, 10.0, 100.0, 1000.0, 10000.0,
7564 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7565 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7566 100000000000000.0,
7567 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007568 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007569};
7570
Owen Taylor3473f882001-02-23 17:55:21 +00007571/**
7572 * xmlXPathStringEvalNumber:
7573 * @str: A string to scan
7574 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007575 * [30a] Float ::= Number ('e' Digits?)?
7576 *
Owen Taylor3473f882001-02-23 17:55:21 +00007577 * [30] Number ::= Digits ('.' Digits?)?
7578 * | '.' Digits
7579 * [31] Digits ::= [0-9]+
7580 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007581 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007582 * In complement of the Number expression, this function also handles
7583 * negative values : '-' Number.
7584 *
7585 * Returns the double value.
7586 */
7587double
7588xmlXPathStringEvalNumber(const xmlChar *str) {
7589 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007590 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007591 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007592 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007593 int exponent = 0;
7594 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007595#ifdef __GNUC__
7596 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007597 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007598#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007599 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007600 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007601 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7602 return(xmlXPathNAN);
7603 }
7604 if (*cur == '-') {
7605 isneg = 1;
7606 cur++;
7607 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007608
7609#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007610 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007611 * tmp/temp is a workaround against a gcc compiler bug
7612 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007613 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007614 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007615 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007616 ret = ret * 10;
7617 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007618 ok = 1;
7619 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007620 temp = (double) tmp;
7621 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007622 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007623#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007624 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007625 while ((*cur >= '0') && (*cur <= '9')) {
7626 ret = ret * 10 + (*cur - '0');
7627 ok = 1;
7628 cur++;
7629 }
7630#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007631
Owen Taylor3473f882001-02-23 17:55:21 +00007632 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007633 int v, frac = 0;
7634 double fraction = 0;
7635
Owen Taylor3473f882001-02-23 17:55:21 +00007636 cur++;
7637 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7638 return(xmlXPathNAN);
7639 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007640 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7641 v = (*cur - '0');
7642 fraction = fraction * 10 + v;
7643 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007644 cur++;
7645 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007646 fraction /= my_pow10[frac];
7647 ret = ret + fraction;
7648 while ((*cur >= '0') && (*cur <= '9'))
7649 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007650 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007651 if ((*cur == 'e') || (*cur == 'E')) {
7652 cur++;
7653 if (*cur == '-') {
7654 is_exponent_negative = 1;
7655 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007656 } else if (*cur == '+') {
7657 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007658 }
7659 while ((*cur >= '0') && (*cur <= '9')) {
7660 exponent = exponent * 10 + (*cur - '0');
7661 cur++;
7662 }
7663 }
William M. Brack76e95df2003-10-18 16:20:14 +00007664 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007665 if (*cur != 0) return(xmlXPathNAN);
7666 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007667 if (is_exponent_negative) exponent = -exponent;
7668 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007669 return(ret);
7670}
7671
7672/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007673 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007674 * @ctxt: the XPath Parser context
7675 *
7676 * [30] Number ::= Digits ('.' Digits?)?
7677 * | '.' Digits
7678 * [31] Digits ::= [0-9]+
7679 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007680 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007681 *
7682 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007683static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007684xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7685{
Owen Taylor3473f882001-02-23 17:55:21 +00007686 double ret = 0.0;
7687 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007688 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007689 int exponent = 0;
7690 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007691#ifdef __GNUC__
7692 unsigned long tmp = 0;
7693 double temp;
7694#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007695
7696 CHECK_ERROR;
7697 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7698 XP_ERROR(XPATH_NUMBER_ERROR);
7699 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007700#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007701 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007702 * tmp/temp is a workaround against a gcc compiler bug
7703 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007704 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007705 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007706 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007707 ret = ret * 10;
7708 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007709 ok = 1;
7710 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007711 temp = (double) tmp;
7712 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007713 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007714#else
7715 ret = 0;
7716 while ((CUR >= '0') && (CUR <= '9')) {
7717 ret = ret * 10 + (CUR - '0');
7718 ok = 1;
7719 NEXT;
7720 }
7721#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007722 if (CUR == '.') {
7723 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007724 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7725 XP_ERROR(XPATH_NUMBER_ERROR);
7726 }
7727 while ((CUR >= '0') && (CUR <= '9')) {
7728 mult /= 10;
7729 ret = ret + (CUR - '0') * mult;
7730 NEXT;
7731 }
Owen Taylor3473f882001-02-23 17:55:21 +00007732 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007733 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007734 NEXT;
7735 if (CUR == '-') {
7736 is_exponent_negative = 1;
7737 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007738 } else if (CUR == '+') {
7739 NEXT;
7740 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007741 while ((CUR >= '0') && (CUR <= '9')) {
7742 exponent = exponent * 10 + (CUR - '0');
7743 NEXT;
7744 }
7745 if (is_exponent_negative)
7746 exponent = -exponent;
7747 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007748 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007749 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007750 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007751}
7752
7753/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007754 * xmlXPathParseLiteral:
7755 * @ctxt: the XPath Parser context
7756 *
7757 * Parse a Literal
7758 *
7759 * [29] Literal ::= '"' [^"]* '"'
7760 * | "'" [^']* "'"
7761 *
7762 * Returns the value found or NULL in case of error
7763 */
7764static xmlChar *
7765xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7766 const xmlChar *q;
7767 xmlChar *ret = NULL;
7768
7769 if (CUR == '"') {
7770 NEXT;
7771 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007772 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007773 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007774 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007775 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7776 } else {
7777 ret = xmlStrndup(q, CUR_PTR - q);
7778 NEXT;
7779 }
7780 } else if (CUR == '\'') {
7781 NEXT;
7782 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007783 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007784 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007785 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007786 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7787 } else {
7788 ret = xmlStrndup(q, CUR_PTR - q);
7789 NEXT;
7790 }
7791 } else {
7792 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7793 }
7794 return(ret);
7795}
7796
7797/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007798 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007799 * @ctxt: the XPath Parser context
7800 *
7801 * Parse a Literal and push it on the stack.
7802 *
7803 * [29] Literal ::= '"' [^"]* '"'
7804 * | "'" [^']* "'"
7805 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007806 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007807 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007808static void
7809xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007810 const xmlChar *q;
7811 xmlChar *ret = NULL;
7812
7813 if (CUR == '"') {
7814 NEXT;
7815 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007816 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007817 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007818 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007819 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7820 } else {
7821 ret = xmlStrndup(q, CUR_PTR - q);
7822 NEXT;
7823 }
7824 } else if (CUR == '\'') {
7825 NEXT;
7826 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007827 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007828 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007829 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007830 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7831 } else {
7832 ret = xmlStrndup(q, CUR_PTR - q);
7833 NEXT;
7834 }
7835 } else {
7836 XP_ERROR(XPATH_START_LITERAL_ERROR);
7837 }
7838 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007839 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7840 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007841 xmlFree(ret);
7842}
7843
7844/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007845 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007846 * @ctxt: the XPath Parser context
7847 *
7848 * Parse a VariableReference, evaluate it and push it on the stack.
7849 *
7850 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007851 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007852 * of any of the types that are possible for the value of an expression,
7853 * and may also be of additional types not specified here.
7854 *
7855 * Early evaluation is possible since:
7856 * The variable bindings [...] used to evaluate a subexpression are
7857 * always the same as those used to evaluate the containing expression.
7858 *
7859 * [36] VariableReference ::= '$' QName
7860 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007861static void
7862xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007863 xmlChar *name;
7864 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007865
7866 SKIP_BLANKS;
7867 if (CUR != '$') {
7868 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7869 }
7870 NEXT;
7871 name = xmlXPathParseQName(ctxt, &prefix);
7872 if (name == NULL) {
7873 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7874 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007875 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007876 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7877 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007878 SKIP_BLANKS;
7879}
7880
7881/**
7882 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007883 * @name: a name string
7884 *
7885 * Is the name given a NodeType one.
7886 *
7887 * [38] NodeType ::= 'comment'
7888 * | 'text'
7889 * | 'processing-instruction'
7890 * | 'node'
7891 *
7892 * Returns 1 if true 0 otherwise
7893 */
7894int
7895xmlXPathIsNodeType(const xmlChar *name) {
7896 if (name == NULL)
7897 return(0);
7898
Daniel Veillard1971ee22002-01-31 20:29:19 +00007899 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007900 return(1);
7901 if (xmlStrEqual(name, BAD_CAST "text"))
7902 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007903 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007904 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007905 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007906 return(1);
7907 return(0);
7908}
7909
7910/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007911 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007912 * @ctxt: the XPath Parser context
7913 *
7914 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7915 * [17] Argument ::= Expr
7916 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007917 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007918 * pushed on the stack
7919 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007920static void
7921xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007922 xmlChar *name;
7923 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007924 int nbargs = 0;
7925
7926 name = xmlXPathParseQName(ctxt, &prefix);
7927 if (name == NULL) {
7928 XP_ERROR(XPATH_EXPR_ERROR);
7929 }
7930 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007931#ifdef DEBUG_EXPR
7932 if (prefix == NULL)
7933 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7934 name);
7935 else
7936 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7937 prefix, name);
7938#endif
7939
Owen Taylor3473f882001-02-23 17:55:21 +00007940 if (CUR != '(') {
7941 XP_ERROR(XPATH_EXPR_ERROR);
7942 }
7943 NEXT;
7944 SKIP_BLANKS;
7945
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007946 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007947 if (CUR != ')') {
7948 while (CUR != 0) {
7949 int op1 = ctxt->comp->last;
7950 ctxt->comp->last = -1;
7951 xmlXPathCompileExpr(ctxt);
7952 CHECK_ERROR;
7953 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7954 nbargs++;
7955 if (CUR == ')') break;
7956 if (CUR != ',') {
7957 XP_ERROR(XPATH_EXPR_ERROR);
7958 }
7959 NEXT;
7960 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007961 }
Owen Taylor3473f882001-02-23 17:55:21 +00007962 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007963 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7964 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007965 NEXT;
7966 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007967}
7968
7969/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007970 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007971 * @ctxt: the XPath Parser context
7972 *
7973 * [15] PrimaryExpr ::= VariableReference
7974 * | '(' Expr ')'
7975 * | Literal
7976 * | Number
7977 * | FunctionCall
7978 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007979 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007980 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007981static void
7982xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007983 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007984 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007985 else if (CUR == '(') {
7986 NEXT;
7987 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007988 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007989 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007990 if (CUR != ')') {
7991 XP_ERROR(XPATH_EXPR_ERROR);
7992 }
7993 NEXT;
7994 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00007995 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007996 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007997 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007998 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007999 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008000 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008001 }
8002 SKIP_BLANKS;
8003}
8004
8005/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008006 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008007 * @ctxt: the XPath Parser context
8008 *
8009 * [20] FilterExpr ::= PrimaryExpr
8010 * | FilterExpr Predicate
8011 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008012 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008013 * Square brackets are used to filter expressions in the same way that
8014 * they are used in location paths. It is an error if the expression to
8015 * be filtered does not evaluate to a node-set. The context node list
8016 * used for evaluating the expression in square brackets is the node-set
8017 * to be filtered listed in document order.
8018 */
8019
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008020static void
8021xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8022 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008023 CHECK_ERROR;
8024 SKIP_BLANKS;
8025
8026 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008027 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008028 SKIP_BLANKS;
8029 }
8030
8031
8032}
8033
8034/**
8035 * xmlXPathScanName:
8036 * @ctxt: the XPath Parser context
8037 *
8038 * Trickery: parse an XML name but without consuming the input flow
8039 * Needed to avoid insanity in the parser state.
8040 *
8041 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8042 * CombiningChar | Extender
8043 *
8044 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8045 *
8046 * [6] Names ::= Name (S Name)*
8047 *
8048 * Returns the Name parsed or NULL
8049 */
8050
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008051static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008052xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008053 int len = 0, l;
8054 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008055 const xmlChar *cur;
8056 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008057
Daniel Veillard03226812004-11-01 14:55:21 +00008058 cur = ctxt->cur;
8059
8060 c = CUR_CHAR(l);
8061 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8062 (!IS_LETTER(c) && (c != '_') &&
8063 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008064 return(NULL);
8065 }
8066
Daniel Veillard03226812004-11-01 14:55:21 +00008067 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8068 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8069 (c == '.') || (c == '-') ||
8070 (c == '_') || (c == ':') ||
8071 (IS_COMBINING(c)) ||
8072 (IS_EXTENDER(c)))) {
8073 len += l;
8074 NEXTL(l);
8075 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008076 }
Daniel Veillard03226812004-11-01 14:55:21 +00008077 ret = xmlStrndup(cur, ctxt->cur - cur);
8078 ctxt->cur = cur;
8079 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008080}
8081
8082/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008083 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008084 * @ctxt: the XPath Parser context
8085 *
8086 * [19] PathExpr ::= LocationPath
8087 * | FilterExpr
8088 * | FilterExpr '/' RelativeLocationPath
8089 * | FilterExpr '//' RelativeLocationPath
8090 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008091 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008092 * The / operator and // operators combine an arbitrary expression
8093 * and a relative location path. It is an error if the expression
8094 * does not evaluate to a node-set.
8095 * The / operator does composition in the same way as when / is
8096 * used in a location path. As in location paths, // is short for
8097 * /descendant-or-self::node()/.
8098 */
8099
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008100static void
8101xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008102 int lc = 1; /* Should we branch to LocationPath ? */
8103 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8104
8105 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008106 if ((CUR == '$') || (CUR == '(') ||
8107 (IS_ASCII_DIGIT(CUR)) ||
8108 (CUR == '\'') || (CUR == '"') ||
8109 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008110 lc = 0;
8111 } else if (CUR == '*') {
8112 /* relative or absolute location path */
8113 lc = 1;
8114 } else if (CUR == '/') {
8115 /* relative or absolute location path */
8116 lc = 1;
8117 } else if (CUR == '@') {
8118 /* relative abbreviated attribute location path */
8119 lc = 1;
8120 } else if (CUR == '.') {
8121 /* relative abbreviated attribute location path */
8122 lc = 1;
8123 } else {
8124 /*
8125 * Problem is finding if we have a name here whether it's:
8126 * - a nodetype
8127 * - a function call in which case it's followed by '('
8128 * - an axis in which case it's followed by ':'
8129 * - a element name
8130 * We do an a priori analysis here rather than having to
8131 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008132 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008133 * read/write/debug.
8134 */
8135 SKIP_BLANKS;
8136 name = xmlXPathScanName(ctxt);
8137 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8138#ifdef DEBUG_STEP
8139 xmlGenericError(xmlGenericErrorContext,
8140 "PathExpr: Axis\n");
8141#endif
8142 lc = 1;
8143 xmlFree(name);
8144 } else if (name != NULL) {
8145 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008146
8147
8148 while (NXT(len) != 0) {
8149 if (NXT(len) == '/') {
8150 /* element name */
8151#ifdef DEBUG_STEP
8152 xmlGenericError(xmlGenericErrorContext,
8153 "PathExpr: AbbrRelLocation\n");
8154#endif
8155 lc = 1;
8156 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008157 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008158 /* ignore blanks */
8159 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008160 } else if (NXT(len) == ':') {
8161#ifdef DEBUG_STEP
8162 xmlGenericError(xmlGenericErrorContext,
8163 "PathExpr: AbbrRelLocation\n");
8164#endif
8165 lc = 1;
8166 break;
8167 } else if ((NXT(len) == '(')) {
8168 /* Note Type or Function */
8169 if (xmlXPathIsNodeType(name)) {
8170#ifdef DEBUG_STEP
8171 xmlGenericError(xmlGenericErrorContext,
8172 "PathExpr: Type search\n");
8173#endif
8174 lc = 1;
8175 } else {
8176#ifdef DEBUG_STEP
8177 xmlGenericError(xmlGenericErrorContext,
8178 "PathExpr: function call\n");
8179#endif
8180 lc = 0;
8181 }
8182 break;
8183 } else if ((NXT(len) == '[')) {
8184 /* element name */
8185#ifdef DEBUG_STEP
8186 xmlGenericError(xmlGenericErrorContext,
8187 "PathExpr: AbbrRelLocation\n");
8188#endif
8189 lc = 1;
8190 break;
8191 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8192 (NXT(len) == '=')) {
8193 lc = 1;
8194 break;
8195 } else {
8196 lc = 1;
8197 break;
8198 }
8199 len++;
8200 }
8201 if (NXT(len) == 0) {
8202#ifdef DEBUG_STEP
8203 xmlGenericError(xmlGenericErrorContext,
8204 "PathExpr: AbbrRelLocation\n");
8205#endif
8206 /* element name */
8207 lc = 1;
8208 }
8209 xmlFree(name);
8210 } else {
William M. Brack08171912003-12-29 02:52:11 +00008211 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008212 XP_ERROR(XPATH_EXPR_ERROR);
8213 }
8214 }
8215
8216 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008217 if (CUR == '/') {
8218 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8219 } else {
8220 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008221 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008222 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008223 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008224 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008225 CHECK_ERROR;
8226 if ((CUR == '/') && (NXT(1) == '/')) {
8227 SKIP(2);
8228 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008229
8230 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8231 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8232 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8233
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008234 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008235 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008236 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008237 }
8238 }
8239 SKIP_BLANKS;
8240}
8241
8242/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008243 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008244 * @ctxt: the XPath Parser context
8245 *
8246 * [18] UnionExpr ::= PathExpr
8247 * | UnionExpr '|' PathExpr
8248 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008249 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008250 */
8251
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008252static void
8253xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8254 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008255 CHECK_ERROR;
8256 SKIP_BLANKS;
8257 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008258 int op1 = ctxt->comp->last;
8259 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008260
8261 NEXT;
8262 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008263 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008264
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008265 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8266
Owen Taylor3473f882001-02-23 17:55:21 +00008267 SKIP_BLANKS;
8268 }
Owen Taylor3473f882001-02-23 17:55:21 +00008269}
8270
8271/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008272 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008273 * @ctxt: the XPath Parser context
8274 *
8275 * [27] UnaryExpr ::= UnionExpr
8276 * | '-' UnaryExpr
8277 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008278 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008279 */
8280
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008281static void
8282xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008283 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008284 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008285
8286 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008287 while (CUR == '-') {
8288 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008289 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008290 NEXT;
8291 SKIP_BLANKS;
8292 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008293
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008294 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008295 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008296 if (found) {
8297 if (minus)
8298 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8299 else
8300 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008301 }
8302}
8303
8304/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008305 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008306 * @ctxt: the XPath Parser context
8307 *
8308 * [26] MultiplicativeExpr ::= UnaryExpr
8309 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8310 * | MultiplicativeExpr 'div' UnaryExpr
8311 * | MultiplicativeExpr 'mod' UnaryExpr
8312 * [34] MultiplyOperator ::= '*'
8313 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008314 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008315 */
8316
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008317static void
8318xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8319 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008320 CHECK_ERROR;
8321 SKIP_BLANKS;
8322 while ((CUR == '*') ||
8323 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8324 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8325 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008326 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008327
8328 if (CUR == '*') {
8329 op = 0;
8330 NEXT;
8331 } else if (CUR == 'd') {
8332 op = 1;
8333 SKIP(3);
8334 } else if (CUR == 'm') {
8335 op = 2;
8336 SKIP(3);
8337 }
8338 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008339 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008340 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008341 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008342 SKIP_BLANKS;
8343 }
8344}
8345
8346/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008347 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008348 * @ctxt: the XPath Parser context
8349 *
8350 * [25] AdditiveExpr ::= MultiplicativeExpr
8351 * | AdditiveExpr '+' MultiplicativeExpr
8352 * | AdditiveExpr '-' MultiplicativeExpr
8353 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008354 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008355 */
8356
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008357static void
8358xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008359
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008360 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008361 CHECK_ERROR;
8362 SKIP_BLANKS;
8363 while ((CUR == '+') || (CUR == '-')) {
8364 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008365 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008366
8367 if (CUR == '+') plus = 1;
8368 else plus = 0;
8369 NEXT;
8370 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008371 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008372 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008373 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008374 SKIP_BLANKS;
8375 }
8376}
8377
8378/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008379 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008380 * @ctxt: the XPath Parser context
8381 *
8382 * [24] RelationalExpr ::= AdditiveExpr
8383 * | RelationalExpr '<' AdditiveExpr
8384 * | RelationalExpr '>' AdditiveExpr
8385 * | RelationalExpr '<=' AdditiveExpr
8386 * | RelationalExpr '>=' AdditiveExpr
8387 *
8388 * A <= B > C is allowed ? Answer from James, yes with
8389 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8390 * which is basically what got implemented.
8391 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008392 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008393 * on the stack
8394 */
8395
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008396static void
8397xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8398 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008399 CHECK_ERROR;
8400 SKIP_BLANKS;
8401 while ((CUR == '<') ||
8402 (CUR == '>') ||
8403 ((CUR == '<') && (NXT(1) == '=')) ||
8404 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008405 int inf, strict;
8406 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008407
8408 if (CUR == '<') inf = 1;
8409 else inf = 0;
8410 if (NXT(1) == '=') strict = 0;
8411 else strict = 1;
8412 NEXT;
8413 if (!strict) NEXT;
8414 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008415 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008416 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008417 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008418 SKIP_BLANKS;
8419 }
8420}
8421
8422/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008423 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008424 * @ctxt: the XPath Parser context
8425 *
8426 * [23] EqualityExpr ::= RelationalExpr
8427 * | EqualityExpr '=' RelationalExpr
8428 * | EqualityExpr '!=' RelationalExpr
8429 *
8430 * A != B != C is allowed ? Answer from James, yes with
8431 * (RelationalExpr = RelationalExpr) = RelationalExpr
8432 * (RelationalExpr != RelationalExpr) != RelationalExpr
8433 * which is basically what got implemented.
8434 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008435 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008436 *
8437 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008438static void
8439xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8440 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008441 CHECK_ERROR;
8442 SKIP_BLANKS;
8443 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008444 int eq;
8445 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008446
8447 if (CUR == '=') eq = 1;
8448 else eq = 0;
8449 NEXT;
8450 if (!eq) NEXT;
8451 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008452 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008453 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008454 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008455 SKIP_BLANKS;
8456 }
8457}
8458
8459/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008460 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008461 * @ctxt: the XPath Parser context
8462 *
8463 * [22] AndExpr ::= EqualityExpr
8464 * | AndExpr 'and' EqualityExpr
8465 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008466 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008467 *
8468 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008469static void
8470xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8471 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008472 CHECK_ERROR;
8473 SKIP_BLANKS;
8474 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008475 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008476 SKIP(3);
8477 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008478 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008479 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008480 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008481 SKIP_BLANKS;
8482 }
8483}
8484
8485/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008486 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008487 * @ctxt: the XPath Parser context
8488 *
8489 * [14] Expr ::= OrExpr
8490 * [21] OrExpr ::= AndExpr
8491 * | OrExpr 'or' AndExpr
8492 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008493 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008494 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008495static void
8496xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8497 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008498 CHECK_ERROR;
8499 SKIP_BLANKS;
8500 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008501 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008502 SKIP(2);
8503 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008504 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008505 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008506 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8507 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008508 SKIP_BLANKS;
8509 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008510 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8511 /* more ops could be optimized too */
8512 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8513 }
Owen Taylor3473f882001-02-23 17:55:21 +00008514}
8515
8516/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008517 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008518 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008519 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008520 *
8521 * [8] Predicate ::= '[' PredicateExpr ']'
8522 * [9] PredicateExpr ::= Expr
8523 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008524 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008525 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008526static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008527xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008528 int op1 = ctxt->comp->last;
8529
8530 SKIP_BLANKS;
8531 if (CUR != '[') {
8532 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8533 }
8534 NEXT;
8535 SKIP_BLANKS;
8536
8537 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008538 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008539 CHECK_ERROR;
8540
8541 if (CUR != ']') {
8542 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8543 }
8544
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008545 if (filter)
8546 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8547 else
8548 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008549
8550 NEXT;
8551 SKIP_BLANKS;
8552}
8553
8554/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008555 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008556 * @ctxt: the XPath Parser context
8557 * @test: pointer to a xmlXPathTestVal
8558 * @type: pointer to a xmlXPathTypeVal
8559 * @prefix: placeholder for a possible name prefix
8560 *
8561 * [7] NodeTest ::= NameTest
8562 * | NodeType '(' ')'
8563 * | 'processing-instruction' '(' Literal ')'
8564 *
8565 * [37] NameTest ::= '*'
8566 * | NCName ':' '*'
8567 * | QName
8568 * [38] NodeType ::= 'comment'
8569 * | 'text'
8570 * | 'processing-instruction'
8571 * | 'node'
8572 *
William M. Brack08171912003-12-29 02:52:11 +00008573 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008574 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008575static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008576xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8577 xmlXPathTypeVal *type, const xmlChar **prefix,
8578 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008579 int blanks;
8580
8581 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8582 STRANGE;
8583 return(NULL);
8584 }
William M. Brack78637da2003-07-31 14:47:38 +00008585 *type = (xmlXPathTypeVal) 0;
8586 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008587 *prefix = NULL;
8588 SKIP_BLANKS;
8589
8590 if ((name == NULL) && (CUR == '*')) {
8591 /*
8592 * All elements
8593 */
8594 NEXT;
8595 *test = NODE_TEST_ALL;
8596 return(NULL);
8597 }
8598
8599 if (name == NULL)
8600 name = xmlXPathParseNCName(ctxt);
8601 if (name == NULL) {
8602 XP_ERROR0(XPATH_EXPR_ERROR);
8603 }
8604
William M. Brack76e95df2003-10-18 16:20:14 +00008605 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008606 SKIP_BLANKS;
8607 if (CUR == '(') {
8608 NEXT;
8609 /*
8610 * NodeType or PI search
8611 */
8612 if (xmlStrEqual(name, BAD_CAST "comment"))
8613 *type = NODE_TYPE_COMMENT;
8614 else if (xmlStrEqual(name, BAD_CAST "node"))
8615 *type = NODE_TYPE_NODE;
8616 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8617 *type = NODE_TYPE_PI;
8618 else if (xmlStrEqual(name, BAD_CAST "text"))
8619 *type = NODE_TYPE_TEXT;
8620 else {
8621 if (name != NULL)
8622 xmlFree(name);
8623 XP_ERROR0(XPATH_EXPR_ERROR);
8624 }
8625
8626 *test = NODE_TEST_TYPE;
8627
8628 SKIP_BLANKS;
8629 if (*type == NODE_TYPE_PI) {
8630 /*
8631 * Specific case: search a PI by name.
8632 */
Owen Taylor3473f882001-02-23 17:55:21 +00008633 if (name != NULL)
8634 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008635 name = NULL;
8636 if (CUR != ')') {
8637 name = xmlXPathParseLiteral(ctxt);
8638 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008639 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008640 SKIP_BLANKS;
8641 }
Owen Taylor3473f882001-02-23 17:55:21 +00008642 }
8643 if (CUR != ')') {
8644 if (name != NULL)
8645 xmlFree(name);
8646 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8647 }
8648 NEXT;
8649 return(name);
8650 }
8651 *test = NODE_TEST_NAME;
8652 if ((!blanks) && (CUR == ':')) {
8653 NEXT;
8654
8655 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008656 * Since currently the parser context don't have a
8657 * namespace list associated:
8658 * The namespace name for this prefix can be computed
8659 * only at evaluation time. The compilation is done
8660 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008661 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008662#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008663 *prefix = xmlXPathNsLookup(ctxt->context, name);
8664 if (name != NULL)
8665 xmlFree(name);
8666 if (*prefix == NULL) {
8667 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8668 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008669#else
8670 *prefix = name;
8671#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008672
8673 if (CUR == '*') {
8674 /*
8675 * All elements
8676 */
8677 NEXT;
8678 *test = NODE_TEST_ALL;
8679 return(NULL);
8680 }
8681
8682 name = xmlXPathParseNCName(ctxt);
8683 if (name == NULL) {
8684 XP_ERROR0(XPATH_EXPR_ERROR);
8685 }
8686 }
8687 return(name);
8688}
8689
8690/**
8691 * xmlXPathIsAxisName:
8692 * @name: a preparsed name token
8693 *
8694 * [6] AxisName ::= 'ancestor'
8695 * | 'ancestor-or-self'
8696 * | 'attribute'
8697 * | 'child'
8698 * | 'descendant'
8699 * | 'descendant-or-self'
8700 * | 'following'
8701 * | 'following-sibling'
8702 * | 'namespace'
8703 * | 'parent'
8704 * | 'preceding'
8705 * | 'preceding-sibling'
8706 * | 'self'
8707 *
8708 * Returns the axis or 0
8709 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008710static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008711xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008712 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008713 switch (name[0]) {
8714 case 'a':
8715 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8716 ret = AXIS_ANCESTOR;
8717 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8718 ret = AXIS_ANCESTOR_OR_SELF;
8719 if (xmlStrEqual(name, BAD_CAST "attribute"))
8720 ret = AXIS_ATTRIBUTE;
8721 break;
8722 case 'c':
8723 if (xmlStrEqual(name, BAD_CAST "child"))
8724 ret = AXIS_CHILD;
8725 break;
8726 case 'd':
8727 if (xmlStrEqual(name, BAD_CAST "descendant"))
8728 ret = AXIS_DESCENDANT;
8729 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8730 ret = AXIS_DESCENDANT_OR_SELF;
8731 break;
8732 case 'f':
8733 if (xmlStrEqual(name, BAD_CAST "following"))
8734 ret = AXIS_FOLLOWING;
8735 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8736 ret = AXIS_FOLLOWING_SIBLING;
8737 break;
8738 case 'n':
8739 if (xmlStrEqual(name, BAD_CAST "namespace"))
8740 ret = AXIS_NAMESPACE;
8741 break;
8742 case 'p':
8743 if (xmlStrEqual(name, BAD_CAST "parent"))
8744 ret = AXIS_PARENT;
8745 if (xmlStrEqual(name, BAD_CAST "preceding"))
8746 ret = AXIS_PRECEDING;
8747 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8748 ret = AXIS_PRECEDING_SIBLING;
8749 break;
8750 case 's':
8751 if (xmlStrEqual(name, BAD_CAST "self"))
8752 ret = AXIS_SELF;
8753 break;
8754 }
8755 return(ret);
8756}
8757
8758/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008759 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008760 * @ctxt: the XPath Parser context
8761 *
8762 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8763 * | AbbreviatedStep
8764 *
8765 * [12] AbbreviatedStep ::= '.' | '..'
8766 *
8767 * [5] AxisSpecifier ::= AxisName '::'
8768 * | AbbreviatedAxisSpecifier
8769 *
8770 * [13] AbbreviatedAxisSpecifier ::= '@'?
8771 *
8772 * Modified for XPtr range support as:
8773 *
8774 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8775 * | AbbreviatedStep
8776 * | 'range-to' '(' Expr ')' Predicate*
8777 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008778 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008779 * A location step of . is short for self::node(). This is
8780 * particularly useful in conjunction with //. For example, the
8781 * location path .//para is short for
8782 * self::node()/descendant-or-self::node()/child::para
8783 * and so will select all para descendant elements of the context
8784 * node.
8785 * Similarly, a location step of .. is short for parent::node().
8786 * For example, ../title is short for parent::node()/child::title
8787 * and so will select the title children of the parent of the context
8788 * node.
8789 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008790static void
8791xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008792#ifdef LIBXML_XPTR_ENABLED
8793 int rangeto = 0;
8794 int op2 = -1;
8795#endif
8796
Owen Taylor3473f882001-02-23 17:55:21 +00008797 SKIP_BLANKS;
8798 if ((CUR == '.') && (NXT(1) == '.')) {
8799 SKIP(2);
8800 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008801 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8802 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008803 } else if (CUR == '.') {
8804 NEXT;
8805 SKIP_BLANKS;
8806 } else {
8807 xmlChar *name = NULL;
8808 const xmlChar *prefix = NULL;
8809 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008810 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008811 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008812 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008813
8814 /*
8815 * The modification needed for XPointer change to the production
8816 */
8817#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008818 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008819 name = xmlXPathParseNCName(ctxt);
8820 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008821 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008822 xmlFree(name);
8823 SKIP_BLANKS;
8824 if (CUR != '(') {
8825 XP_ERROR(XPATH_EXPR_ERROR);
8826 }
8827 NEXT;
8828 SKIP_BLANKS;
8829
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008830 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008831 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008832 CHECK_ERROR;
8833
8834 SKIP_BLANKS;
8835 if (CUR != ')') {
8836 XP_ERROR(XPATH_EXPR_ERROR);
8837 }
8838 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008839 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008840 goto eval_predicates;
8841 }
8842 }
8843#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008844 if (CUR == '*') {
8845 axis = AXIS_CHILD;
8846 } else {
8847 if (name == NULL)
8848 name = xmlXPathParseNCName(ctxt);
8849 if (name != NULL) {
8850 axis = xmlXPathIsAxisName(name);
8851 if (axis != 0) {
8852 SKIP_BLANKS;
8853 if ((CUR == ':') && (NXT(1) == ':')) {
8854 SKIP(2);
8855 xmlFree(name);
8856 name = NULL;
8857 } else {
8858 /* an element name can conflict with an axis one :-\ */
8859 axis = AXIS_CHILD;
8860 }
Owen Taylor3473f882001-02-23 17:55:21 +00008861 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008862 axis = AXIS_CHILD;
8863 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008864 } else if (CUR == '@') {
8865 NEXT;
8866 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008867 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008868 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008869 }
Owen Taylor3473f882001-02-23 17:55:21 +00008870 }
8871
8872 CHECK_ERROR;
8873
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008874 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008875 if (test == 0)
8876 return;
8877
8878#ifdef DEBUG_STEP
8879 xmlGenericError(xmlGenericErrorContext,
8880 "Basis : computing new set\n");
8881#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008882
Owen Taylor3473f882001-02-23 17:55:21 +00008883#ifdef DEBUG_STEP
8884 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008885 if (ctxt->value == NULL)
8886 xmlGenericError(xmlGenericErrorContext, "no value\n");
8887 else if (ctxt->value->nodesetval == NULL)
8888 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8889 else
8890 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008891#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008892
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008893#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008894eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008895#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008896 op1 = ctxt->comp->last;
8897 ctxt->comp->last = -1;
8898
Owen Taylor3473f882001-02-23 17:55:21 +00008899 SKIP_BLANKS;
8900 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008901 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008902 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008903
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008904#ifdef LIBXML_XPTR_ENABLED
8905 if (rangeto) {
8906 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8907 } else
8908#endif
8909 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8910 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008911
Owen Taylor3473f882001-02-23 17:55:21 +00008912 }
8913#ifdef DEBUG_STEP
8914 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008915 if (ctxt->value == NULL)
8916 xmlGenericError(xmlGenericErrorContext, "no value\n");
8917 else if (ctxt->value->nodesetval == NULL)
8918 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8919 else
8920 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8921 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008922#endif
8923}
8924
8925/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008926 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008927 * @ctxt: the XPath Parser context
8928 *
8929 * [3] RelativeLocationPath ::= Step
8930 * | RelativeLocationPath '/' Step
8931 * | AbbreviatedRelativeLocationPath
8932 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8933 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008934 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008935 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008936static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008937xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008938(xmlXPathParserContextPtr ctxt) {
8939 SKIP_BLANKS;
8940 if ((CUR == '/') && (NXT(1) == '/')) {
8941 SKIP(2);
8942 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008943 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8944 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008945 } else if (CUR == '/') {
8946 NEXT;
8947 SKIP_BLANKS;
8948 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008949 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008950 SKIP_BLANKS;
8951 while (CUR == '/') {
8952 if ((CUR == '/') && (NXT(1) == '/')) {
8953 SKIP(2);
8954 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008955 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008956 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008957 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008958 } else if (CUR == '/') {
8959 NEXT;
8960 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008961 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008962 }
8963 SKIP_BLANKS;
8964 }
8965}
8966
8967/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008968 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008969 * @ctxt: the XPath Parser context
8970 *
8971 * [1] LocationPath ::= RelativeLocationPath
8972 * | AbsoluteLocationPath
8973 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8974 * | AbbreviatedAbsoluteLocationPath
8975 * [10] AbbreviatedAbsoluteLocationPath ::=
8976 * '//' RelativeLocationPath
8977 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008978 * Compile a location path
8979 *
Owen Taylor3473f882001-02-23 17:55:21 +00008980 * // is short for /descendant-or-self::node()/. For example,
8981 * //para is short for /descendant-or-self::node()/child::para and
8982 * so will select any para element in the document (even a para element
8983 * that is a document element will be selected by //para since the
8984 * document element node is a child of the root node); div//para is
8985 * short for div/descendant-or-self::node()/child::para and so will
8986 * select all para descendants of div children.
8987 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008988static void
8989xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008990 SKIP_BLANKS;
8991 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008992 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008993 } else {
8994 while (CUR == '/') {
8995 if ((CUR == '/') && (NXT(1) == '/')) {
8996 SKIP(2);
8997 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008998 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8999 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009000 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009001 } else if (CUR == '/') {
9002 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009003 SKIP_BLANKS;
9004 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009005 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009006 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009007 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009008 }
9009 }
9010 }
9011}
9012
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009013/************************************************************************
9014 * *
9015 * XPath precompiled expression evaluation *
9016 * *
9017 ************************************************************************/
9018
Daniel Veillardf06307e2001-07-03 10:35:50 +00009019static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009020xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9021
9022/**
9023 * xmlXPathNodeCollectAndTest:
9024 * @ctxt: the XPath Parser context
9025 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009026 * @first: pointer to the first element in document order
9027 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009028 *
9029 * This is the function implementing a step: based on the current list
9030 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009031 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009032 *
9033 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009034 *
William M. Brack08171912003-12-29 02:52:11 +00009035 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009036 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009037static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009038xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009039 xmlXPathStepOpPtr op,
9040 xmlNodePtr * first, xmlNodePtr * last)
9041{
William M. Brack78637da2003-07-31 14:47:38 +00009042 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9043 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9044 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009045 const xmlChar *prefix = op->value4;
9046 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009047 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009048
9049#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009050 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009051#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009052 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009053 xmlNodeSetPtr ret, list;
9054 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009055 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009056 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009057 xmlNodePtr cur = NULL;
9058 xmlXPathObjectPtr obj;
9059 xmlNodeSetPtr nodelist;
9060 xmlNodePtr tmp;
9061
Daniel Veillardf06307e2001-07-03 10:35:50 +00009062 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009063 obj = valuePop(ctxt);
9064 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009065 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009066 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009067 URI = xmlXPathNsLookup(ctxt->context, prefix);
9068 if (URI == NULL)
9069 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009070 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009071#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009072 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009073#endif
9074 switch (axis) {
9075 case AXIS_ANCESTOR:
9076#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009077 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009078#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 first = NULL;
9080 next = xmlXPathNextAncestor;
9081 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009082 case AXIS_ANCESTOR_OR_SELF:
9083#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 xmlGenericError(xmlGenericErrorContext,
9085 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009086#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009087 first = NULL;
9088 next = xmlXPathNextAncestorOrSelf;
9089 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009090 case AXIS_ATTRIBUTE:
9091#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 first = NULL;
9095 last = NULL;
9096 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009097 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009099 case AXIS_CHILD:
9100#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009102#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 last = NULL;
9104 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009105 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009106 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009107 case AXIS_DESCENDANT:
9108#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009109 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009110#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111 last = NULL;
9112 next = xmlXPathNextDescendant;
9113 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009114 case AXIS_DESCENDANT_OR_SELF:
9115#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009116 xmlGenericError(xmlGenericErrorContext,
9117 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009118#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009119 last = NULL;
9120 next = xmlXPathNextDescendantOrSelf;
9121 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009122 case AXIS_FOLLOWING:
9123#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009124 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009125#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009126 last = NULL;
9127 next = xmlXPathNextFollowing;
9128 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009129 case AXIS_FOLLOWING_SIBLING:
9130#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 xmlGenericError(xmlGenericErrorContext,
9132 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009133#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 last = NULL;
9135 next = xmlXPathNextFollowingSibling;
9136 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009137 case AXIS_NAMESPACE:
9138#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009140#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 first = NULL;
9142 last = NULL;
9143 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009144 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009145 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009146 case AXIS_PARENT:
9147#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009149#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009150 first = NULL;
9151 next = xmlXPathNextParent;
9152 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009153 case AXIS_PRECEDING:
9154#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009155 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009156#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009157 first = NULL;
9158 next = xmlXPathNextPrecedingInternal;
9159 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009160 case AXIS_PRECEDING_SIBLING:
9161#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009162 xmlGenericError(xmlGenericErrorContext,
9163 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009164#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009165 first = NULL;
9166 next = xmlXPathNextPrecedingSibling;
9167 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009168 case AXIS_SELF:
9169#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009170 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009171#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009172 first = NULL;
9173 last = NULL;
9174 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009175 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009177 }
9178 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009179 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009180
9181 nodelist = obj->nodesetval;
9182 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009183 xmlXPathFreeObject(obj);
9184 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9185 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009186 }
9187 addNode = xmlXPathNodeSetAddUnique;
9188 ret = NULL;
9189#ifdef DEBUG_STEP
9190 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009191 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009192 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009193 case NODE_TEST_NONE:
9194 xmlGenericError(xmlGenericErrorContext,
9195 " searching for none !!!\n");
9196 break;
9197 case NODE_TEST_TYPE:
9198 xmlGenericError(xmlGenericErrorContext,
9199 " searching for type %d\n", type);
9200 break;
9201 case NODE_TEST_PI:
9202 xmlGenericError(xmlGenericErrorContext,
9203 " searching for PI !!!\n");
9204 break;
9205 case NODE_TEST_ALL:
9206 xmlGenericError(xmlGenericErrorContext,
9207 " searching for *\n");
9208 break;
9209 case NODE_TEST_NS:
9210 xmlGenericError(xmlGenericErrorContext,
9211 " searching for namespace %s\n",
9212 prefix);
9213 break;
9214 case NODE_TEST_NAME:
9215 xmlGenericError(xmlGenericErrorContext,
9216 " searching for name %s\n", name);
9217 if (prefix != NULL)
9218 xmlGenericError(xmlGenericErrorContext,
9219 " with namespace %s\n", prefix);
9220 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009221 }
9222 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9223#endif
9224 /*
9225 * 2.3 Node Tests
9226 * - For the attribute axis, the principal node type is attribute.
9227 * - For the namespace axis, the principal node type is namespace.
9228 * - For other axes, the principal node type is element.
9229 *
9230 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009231 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009232 * select all element children of the context node
9233 */
9234 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009235 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009236 ctxt->context->node = nodelist->nodeTab[i];
9237
Daniel Veillardf06307e2001-07-03 10:35:50 +00009238 cur = NULL;
9239 list = xmlXPathNodeSetCreate(NULL);
9240 do {
9241 cur = next(ctxt, cur);
9242 if (cur == NULL)
9243 break;
9244 if ((first != NULL) && (*first == cur))
9245 break;
9246 if (((t % 256) == 0) &&
9247 (first != NULL) && (*first != NULL) &&
9248 (xmlXPathCmpNodes(*first, cur) >= 0))
9249 break;
9250 if ((last != NULL) && (*last == cur))
9251 break;
9252 if (((t % 256) == 0) &&
9253 (last != NULL) && (*last != NULL) &&
9254 (xmlXPathCmpNodes(cur, *last) >= 0))
9255 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009256 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009257#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009258 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9259#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009260 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009261 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009262 ctxt->context->node = tmp;
9263 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009264 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009265 if ((cur->type == type) ||
9266 ((type == NODE_TYPE_NODE) &&
9267 ((cur->type == XML_DOCUMENT_NODE) ||
9268 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9269 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009270 (cur->type == XML_NAMESPACE_DECL) ||
9271 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009272 (cur->type == XML_PI_NODE) ||
9273 (cur->type == XML_COMMENT_NODE) ||
9274 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009275 (cur->type == XML_TEXT_NODE))) ||
9276 ((type == NODE_TYPE_TEXT) &&
9277 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009278#ifdef DEBUG_STEP
9279 n++;
9280#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009281 addNode(list, cur);
9282 }
9283 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009284 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009285 if (cur->type == XML_PI_NODE) {
9286 if ((name != NULL) &&
9287 (!xmlStrEqual(name, cur->name)))
9288 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009289#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009290 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009291#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009292 addNode(list, cur);
9293 }
9294 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009295 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009296 if (axis == AXIS_ATTRIBUTE) {
9297 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009298#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009299 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009300#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009301 addNode(list, cur);
9302 }
9303 } else if (axis == AXIS_NAMESPACE) {
9304 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009305#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009306 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009307#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009308 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9309 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009310 }
9311 } else {
9312 if (cur->type == XML_ELEMENT_NODE) {
9313 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009314#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009315 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009316#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009317 addNode(list, cur);
9318 } else if ((cur->ns != NULL) &&
9319 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009320#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009321 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009322#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009323 addNode(list, cur);
9324 }
9325 }
9326 }
9327 break;
9328 case NODE_TEST_NS:{
9329 TODO;
9330 break;
9331 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009332 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009333 switch (cur->type) {
9334 case XML_ELEMENT_NODE:
9335 if (xmlStrEqual(name, cur->name)) {
9336 if (prefix == NULL) {
9337 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009338#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009339 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009340#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009341 addNode(list, cur);
9342 }
9343 } else {
9344 if ((cur->ns != NULL) &&
9345 (xmlStrEqual(URI,
9346 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009347#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009348 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009349#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009350 addNode(list, cur);
9351 }
9352 }
9353 }
9354 break;
9355 case XML_ATTRIBUTE_NODE:{
9356 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009357
Daniel Veillardf06307e2001-07-03 10:35:50 +00009358 if (xmlStrEqual(name, attr->name)) {
9359 if (prefix == NULL) {
9360 if ((attr->ns == NULL) ||
9361 (attr->ns->prefix == NULL)) {
9362#ifdef DEBUG_STEP
9363 n++;
9364#endif
9365 addNode(list,
9366 (xmlNodePtr) attr);
9367 }
9368 } else {
9369 if ((attr->ns != NULL) &&
9370 (xmlStrEqual(URI,
9371 attr->ns->
9372 href))) {
9373#ifdef DEBUG_STEP
9374 n++;
9375#endif
9376 addNode(list,
9377 (xmlNodePtr) attr);
9378 }
9379 }
9380 }
9381 break;
9382 }
9383 case XML_NAMESPACE_DECL:
9384 if (cur->type == XML_NAMESPACE_DECL) {
9385 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009386
Daniel Veillardf06307e2001-07-03 10:35:50 +00009387 if ((ns->prefix != NULL) && (name != NULL)
9388 && (xmlStrEqual(ns->prefix, name))) {
9389#ifdef DEBUG_STEP
9390 n++;
9391#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009392 xmlXPathNodeSetAddNs(list,
9393 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009394 }
9395 }
9396 break;
9397 default:
9398 break;
9399 }
9400 break;
9401 break;
9402 }
9403 } while (cur != NULL);
9404
9405 /*
9406 * If there is some predicate filtering do it now
9407 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009408 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009409 xmlXPathObjectPtr obj2;
9410
9411 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9412 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9413 CHECK_TYPE0(XPATH_NODESET);
9414 obj2 = valuePop(ctxt);
9415 list = obj2->nodesetval;
9416 obj2->nodesetval = NULL;
9417 xmlXPathFreeObject(obj2);
9418 }
9419 if (ret == NULL) {
9420 ret = list;
9421 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009422 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009423 xmlXPathFreeNodeSet(list);
9424 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009425 }
9426 ctxt->context->node = tmp;
9427#ifdef DEBUG_STEP
9428 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009429 "\nExamined %d nodes, found %d nodes at that step\n",
9430 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009431#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009432 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009433 if ((obj->boolval) && (obj->user != NULL)) {
9434 ctxt->value->boolval = 1;
9435 ctxt->value->user = obj->user;
9436 obj->user = NULL;
9437 obj->boolval = 0;
9438 }
9439 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009440 return(t);
9441}
9442
9443/**
9444 * xmlXPathNodeCollectAndTestNth:
9445 * @ctxt: the XPath Parser context
9446 * @op: the XPath precompiled step operation
9447 * @indx: the index to collect
9448 * @first: pointer to the first element in document order
9449 * @last: pointer to the last element in document order
9450 *
9451 * This is the function implementing a step: based on the current list
9452 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009453 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009454 *
9455 * Pushes the new NodeSet resulting from the search.
9456 * Returns the number of node traversed
9457 */
9458static int
9459xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9460 xmlXPathStepOpPtr op, int indx,
9461 xmlNodePtr * first, xmlNodePtr * last)
9462{
William M. Brack78637da2003-07-31 14:47:38 +00009463 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9464 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9465 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009466 const xmlChar *prefix = op->value4;
9467 const xmlChar *name = op->value5;
9468 const xmlChar *URI = NULL;
9469 int n = 0, t = 0;
9470
9471 int i;
9472 xmlNodeSetPtr list;
9473 xmlXPathTraversalFunction next = NULL;
9474 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9475 xmlNodePtr cur = NULL;
9476 xmlXPathObjectPtr obj;
9477 xmlNodeSetPtr nodelist;
9478 xmlNodePtr tmp;
9479
9480 CHECK_TYPE0(XPATH_NODESET);
9481 obj = valuePop(ctxt);
9482 addNode = xmlXPathNodeSetAdd;
9483 if (prefix != NULL) {
9484 URI = xmlXPathNsLookup(ctxt->context, prefix);
9485 if (URI == NULL)
9486 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9487 }
9488#ifdef DEBUG_STEP_NTH
9489 xmlGenericError(xmlGenericErrorContext, "new step : ");
9490 if (first != NULL) {
9491 if (*first != NULL)
9492 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9493 (*first)->name);
9494 else
9495 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9496 }
9497 if (last != NULL) {
9498 if (*last != NULL)
9499 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9500 (*last)->name);
9501 else
9502 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9503 }
9504#endif
9505 switch (axis) {
9506 case AXIS_ANCESTOR:
9507#ifdef DEBUG_STEP_NTH
9508 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9509#endif
9510 first = NULL;
9511 next = xmlXPathNextAncestor;
9512 break;
9513 case AXIS_ANCESTOR_OR_SELF:
9514#ifdef DEBUG_STEP_NTH
9515 xmlGenericError(xmlGenericErrorContext,
9516 "axis 'ancestors-or-self' ");
9517#endif
9518 first = NULL;
9519 next = xmlXPathNextAncestorOrSelf;
9520 break;
9521 case AXIS_ATTRIBUTE:
9522#ifdef DEBUG_STEP_NTH
9523 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9524#endif
9525 first = NULL;
9526 last = NULL;
9527 next = xmlXPathNextAttribute;
9528 break;
9529 case AXIS_CHILD:
9530#ifdef DEBUG_STEP_NTH
9531 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9532#endif
9533 last = NULL;
9534 next = xmlXPathNextChild;
9535 break;
9536 case AXIS_DESCENDANT:
9537#ifdef DEBUG_STEP_NTH
9538 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9539#endif
9540 last = NULL;
9541 next = xmlXPathNextDescendant;
9542 break;
9543 case AXIS_DESCENDANT_OR_SELF:
9544#ifdef DEBUG_STEP_NTH
9545 xmlGenericError(xmlGenericErrorContext,
9546 "axis 'descendant-or-self' ");
9547#endif
9548 last = NULL;
9549 next = xmlXPathNextDescendantOrSelf;
9550 break;
9551 case AXIS_FOLLOWING:
9552#ifdef DEBUG_STEP_NTH
9553 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9554#endif
9555 last = NULL;
9556 next = xmlXPathNextFollowing;
9557 break;
9558 case AXIS_FOLLOWING_SIBLING:
9559#ifdef DEBUG_STEP_NTH
9560 xmlGenericError(xmlGenericErrorContext,
9561 "axis 'following-siblings' ");
9562#endif
9563 last = NULL;
9564 next = xmlXPathNextFollowingSibling;
9565 break;
9566 case AXIS_NAMESPACE:
9567#ifdef DEBUG_STEP_NTH
9568 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9569#endif
9570 last = NULL;
9571 first = NULL;
9572 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9573 break;
9574 case AXIS_PARENT:
9575#ifdef DEBUG_STEP_NTH
9576 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9577#endif
9578 first = NULL;
9579 next = xmlXPathNextParent;
9580 break;
9581 case AXIS_PRECEDING:
9582#ifdef DEBUG_STEP_NTH
9583 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9584#endif
9585 first = NULL;
9586 next = xmlXPathNextPrecedingInternal;
9587 break;
9588 case AXIS_PRECEDING_SIBLING:
9589#ifdef DEBUG_STEP_NTH
9590 xmlGenericError(xmlGenericErrorContext,
9591 "axis 'preceding-sibling' ");
9592#endif
9593 first = NULL;
9594 next = xmlXPathNextPrecedingSibling;
9595 break;
9596 case AXIS_SELF:
9597#ifdef DEBUG_STEP_NTH
9598 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9599#endif
9600 first = NULL;
9601 last = NULL;
9602 next = xmlXPathNextSelf;
9603 break;
9604 }
9605 if (next == NULL)
9606 return(0);
9607
9608 nodelist = obj->nodesetval;
9609 if (nodelist == NULL) {
9610 xmlXPathFreeObject(obj);
9611 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9612 return(0);
9613 }
9614 addNode = xmlXPathNodeSetAddUnique;
9615#ifdef DEBUG_STEP_NTH
9616 xmlGenericError(xmlGenericErrorContext,
9617 " context contains %d nodes\n", nodelist->nodeNr);
9618 switch (test) {
9619 case NODE_TEST_NONE:
9620 xmlGenericError(xmlGenericErrorContext,
9621 " searching for none !!!\n");
9622 break;
9623 case NODE_TEST_TYPE:
9624 xmlGenericError(xmlGenericErrorContext,
9625 " searching for type %d\n", type);
9626 break;
9627 case NODE_TEST_PI:
9628 xmlGenericError(xmlGenericErrorContext,
9629 " searching for PI !!!\n");
9630 break;
9631 case NODE_TEST_ALL:
9632 xmlGenericError(xmlGenericErrorContext,
9633 " searching for *\n");
9634 break;
9635 case NODE_TEST_NS:
9636 xmlGenericError(xmlGenericErrorContext,
9637 " searching for namespace %s\n",
9638 prefix);
9639 break;
9640 case NODE_TEST_NAME:
9641 xmlGenericError(xmlGenericErrorContext,
9642 " searching for name %s\n", name);
9643 if (prefix != NULL)
9644 xmlGenericError(xmlGenericErrorContext,
9645 " with namespace %s\n", prefix);
9646 break;
9647 }
9648 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9649#endif
9650 /*
9651 * 2.3 Node Tests
9652 * - For the attribute axis, the principal node type is attribute.
9653 * - For the namespace axis, the principal node type is namespace.
9654 * - For other axes, the principal node type is element.
9655 *
9656 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009657 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009658 * select all element children of the context node
9659 */
9660 tmp = ctxt->context->node;
9661 list = xmlXPathNodeSetCreate(NULL);
9662 for (i = 0; i < nodelist->nodeNr; i++) {
9663 ctxt->context->node = nodelist->nodeTab[i];
9664
9665 cur = NULL;
9666 n = 0;
9667 do {
9668 cur = next(ctxt, cur);
9669 if (cur == NULL)
9670 break;
9671 if ((first != NULL) && (*first == cur))
9672 break;
9673 if (((t % 256) == 0) &&
9674 (first != NULL) && (*first != NULL) &&
9675 (xmlXPathCmpNodes(*first, cur) >= 0))
9676 break;
9677 if ((last != NULL) && (*last == cur))
9678 break;
9679 if (((t % 256) == 0) &&
9680 (last != NULL) && (*last != NULL) &&
9681 (xmlXPathCmpNodes(cur, *last) >= 0))
9682 break;
9683 t++;
9684 switch (test) {
9685 case NODE_TEST_NONE:
9686 ctxt->context->node = tmp;
9687 STRANGE return(0);
9688 case NODE_TEST_TYPE:
9689 if ((cur->type == type) ||
9690 ((type == NODE_TYPE_NODE) &&
9691 ((cur->type == XML_DOCUMENT_NODE) ||
9692 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9693 (cur->type == XML_ELEMENT_NODE) ||
9694 (cur->type == XML_PI_NODE) ||
9695 (cur->type == XML_COMMENT_NODE) ||
9696 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009697 (cur->type == XML_TEXT_NODE))) ||
9698 ((type == NODE_TYPE_TEXT) &&
9699 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009700 n++;
9701 if (n == indx)
9702 addNode(list, cur);
9703 }
9704 break;
9705 case NODE_TEST_PI:
9706 if (cur->type == XML_PI_NODE) {
9707 if ((name != NULL) &&
9708 (!xmlStrEqual(name, cur->name)))
9709 break;
9710 n++;
9711 if (n == indx)
9712 addNode(list, cur);
9713 }
9714 break;
9715 case NODE_TEST_ALL:
9716 if (axis == AXIS_ATTRIBUTE) {
9717 if (cur->type == XML_ATTRIBUTE_NODE) {
9718 n++;
9719 if (n == indx)
9720 addNode(list, cur);
9721 }
9722 } else if (axis == AXIS_NAMESPACE) {
9723 if (cur->type == XML_NAMESPACE_DECL) {
9724 n++;
9725 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009726 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9727 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009728 }
9729 } else {
9730 if (cur->type == XML_ELEMENT_NODE) {
9731 if (prefix == NULL) {
9732 n++;
9733 if (n == indx)
9734 addNode(list, cur);
9735 } else if ((cur->ns != NULL) &&
9736 (xmlStrEqual(URI, cur->ns->href))) {
9737 n++;
9738 if (n == indx)
9739 addNode(list, cur);
9740 }
9741 }
9742 }
9743 break;
9744 case NODE_TEST_NS:{
9745 TODO;
9746 break;
9747 }
9748 case NODE_TEST_NAME:
9749 switch (cur->type) {
9750 case XML_ELEMENT_NODE:
9751 if (xmlStrEqual(name, cur->name)) {
9752 if (prefix == NULL) {
9753 if (cur->ns == NULL) {
9754 n++;
9755 if (n == indx)
9756 addNode(list, cur);
9757 }
9758 } else {
9759 if ((cur->ns != NULL) &&
9760 (xmlStrEqual(URI,
9761 cur->ns->href))) {
9762 n++;
9763 if (n == indx)
9764 addNode(list, cur);
9765 }
9766 }
9767 }
9768 break;
9769 case XML_ATTRIBUTE_NODE:{
9770 xmlAttrPtr attr = (xmlAttrPtr) cur;
9771
9772 if (xmlStrEqual(name, attr->name)) {
9773 if (prefix == NULL) {
9774 if ((attr->ns == NULL) ||
9775 (attr->ns->prefix == NULL)) {
9776 n++;
9777 if (n == indx)
9778 addNode(list, cur);
9779 }
9780 } else {
9781 if ((attr->ns != NULL) &&
9782 (xmlStrEqual(URI,
9783 attr->ns->
9784 href))) {
9785 n++;
9786 if (n == indx)
9787 addNode(list, cur);
9788 }
9789 }
9790 }
9791 break;
9792 }
9793 case XML_NAMESPACE_DECL:
9794 if (cur->type == XML_NAMESPACE_DECL) {
9795 xmlNsPtr ns = (xmlNsPtr) cur;
9796
9797 if ((ns->prefix != NULL) && (name != NULL)
9798 && (xmlStrEqual(ns->prefix, name))) {
9799 n++;
9800 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009801 xmlXPathNodeSetAddNs(list,
9802 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009803 }
9804 }
9805 break;
9806 default:
9807 break;
9808 }
9809 break;
9810 break;
9811 }
9812 } while (n < indx);
9813 }
9814 ctxt->context->node = tmp;
9815#ifdef DEBUG_STEP_NTH
9816 xmlGenericError(xmlGenericErrorContext,
9817 "\nExamined %d nodes, found %d nodes at that step\n",
9818 t, list->nodeNr);
9819#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009820 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009821 if ((obj->boolval) && (obj->user != NULL)) {
9822 ctxt->value->boolval = 1;
9823 ctxt->value->user = obj->user;
9824 obj->user = NULL;
9825 obj->boolval = 0;
9826 }
9827 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009828 return(t);
9829}
9830
9831/**
9832 * xmlXPathCompOpEvalFirst:
9833 * @ctxt: the XPath parser context with the compiled expression
9834 * @op: an XPath compiled operation
9835 * @first: the first elem found so far
9836 *
9837 * Evaluate the Precompiled XPath operation searching only the first
9838 * element in document order
9839 *
9840 * Returns the number of examined objects.
9841 */
9842static int
9843xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9844 xmlXPathStepOpPtr op, xmlNodePtr * first)
9845{
9846 int total = 0, cur;
9847 xmlXPathCompExprPtr comp;
9848 xmlXPathObjectPtr arg1, arg2;
9849
Daniel Veillard556c6682001-10-06 09:59:51 +00009850 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009851 comp = ctxt->comp;
9852 switch (op->op) {
9853 case XPATH_OP_END:
9854 return (0);
9855 case XPATH_OP_UNION:
9856 total =
9857 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9858 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009859 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009860 if ((ctxt->value != NULL)
9861 && (ctxt->value->type == XPATH_NODESET)
9862 && (ctxt->value->nodesetval != NULL)
9863 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9864 /*
9865 * limit tree traversing to first node in the result
9866 */
9867 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9868 *first = ctxt->value->nodesetval->nodeTab[0];
9869 }
9870 cur =
9871 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9872 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009873 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009874 CHECK_TYPE0(XPATH_NODESET);
9875 arg2 = valuePop(ctxt);
9876
9877 CHECK_TYPE0(XPATH_NODESET);
9878 arg1 = valuePop(ctxt);
9879
9880 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9881 arg2->nodesetval);
9882 valuePush(ctxt, arg1);
9883 xmlXPathFreeObject(arg2);
9884 /* optimizer */
9885 if (total > cur)
9886 xmlXPathCompSwap(op);
9887 return (total + cur);
9888 case XPATH_OP_ROOT:
9889 xmlXPathRoot(ctxt);
9890 return (0);
9891 case XPATH_OP_NODE:
9892 if (op->ch1 != -1)
9893 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009894 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009895 if (op->ch2 != -1)
9896 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009897 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009898 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9899 return (total);
9900 case XPATH_OP_RESET:
9901 if (op->ch1 != -1)
9902 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009903 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009904 if (op->ch2 != -1)
9905 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009906 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009907 ctxt->context->node = NULL;
9908 return (total);
9909 case XPATH_OP_COLLECT:{
9910 if (op->ch1 == -1)
9911 return (total);
9912
9913 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009914 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009915
9916 /*
9917 * Optimization for [n] selection where n is a number
9918 */
9919 if ((op->ch2 != -1) &&
9920 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9921 (comp->steps[op->ch2].ch1 == -1) &&
9922 (comp->steps[op->ch2].ch2 != -1) &&
9923 (comp->steps[comp->steps[op->ch2].ch2].op ==
9924 XPATH_OP_VALUE)) {
9925 xmlXPathObjectPtr val;
9926
9927 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9928 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9929 int indx = (int) val->floatval;
9930
9931 if (val->floatval == (float) indx) {
9932 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9933 first, NULL);
9934 return (total);
9935 }
9936 }
9937 }
9938 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9939 return (total);
9940 }
9941 case XPATH_OP_VALUE:
9942 valuePush(ctxt,
9943 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9944 return (0);
9945 case XPATH_OP_SORT:
9946 if (op->ch1 != -1)
9947 total +=
9948 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9949 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009950 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009951 if ((ctxt->value != NULL)
9952 && (ctxt->value->type == XPATH_NODESET)
9953 && (ctxt->value->nodesetval != NULL))
9954 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9955 return (total);
9956 default:
9957 return (xmlXPathCompOpEval(ctxt, op));
9958 }
9959}
9960
9961/**
9962 * xmlXPathCompOpEvalLast:
9963 * @ctxt: the XPath parser context with the compiled expression
9964 * @op: an XPath compiled operation
9965 * @last: the last elem found so far
9966 *
9967 * Evaluate the Precompiled XPath operation searching only the last
9968 * element in document order
9969 *
William M. Brack08171912003-12-29 02:52:11 +00009970 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009971 */
9972static int
9973xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9974 xmlNodePtr * last)
9975{
9976 int total = 0, cur;
9977 xmlXPathCompExprPtr comp;
9978 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009979 xmlNodePtr bak;
9980 xmlDocPtr bakd;
9981 int pp;
9982 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009983
Daniel Veillard556c6682001-10-06 09:59:51 +00009984 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009985 comp = ctxt->comp;
9986 switch (op->op) {
9987 case XPATH_OP_END:
9988 return (0);
9989 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009990 bakd = ctxt->context->doc;
9991 bak = ctxt->context->node;
9992 pp = ctxt->context->proximityPosition;
9993 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009994 total =
9995 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009996 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009997 if ((ctxt->value != NULL)
9998 && (ctxt->value->type == XPATH_NODESET)
9999 && (ctxt->value->nodesetval != NULL)
10000 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10001 /*
10002 * limit tree traversing to first node in the result
10003 */
10004 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10005 *last =
10006 ctxt->value->nodesetval->nodeTab[ctxt->value->
10007 nodesetval->nodeNr -
10008 1];
10009 }
William M. Brackce4fc562004-01-22 02:47:18 +000010010 ctxt->context->doc = bakd;
10011 ctxt->context->node = bak;
10012 ctxt->context->proximityPosition = pp;
10013 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010014 cur =
10015 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010016 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010017 if ((ctxt->value != NULL)
10018 && (ctxt->value->type == XPATH_NODESET)
10019 && (ctxt->value->nodesetval != NULL)
10020 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10021 }
10022 CHECK_TYPE0(XPATH_NODESET);
10023 arg2 = valuePop(ctxt);
10024
10025 CHECK_TYPE0(XPATH_NODESET);
10026 arg1 = valuePop(ctxt);
10027
10028 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10029 arg2->nodesetval);
10030 valuePush(ctxt, arg1);
10031 xmlXPathFreeObject(arg2);
10032 /* optimizer */
10033 if (total > cur)
10034 xmlXPathCompSwap(op);
10035 return (total + cur);
10036 case XPATH_OP_ROOT:
10037 xmlXPathRoot(ctxt);
10038 return (0);
10039 case XPATH_OP_NODE:
10040 if (op->ch1 != -1)
10041 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010042 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 if (op->ch2 != -1)
10044 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010045 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010046 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10047 return (total);
10048 case XPATH_OP_RESET:
10049 if (op->ch1 != -1)
10050 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010051 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010052 if (op->ch2 != -1)
10053 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010054 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010055 ctxt->context->node = NULL;
10056 return (total);
10057 case XPATH_OP_COLLECT:{
10058 if (op->ch1 == -1)
10059 return (0);
10060
10061 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010062 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010063
10064 /*
10065 * Optimization for [n] selection where n is a number
10066 */
10067 if ((op->ch2 != -1) &&
10068 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10069 (comp->steps[op->ch2].ch1 == -1) &&
10070 (comp->steps[op->ch2].ch2 != -1) &&
10071 (comp->steps[comp->steps[op->ch2].ch2].op ==
10072 XPATH_OP_VALUE)) {
10073 xmlXPathObjectPtr val;
10074
10075 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10076 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10077 int indx = (int) val->floatval;
10078
10079 if (val->floatval == (float) indx) {
10080 total +=
10081 xmlXPathNodeCollectAndTestNth(ctxt, op,
10082 indx, NULL,
10083 last);
10084 return (total);
10085 }
10086 }
10087 }
10088 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10089 return (total);
10090 }
10091 case XPATH_OP_VALUE:
10092 valuePush(ctxt,
10093 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10094 return (0);
10095 case XPATH_OP_SORT:
10096 if (op->ch1 != -1)
10097 total +=
10098 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10099 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010100 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010101 if ((ctxt->value != NULL)
10102 && (ctxt->value->type == XPATH_NODESET)
10103 && (ctxt->value->nodesetval != NULL))
10104 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10105 return (total);
10106 default:
10107 return (xmlXPathCompOpEval(ctxt, op));
10108 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010109}
10110
Owen Taylor3473f882001-02-23 17:55:21 +000010111/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010112 * xmlXPathCompOpEval:
10113 * @ctxt: the XPath parser context with the compiled expression
10114 * @op: an XPath compiled operation
10115 *
10116 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010117 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010118 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010119static int
10120xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10121{
10122 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010123 int equal, ret;
10124 xmlXPathCompExprPtr comp;
10125 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010126 xmlNodePtr bak;
10127 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010128 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010129 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010130
Daniel Veillard556c6682001-10-06 09:59:51 +000010131 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010132 comp = ctxt->comp;
10133 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010134 case XPATH_OP_END:
10135 return (0);
10136 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010137 bakd = ctxt->context->doc;
10138 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010139 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010140 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010141 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010142 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010143 xmlXPathBooleanFunction(ctxt, 1);
10144 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10145 return (total);
10146 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010147 ctxt->context->doc = bakd;
10148 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010149 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010150 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010151 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010152 if (ctxt->error) {
10153 xmlXPathFreeObject(arg2);
10154 return(0);
10155 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010156 xmlXPathBooleanFunction(ctxt, 1);
10157 arg1 = valuePop(ctxt);
10158 arg1->boolval &= arg2->boolval;
10159 valuePush(ctxt, arg1);
10160 xmlXPathFreeObject(arg2);
10161 return (total);
10162 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010163 bakd = ctxt->context->doc;
10164 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010165 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010166 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010167 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010168 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010169 xmlXPathBooleanFunction(ctxt, 1);
10170 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10171 return (total);
10172 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010173 ctxt->context->doc = bakd;
10174 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010175 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010176 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010177 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010178 if (ctxt->error) {
10179 xmlXPathFreeObject(arg2);
10180 return(0);
10181 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010182 xmlXPathBooleanFunction(ctxt, 1);
10183 arg1 = valuePop(ctxt);
10184 arg1->boolval |= arg2->boolval;
10185 valuePush(ctxt, arg1);
10186 xmlXPathFreeObject(arg2);
10187 return (total);
10188 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010189 bakd = ctxt->context->doc;
10190 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010191 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010192 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010193 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010194 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010195 ctxt->context->doc = bakd;
10196 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010197 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010198 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010199 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010200 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010201 if (op->value)
10202 equal = xmlXPathEqualValues(ctxt);
10203 else
10204 equal = xmlXPathNotEqualValues(ctxt);
10205 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010206 return (total);
10207 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010208 bakd = ctxt->context->doc;
10209 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010210 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010211 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010212 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010213 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010214 ctxt->context->doc = bakd;
10215 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010216 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010217 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010218 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010219 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010220 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10221 valuePush(ctxt, xmlXPathNewBoolean(ret));
10222 return (total);
10223 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010224 bakd = ctxt->context->doc;
10225 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010226 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010227 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010228 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010229 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010230 if (op->ch2 != -1) {
10231 ctxt->context->doc = bakd;
10232 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010233 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010234 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010235 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010236 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010237 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010238 if (op->value == 0)
10239 xmlXPathSubValues(ctxt);
10240 else if (op->value == 1)
10241 xmlXPathAddValues(ctxt);
10242 else if (op->value == 2)
10243 xmlXPathValueFlipSign(ctxt);
10244 else if (op->value == 3) {
10245 CAST_TO_NUMBER;
10246 CHECK_TYPE0(XPATH_NUMBER);
10247 }
10248 return (total);
10249 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010250 bakd = ctxt->context->doc;
10251 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010252 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010253 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010254 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010255 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010256 ctxt->context->doc = bakd;
10257 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010258 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010259 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010260 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010261 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010262 if (op->value == 0)
10263 xmlXPathMultValues(ctxt);
10264 else if (op->value == 1)
10265 xmlXPathDivValues(ctxt);
10266 else if (op->value == 2)
10267 xmlXPathModValues(ctxt);
10268 return (total);
10269 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010270 bakd = ctxt->context->doc;
10271 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010272 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010273 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010274 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010275 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010276 ctxt->context->doc = bakd;
10277 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010278 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010279 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010280 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010281 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010282 CHECK_TYPE0(XPATH_NODESET);
10283 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010284
Daniel Veillardf06307e2001-07-03 10:35:50 +000010285 CHECK_TYPE0(XPATH_NODESET);
10286 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010287
Daniel Veillardf06307e2001-07-03 10:35:50 +000010288 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10289 arg2->nodesetval);
10290 valuePush(ctxt, arg1);
10291 xmlXPathFreeObject(arg2);
10292 return (total);
10293 case XPATH_OP_ROOT:
10294 xmlXPathRoot(ctxt);
10295 return (total);
10296 case XPATH_OP_NODE:
10297 if (op->ch1 != -1)
10298 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010299 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010300 if (op->ch2 != -1)
10301 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010302 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010303 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10304 return (total);
10305 case XPATH_OP_RESET:
10306 if (op->ch1 != -1)
10307 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010308 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010309 if (op->ch2 != -1)
10310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010311 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010312 ctxt->context->node = NULL;
10313 return (total);
10314 case XPATH_OP_COLLECT:{
10315 if (op->ch1 == -1)
10316 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010317
Daniel Veillardf06307e2001-07-03 10:35:50 +000010318 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010319 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010320
Daniel Veillardf06307e2001-07-03 10:35:50 +000010321 /*
10322 * Optimization for [n] selection where n is a number
10323 */
10324 if ((op->ch2 != -1) &&
10325 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10326 (comp->steps[op->ch2].ch1 == -1) &&
10327 (comp->steps[op->ch2].ch2 != -1) &&
10328 (comp->steps[comp->steps[op->ch2].ch2].op ==
10329 XPATH_OP_VALUE)) {
10330 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010331
Daniel Veillardf06307e2001-07-03 10:35:50 +000010332 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10333 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10334 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010335
Daniel Veillardf06307e2001-07-03 10:35:50 +000010336 if (val->floatval == (float) indx) {
10337 total +=
10338 xmlXPathNodeCollectAndTestNth(ctxt, op,
10339 indx, NULL,
10340 NULL);
10341 return (total);
10342 }
10343 }
10344 }
10345 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10346 return (total);
10347 }
10348 case XPATH_OP_VALUE:
10349 valuePush(ctxt,
10350 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10351 return (total);
10352 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010353 xmlXPathObjectPtr val;
10354
Daniel Veillardf06307e2001-07-03 10:35:50 +000010355 if (op->ch1 != -1)
10356 total +=
10357 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010358 if (op->value5 == NULL) {
10359 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10360 if (val == NULL) {
10361 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10362 return(0);
10363 }
10364 valuePush(ctxt, val);
10365 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010366 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010367
Daniel Veillardf06307e2001-07-03 10:35:50 +000010368 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10369 if (URI == NULL) {
10370 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010371 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010372 op->value4, op->value5);
10373 return (total);
10374 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010375 val = xmlXPathVariableLookupNS(ctxt->context,
10376 op->value4, URI);
10377 if (val == NULL) {
10378 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10379 return(0);
10380 }
10381 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010382 }
10383 return (total);
10384 }
10385 case XPATH_OP_FUNCTION:{
10386 xmlXPathFunction func;
10387 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010388 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010389
10390 if (op->ch1 != -1)
10391 total +=
10392 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010393 if (ctxt->valueNr < op->value) {
10394 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010395 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010396 ctxt->error = XPATH_INVALID_OPERAND;
10397 return (total);
10398 }
10399 for (i = 0; i < op->value; i++)
10400 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10401 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010402 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010403 ctxt->error = XPATH_INVALID_OPERAND;
10404 return (total);
10405 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010406 if (op->cache != NULL)
10407 func = (xmlXPathFunction) op->cache;
10408 else {
10409 const xmlChar *URI = NULL;
10410
10411 if (op->value5 == NULL)
10412 func =
10413 xmlXPathFunctionLookup(ctxt->context,
10414 op->value4);
10415 else {
10416 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10417 if (URI == NULL) {
10418 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010419 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010420 op->value4, op->value5);
10421 return (total);
10422 }
10423 func = xmlXPathFunctionLookupNS(ctxt->context,
10424 op->value4, URI);
10425 }
10426 if (func == NULL) {
10427 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010428 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010429 op->value4);
10430 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010431 }
10432 op->cache = (void *) func;
10433 op->cacheURI = (void *) URI;
10434 }
10435 oldFunc = ctxt->context->function;
10436 oldFuncURI = ctxt->context->functionURI;
10437 ctxt->context->function = op->value4;
10438 ctxt->context->functionURI = op->cacheURI;
10439 func(ctxt, op->value);
10440 ctxt->context->function = oldFunc;
10441 ctxt->context->functionURI = oldFuncURI;
10442 return (total);
10443 }
10444 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010445 bakd = ctxt->context->doc;
10446 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010447 pp = ctxt->context->proximityPosition;
10448 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010449 if (op->ch1 != -1)
10450 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010451 ctxt->context->contextSize = cs;
10452 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010453 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010454 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010455 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010456 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010457 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010458 ctxt->context->doc = bakd;
10459 ctxt->context->node = bak;
10460 CHECK_ERROR0;
10461 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010462 return (total);
10463 case XPATH_OP_PREDICATE:
10464 case XPATH_OP_FILTER:{
10465 xmlXPathObjectPtr res;
10466 xmlXPathObjectPtr obj, tmp;
10467 xmlNodeSetPtr newset = NULL;
10468 xmlNodeSetPtr oldset;
10469 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010470 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010471 int i;
10472
10473 /*
10474 * Optimization for ()[1] selection i.e. the first elem
10475 */
10476 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10477 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10478 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10479 xmlXPathObjectPtr val;
10480
10481 val = comp->steps[op->ch2].value4;
10482 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10483 (val->floatval == 1.0)) {
10484 xmlNodePtr first = NULL;
10485
10486 total +=
10487 xmlXPathCompOpEvalFirst(ctxt,
10488 &comp->steps[op->ch1],
10489 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010490 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010491 /*
10492 * The nodeset should be in document order,
10493 * Keep only the first value
10494 */
10495 if ((ctxt->value != NULL) &&
10496 (ctxt->value->type == XPATH_NODESET) &&
10497 (ctxt->value->nodesetval != NULL) &&
10498 (ctxt->value->nodesetval->nodeNr > 1))
10499 ctxt->value->nodesetval->nodeNr = 1;
10500 return (total);
10501 }
10502 }
10503 /*
10504 * Optimization for ()[last()] selection i.e. the last elem
10505 */
10506 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10507 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10508 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10509 int f = comp->steps[op->ch2].ch1;
10510
10511 if ((f != -1) &&
10512 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10513 (comp->steps[f].value5 == NULL) &&
10514 (comp->steps[f].value == 0) &&
10515 (comp->steps[f].value4 != NULL) &&
10516 (xmlStrEqual
10517 (comp->steps[f].value4, BAD_CAST "last"))) {
10518 xmlNodePtr last = NULL;
10519
10520 total +=
10521 xmlXPathCompOpEvalLast(ctxt,
10522 &comp->steps[op->ch1],
10523 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010524 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010525 /*
10526 * The nodeset should be in document order,
10527 * Keep only the last value
10528 */
10529 if ((ctxt->value != NULL) &&
10530 (ctxt->value->type == XPATH_NODESET) &&
10531 (ctxt->value->nodesetval != NULL) &&
10532 (ctxt->value->nodesetval->nodeTab != NULL) &&
10533 (ctxt->value->nodesetval->nodeNr > 1)) {
10534 ctxt->value->nodesetval->nodeTab[0] =
10535 ctxt->value->nodesetval->nodeTab[ctxt->
10536 value->
10537 nodesetval->
10538 nodeNr -
10539 1];
10540 ctxt->value->nodesetval->nodeNr = 1;
10541 }
10542 return (total);
10543 }
10544 }
10545
10546 if (op->ch1 != -1)
10547 total +=
10548 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010549 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010550 if (op->ch2 == -1)
10551 return (total);
10552 if (ctxt->value == NULL)
10553 return (total);
10554
10555 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010556
10557#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010558 /*
10559 * Hum are we filtering the result of an XPointer expression
10560 */
10561 if (ctxt->value->type == XPATH_LOCATIONSET) {
10562 xmlLocationSetPtr newlocset = NULL;
10563 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010564
Daniel Veillardf06307e2001-07-03 10:35:50 +000010565 /*
10566 * Extract the old locset, and then evaluate the result of the
10567 * expression for all the element in the locset. use it to grow
10568 * up a new locset.
10569 */
10570 CHECK_TYPE0(XPATH_LOCATIONSET);
10571 obj = valuePop(ctxt);
10572 oldlocset = obj->user;
10573 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010574
Daniel Veillardf06307e2001-07-03 10:35:50 +000010575 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10576 ctxt->context->contextSize = 0;
10577 ctxt->context->proximityPosition = 0;
10578 if (op->ch2 != -1)
10579 total +=
10580 xmlXPathCompOpEval(ctxt,
10581 &comp->steps[op->ch2]);
10582 res = valuePop(ctxt);
10583 if (res != NULL)
10584 xmlXPathFreeObject(res);
10585 valuePush(ctxt, obj);
10586 CHECK_ERROR0;
10587 return (total);
10588 }
10589 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010590
Daniel Veillardf06307e2001-07-03 10:35:50 +000010591 for (i = 0; i < oldlocset->locNr; i++) {
10592 /*
10593 * Run the evaluation with a node list made of a
10594 * single item in the nodelocset.
10595 */
10596 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010597 ctxt->context->contextSize = oldlocset->locNr;
10598 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010599 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10600 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010601
Daniel Veillardf06307e2001-07-03 10:35:50 +000010602 if (op->ch2 != -1)
10603 total +=
10604 xmlXPathCompOpEval(ctxt,
10605 &comp->steps[op->ch2]);
10606 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010607
Daniel Veillardf06307e2001-07-03 10:35:50 +000010608 /*
10609 * The result of the evaluation need to be tested to
10610 * decided whether the filter succeeded or not
10611 */
10612 res = valuePop(ctxt);
10613 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10614 xmlXPtrLocationSetAdd(newlocset,
10615 xmlXPathObjectCopy
10616 (oldlocset->locTab[i]));
10617 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010618
Daniel Veillardf06307e2001-07-03 10:35:50 +000010619 /*
10620 * Cleanup
10621 */
10622 if (res != NULL)
10623 xmlXPathFreeObject(res);
10624 if (ctxt->value == tmp) {
10625 res = valuePop(ctxt);
10626 xmlXPathFreeObject(res);
10627 }
10628
10629 ctxt->context->node = NULL;
10630 }
10631
10632 /*
10633 * The result is used as the new evaluation locset.
10634 */
10635 xmlXPathFreeObject(obj);
10636 ctxt->context->node = NULL;
10637 ctxt->context->contextSize = -1;
10638 ctxt->context->proximityPosition = -1;
10639 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10640 ctxt->context->node = oldnode;
10641 return (total);
10642 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010643#endif /* LIBXML_XPTR_ENABLED */
10644
Daniel Veillardf06307e2001-07-03 10:35:50 +000010645 /*
10646 * Extract the old set, and then evaluate the result of the
10647 * expression for all the element in the set. use it to grow
10648 * up a new set.
10649 */
10650 CHECK_TYPE0(XPATH_NODESET);
10651 obj = valuePop(ctxt);
10652 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010653
Daniel Veillardf06307e2001-07-03 10:35:50 +000010654 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010655 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010656 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010657
Daniel Veillardf06307e2001-07-03 10:35:50 +000010658 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10659 ctxt->context->contextSize = 0;
10660 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010661/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010662 if (op->ch2 != -1)
10663 total +=
10664 xmlXPathCompOpEval(ctxt,
10665 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010666 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010667 res = valuePop(ctxt);
10668 if (res != NULL)
10669 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010670*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010671 valuePush(ctxt, obj);
10672 ctxt->context->node = oldnode;
10673 CHECK_ERROR0;
10674 } else {
10675 /*
10676 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010677 * Also set the xpath document in case things like
10678 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010679 */
10680 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010681
Daniel Veillardf06307e2001-07-03 10:35:50 +000010682 for (i = 0; i < oldset->nodeNr; i++) {
10683 /*
10684 * Run the evaluation with a node list made of
10685 * a single item in the nodeset.
10686 */
10687 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010688 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10689 (oldset->nodeTab[i]->doc != NULL))
10690 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010691 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10692 valuePush(ctxt, tmp);
10693 ctxt->context->contextSize = oldset->nodeNr;
10694 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010695
Daniel Veillardf06307e2001-07-03 10:35:50 +000010696 if (op->ch2 != -1)
10697 total +=
10698 xmlXPathCompOpEval(ctxt,
10699 &comp->steps[op->ch2]);
10700 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010701
Daniel Veillardf06307e2001-07-03 10:35:50 +000010702 /*
William M. Brack08171912003-12-29 02:52:11 +000010703 * The result of the evaluation needs to be tested to
10704 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010705 */
10706 res = valuePop(ctxt);
10707 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10708 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10709 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010710
Daniel Veillardf06307e2001-07-03 10:35:50 +000010711 /*
10712 * Cleanup
10713 */
10714 if (res != NULL)
10715 xmlXPathFreeObject(res);
10716 if (ctxt->value == tmp) {
10717 res = valuePop(ctxt);
10718 xmlXPathFreeObject(res);
10719 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010720
Daniel Veillardf06307e2001-07-03 10:35:50 +000010721 ctxt->context->node = NULL;
10722 }
10723
10724 /*
10725 * The result is used as the new evaluation set.
10726 */
10727 xmlXPathFreeObject(obj);
10728 ctxt->context->node = NULL;
10729 ctxt->context->contextSize = -1;
10730 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010731 /* may want to move this past the '}' later */
10732 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010733 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10734 }
10735 ctxt->context->node = oldnode;
10736 return (total);
10737 }
10738 case XPATH_OP_SORT:
10739 if (op->ch1 != -1)
10740 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010741 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010742 if ((ctxt->value != NULL) &&
10743 (ctxt->value->type == XPATH_NODESET) &&
10744 (ctxt->value->nodesetval != NULL))
10745 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10746 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010747#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010748 case XPATH_OP_RANGETO:{
10749 xmlXPathObjectPtr range;
10750 xmlXPathObjectPtr res, obj;
10751 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010752 xmlLocationSetPtr newlocset = NULL;
10753 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010754 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010755 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010756
Daniel Veillardf06307e2001-07-03 10:35:50 +000010757 if (op->ch1 != -1)
10758 total +=
10759 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10760 if (op->ch2 == -1)
10761 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010762
William M. Brack08171912003-12-29 02:52:11 +000010763 if (ctxt->value->type == XPATH_LOCATIONSET) {
10764 /*
10765 * Extract the old locset, and then evaluate the result of the
10766 * expression for all the element in the locset. use it to grow
10767 * up a new locset.
10768 */
10769 CHECK_TYPE0(XPATH_LOCATIONSET);
10770 obj = valuePop(ctxt);
10771 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010772
William M. Brack08171912003-12-29 02:52:11 +000010773 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010774 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010775 ctxt->context->contextSize = 0;
10776 ctxt->context->proximityPosition = 0;
10777 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10778 res = valuePop(ctxt);
10779 if (res != NULL)
10780 xmlXPathFreeObject(res);
10781 valuePush(ctxt, obj);
10782 CHECK_ERROR0;
10783 return (total);
10784 }
10785 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010786
William M. Brack08171912003-12-29 02:52:11 +000010787 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010788 /*
William M. Brack08171912003-12-29 02:52:11 +000010789 * Run the evaluation with a node list made of a
10790 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010791 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010792 ctxt->context->node = oldlocset->locTab[i]->user;
10793 ctxt->context->contextSize = oldlocset->locNr;
10794 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010795 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10796 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010797
Daniel Veillardf06307e2001-07-03 10:35:50 +000010798 if (op->ch2 != -1)
10799 total +=
10800 xmlXPathCompOpEval(ctxt,
10801 &comp->steps[op->ch2]);
10802 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010803
Daniel Veillardf06307e2001-07-03 10:35:50 +000010804 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010805 if (res->type == XPATH_LOCATIONSET) {
10806 xmlLocationSetPtr rloc =
10807 (xmlLocationSetPtr)res->user;
10808 for (j=0; j<rloc->locNr; j++) {
10809 range = xmlXPtrNewRange(
10810 oldlocset->locTab[i]->user,
10811 oldlocset->locTab[i]->index,
10812 rloc->locTab[j]->user2,
10813 rloc->locTab[j]->index2);
10814 if (range != NULL) {
10815 xmlXPtrLocationSetAdd(newlocset, range);
10816 }
10817 }
10818 } else {
10819 range = xmlXPtrNewRangeNodeObject(
10820 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10821 if (range != NULL) {
10822 xmlXPtrLocationSetAdd(newlocset,range);
10823 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010824 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010825
Daniel Veillardf06307e2001-07-03 10:35:50 +000010826 /*
10827 * Cleanup
10828 */
10829 if (res != NULL)
10830 xmlXPathFreeObject(res);
10831 if (ctxt->value == tmp) {
10832 res = valuePop(ctxt);
10833 xmlXPathFreeObject(res);
10834 }
10835
10836 ctxt->context->node = NULL;
10837 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010838 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010839 CHECK_TYPE0(XPATH_NODESET);
10840 obj = valuePop(ctxt);
10841 oldset = obj->nodesetval;
10842 ctxt->context->node = NULL;
10843
10844 newlocset = xmlXPtrLocationSetCreate(NULL);
10845
10846 if (oldset != NULL) {
10847 for (i = 0; i < oldset->nodeNr; i++) {
10848 /*
10849 * Run the evaluation with a node list made of a single item
10850 * in the nodeset.
10851 */
10852 ctxt->context->node = oldset->nodeTab[i];
10853 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10854 valuePush(ctxt, tmp);
10855
10856 if (op->ch2 != -1)
10857 total +=
10858 xmlXPathCompOpEval(ctxt,
10859 &comp->steps[op->ch2]);
10860 CHECK_ERROR0;
10861
William M. Brack08171912003-12-29 02:52:11 +000010862 res = valuePop(ctxt);
10863 range =
10864 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10865 res);
10866 if (range != NULL) {
10867 xmlXPtrLocationSetAdd(newlocset, range);
10868 }
10869
10870 /*
10871 * Cleanup
10872 */
10873 if (res != NULL)
10874 xmlXPathFreeObject(res);
10875 if (ctxt->value == tmp) {
10876 res = valuePop(ctxt);
10877 xmlXPathFreeObject(res);
10878 }
10879
10880 ctxt->context->node = NULL;
10881 }
10882 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010883 }
10884
10885 /*
10886 * The result is used as the new evaluation set.
10887 */
10888 xmlXPathFreeObject(obj);
10889 ctxt->context->node = NULL;
10890 ctxt->context->contextSize = -1;
10891 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010892 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010893 return (total);
10894 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010895#endif /* LIBXML_XPTR_ENABLED */
10896 }
10897 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010898 "XPath: unknown precompiled operation %d\n", op->op);
10899 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010900}
10901
10902/**
10903 * xmlXPathRunEval:
10904 * @ctxt: the XPath parser context with the compiled expression
10905 *
10906 * Evaluate the Precompiled XPath expression in the given context.
10907 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010908static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010909xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10910 xmlXPathCompExprPtr comp;
10911
10912 if ((ctxt == NULL) || (ctxt->comp == NULL))
10913 return;
10914
10915 if (ctxt->valueTab == NULL) {
10916 /* Allocate the value stack */
10917 ctxt->valueTab = (xmlXPathObjectPtr *)
10918 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10919 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010920 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010921 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010922 }
10923 ctxt->valueNr = 0;
10924 ctxt->valueMax = 10;
10925 ctxt->value = NULL;
10926 }
10927 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010928 if(comp->last < 0) {
10929 xmlGenericError(xmlGenericErrorContext,
10930 "xmlXPathRunEval: last is less than zero\n");
10931 return;
10932 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010933 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10934}
10935
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010936/************************************************************************
10937 * *
10938 * Public interfaces *
10939 * *
10940 ************************************************************************/
10941
10942/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010943 * xmlXPathEvalPredicate:
10944 * @ctxt: the XPath context
10945 * @res: the Predicate Expression evaluation result
10946 *
10947 * Evaluate a predicate result for the current node.
10948 * A PredicateExpr is evaluated by evaluating the Expr and converting
10949 * the result to a boolean. If the result is a number, the result will
10950 * be converted to true if the number is equal to the position of the
10951 * context node in the context node list (as returned by the position
10952 * function) and will be converted to false otherwise; if the result
10953 * is not a number, then the result will be converted as if by a call
10954 * to the boolean function.
10955 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010956 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010957 */
10958int
10959xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010960 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010961 switch (res->type) {
10962 case XPATH_BOOLEAN:
10963 return(res->boolval);
10964 case XPATH_NUMBER:
10965 return(res->floatval == ctxt->proximityPosition);
10966 case XPATH_NODESET:
10967 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010968 if (res->nodesetval == NULL)
10969 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010970 return(res->nodesetval->nodeNr != 0);
10971 case XPATH_STRING:
10972 return((res->stringval != NULL) &&
10973 (xmlStrlen(res->stringval) != 0));
10974 default:
10975 STRANGE
10976 }
10977 return(0);
10978}
10979
10980/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010981 * xmlXPathEvaluatePredicateResult:
10982 * @ctxt: the XPath Parser context
10983 * @res: the Predicate Expression evaluation result
10984 *
10985 * Evaluate a predicate result for the current node.
10986 * A PredicateExpr is evaluated by evaluating the Expr and converting
10987 * the result to a boolean. If the result is a number, the result will
10988 * be converted to true if the number is equal to the position of the
10989 * context node in the context node list (as returned by the position
10990 * function) and will be converted to false otherwise; if the result
10991 * is not a number, then the result will be converted as if by a call
10992 * to the boolean function.
10993 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010994 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010995 */
10996int
10997xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10998 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010999 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011000 switch (res->type) {
11001 case XPATH_BOOLEAN:
11002 return(res->boolval);
11003 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000011004#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000011005 return((res->floatval == ctxt->context->proximityPosition) &&
11006 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011007#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011008 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011009#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011010 case XPATH_NODESET:
11011 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011012 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011013 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011014 return(res->nodesetval->nodeNr != 0);
11015 case XPATH_STRING:
11016 return((res->stringval != NULL) &&
11017 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011018#ifdef LIBXML_XPTR_ENABLED
11019 case XPATH_LOCATIONSET:{
11020 xmlLocationSetPtr ptr = res->user;
11021 if (ptr == NULL)
11022 return(0);
11023 return (ptr->locNr != 0);
11024 }
11025#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011026 default:
11027 STRANGE
11028 }
11029 return(0);
11030}
11031
11032/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011033 * xmlXPathCtxtCompile:
11034 * @ctxt: an XPath context
11035 * @str: the XPath expression
11036 *
11037 * Compile an XPath expression
11038 *
11039 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11040 * the caller has to free the object.
11041 */
11042xmlXPathCompExprPtr
11043xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11044 xmlXPathParserContextPtr pctxt;
11045 xmlXPathCompExprPtr comp;
11046
11047 xmlXPathInit();
11048
11049 pctxt = xmlXPathNewParserContext(str, ctxt);
11050 xmlXPathCompileExpr(pctxt);
11051
11052 if( pctxt->error != XPATH_EXPRESSION_OK )
11053 {
11054 xmlXPathFreeParserContext(pctxt);
11055 return (0);
11056 }
11057
11058 if (*pctxt->cur != 0) {
11059 /*
11060 * aleksey: in some cases this line prints *second* error message
11061 * (see bug #78858) and probably this should be fixed.
11062 * However, we are not sure that all error messages are printed
11063 * out in other places. It's not critical so we leave it as-is for now
11064 */
11065 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11066 comp = NULL;
11067 } else {
11068 comp = pctxt->comp;
11069 pctxt->comp = NULL;
11070 }
11071 xmlXPathFreeParserContext(pctxt);
11072 if (comp != NULL) {
11073 comp->expr = xmlStrdup(str);
11074#ifdef DEBUG_EVAL_COUNTS
11075 comp->string = xmlStrdup(str);
11076 comp->nb = 0;
11077#endif
11078 }
11079 return(comp);
11080}
11081
11082/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011083 * xmlXPathCompile:
11084 * @str: the XPath expression
11085 *
11086 * Compile an XPath expression
11087 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011088 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011089 * the caller has to free the object.
11090 */
11091xmlXPathCompExprPtr
11092xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011093 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011094}
11095
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011096/**
11097 * xmlXPathCompiledEval:
11098 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011099 * @ctx: the XPath context
11100 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011101 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011102 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011103 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011104 * the caller has to free the object.
11105 */
11106xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011107xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011108 xmlXPathParserContextPtr ctxt;
11109 xmlXPathObjectPtr res, tmp, init = NULL;
11110 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011111#ifndef LIBXML_THREAD_ENABLED
11112 static int reentance = 0;
11113#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011114
William M. Brackf13f77f2004-11-12 16:03:48 +000011115 CHECK_CTXT(ctx)
11116
11117 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011118 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011119 xmlXPathInit();
11120
Daniel Veillard81463942001-10-16 12:34:39 +000011121#ifndef LIBXML_THREAD_ENABLED
11122 reentance++;
11123 if (reentance > 1)
11124 xmlXPathDisableOptimizer = 1;
11125#endif
11126
Daniel Veillardf06307e2001-07-03 10:35:50 +000011127#ifdef DEBUG_EVAL_COUNTS
11128 comp->nb++;
11129 if ((comp->string != NULL) && (comp->nb > 100)) {
11130 fprintf(stderr, "100 x %s\n", comp->string);
11131 comp->nb = 0;
11132 }
11133#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011134 ctxt = xmlXPathCompParserContext(comp, ctx);
11135 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011136
11137 if (ctxt->value == NULL) {
11138 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011139 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011140 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011141 } else {
11142 res = valuePop(ctxt);
11143 }
11144
Daniel Veillardf06307e2001-07-03 10:35:50 +000011145
Owen Taylor3473f882001-02-23 17:55:21 +000011146 do {
11147 tmp = valuePop(ctxt);
11148 if (tmp != NULL) {
11149 if (tmp != init)
11150 stack++;
11151 xmlXPathFreeObject(tmp);
11152 }
11153 } while (tmp != NULL);
11154 if ((stack != 0) && (res != NULL)) {
11155 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011156 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011157 stack);
11158 }
11159 if (ctxt->error != XPATH_EXPRESSION_OK) {
11160 xmlXPathFreeObject(res);
11161 res = NULL;
11162 }
11163
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011164
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011165 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011166 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011167#ifndef LIBXML_THREAD_ENABLED
11168 reentance--;
11169#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011170 return(res);
11171}
11172
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011173/**
11174 * xmlXPathEvalExpr:
11175 * @ctxt: the XPath Parser context
11176 *
11177 * Parse and evaluate an XPath expression in the given context,
11178 * then push the result on the context stack
11179 */
11180void
11181xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +000011182 if (ctxt == NULL) return;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011183 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011184 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011185 xmlXPathRunEval(ctxt);
11186}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011187
11188/**
11189 * xmlXPathEval:
11190 * @str: the XPath expression
11191 * @ctx: the XPath context
11192 *
11193 * Evaluate the XPath Location Path in the given context.
11194 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011195 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011196 * the caller has to free the object.
11197 */
11198xmlXPathObjectPtr
11199xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11200 xmlXPathParserContextPtr ctxt;
11201 xmlXPathObjectPtr res, tmp, init = NULL;
11202 int stack = 0;
11203
William M. Brackf13f77f2004-11-12 16:03:48 +000011204 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011205
William M. Brackf13f77f2004-11-12 16:03:48 +000011206 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011207
11208 ctxt = xmlXPathNewParserContext(str, ctx);
11209 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011210
11211 if (ctxt->value == NULL) {
11212 xmlGenericError(xmlGenericErrorContext,
11213 "xmlXPathEval: evaluation failed\n");
11214 res = NULL;
11215 } else if (*ctxt->cur != 0) {
11216 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11217 res = NULL;
11218 } else {
11219 res = valuePop(ctxt);
11220 }
11221
11222 do {
11223 tmp = valuePop(ctxt);
11224 if (tmp != NULL) {
11225 if (tmp != init)
11226 stack++;
11227 xmlXPathFreeObject(tmp);
11228 }
11229 } while (tmp != NULL);
11230 if ((stack != 0) && (res != NULL)) {
11231 xmlGenericError(xmlGenericErrorContext,
11232 "xmlXPathEval: %d object left on the stack\n",
11233 stack);
11234 }
11235 if (ctxt->error != XPATH_EXPRESSION_OK) {
11236 xmlXPathFreeObject(res);
11237 res = NULL;
11238 }
11239
Owen Taylor3473f882001-02-23 17:55:21 +000011240 xmlXPathFreeParserContext(ctxt);
11241 return(res);
11242}
11243
11244/**
11245 * xmlXPathEvalExpression:
11246 * @str: the XPath expression
11247 * @ctxt: the XPath context
11248 *
11249 * Evaluate the XPath expression in the given context.
11250 *
11251 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11252 * the caller has to free the object.
11253 */
11254xmlXPathObjectPtr
11255xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11256 xmlXPathParserContextPtr pctxt;
11257 xmlXPathObjectPtr res, tmp;
11258 int stack = 0;
11259
William M. Brackf13f77f2004-11-12 16:03:48 +000011260 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000011261
William M. Brackf13f77f2004-11-12 16:03:48 +000011262 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000011263
11264 pctxt = xmlXPathNewParserContext(str, ctxt);
11265 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011266
11267 if (*pctxt->cur != 0) {
11268 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11269 res = NULL;
11270 } else {
11271 res = valuePop(pctxt);
11272 }
11273 do {
11274 tmp = valuePop(pctxt);
11275 if (tmp != NULL) {
11276 xmlXPathFreeObject(tmp);
11277 stack++;
11278 }
11279 } while (tmp != NULL);
11280 if ((stack != 0) && (res != NULL)) {
11281 xmlGenericError(xmlGenericErrorContext,
11282 "xmlXPathEvalExpression: %d object left on the stack\n",
11283 stack);
11284 }
11285 xmlXPathFreeParserContext(pctxt);
11286 return(res);
11287}
11288
Daniel Veillard42766c02002-08-22 20:52:17 +000011289/************************************************************************
11290 * *
11291 * Extra functions not pertaining to the XPath spec *
11292 * *
11293 ************************************************************************/
11294/**
11295 * xmlXPathEscapeUriFunction:
11296 * @ctxt: the XPath Parser context
11297 * @nargs: the number of arguments
11298 *
11299 * Implement the escape-uri() XPath function
11300 * string escape-uri(string $str, bool $escape-reserved)
11301 *
11302 * This function applies the URI escaping rules defined in section 2 of [RFC
11303 * 2396] to the string supplied as $uri-part, which typically represents all
11304 * or part of a URI. The effect of the function is to replace any special
11305 * character in the string by an escape sequence of the form %xx%yy...,
11306 * where xxyy... is the hexadecimal representation of the octets used to
11307 * represent the character in UTF-8.
11308 *
11309 * The set of characters that are escaped depends on the setting of the
11310 * boolean argument $escape-reserved.
11311 *
11312 * If $escape-reserved is true, all characters are escaped other than lower
11313 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11314 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11315 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11316 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11317 * A-F).
11318 *
11319 * If $escape-reserved is false, the behavior differs in that characters
11320 * referred to in [RFC 2396] as reserved characters are not escaped. These
11321 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11322 *
11323 * [RFC 2396] does not define whether escaped URIs should use lower case or
11324 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11325 * compared using string comparison functions, this function must always use
11326 * the upper-case letters A-F.
11327 *
11328 * Generally, $escape-reserved should be set to true when escaping a string
11329 * that is to form a single part of a URI, and to false when escaping an
11330 * entire URI or URI reference.
11331 *
11332 * In the case of non-ascii characters, the string is encoded according to
11333 * utf-8 and then converted according to RFC 2396.
11334 *
11335 * Examples
11336 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11337 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11338 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11339 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11340 *
11341 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011342static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011343xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11344 xmlXPathObjectPtr str;
11345 int escape_reserved;
11346 xmlBufferPtr target;
11347 xmlChar *cptr;
11348 xmlChar escape[4];
11349
11350 CHECK_ARITY(2);
11351
11352 escape_reserved = xmlXPathPopBoolean(ctxt);
11353
11354 CAST_TO_STRING;
11355 str = valuePop(ctxt);
11356
11357 target = xmlBufferCreate();
11358
11359 escape[0] = '%';
11360 escape[3] = 0;
11361
11362 if (target) {
11363 for (cptr = str->stringval; *cptr; cptr++) {
11364 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11365 (*cptr >= 'a' && *cptr <= 'z') ||
11366 (*cptr >= '0' && *cptr <= '9') ||
11367 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11368 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11369 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11370 (*cptr == '%' &&
11371 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11372 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11373 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11374 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11375 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11376 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11377 (!escape_reserved &&
11378 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11379 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11380 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11381 *cptr == ','))) {
11382 xmlBufferAdd(target, cptr, 1);
11383 } else {
11384 if ((*cptr >> 4) < 10)
11385 escape[1] = '0' + (*cptr >> 4);
11386 else
11387 escape[1] = 'A' - 10 + (*cptr >> 4);
11388 if ((*cptr & 0xF) < 10)
11389 escape[2] = '0' + (*cptr & 0xF);
11390 else
11391 escape[2] = 'A' - 10 + (*cptr & 0xF);
11392
11393 xmlBufferAdd(target, &escape[0], 3);
11394 }
11395 }
11396 }
11397 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11398 xmlBufferFree(target);
11399 xmlXPathFreeObject(str);
11400}
11401
Owen Taylor3473f882001-02-23 17:55:21 +000011402/**
11403 * xmlXPathRegisterAllFunctions:
11404 * @ctxt: the XPath context
11405 *
11406 * Registers all default XPath functions in this context
11407 */
11408void
11409xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11410{
11411 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11412 xmlXPathBooleanFunction);
11413 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11414 xmlXPathCeilingFunction);
11415 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11416 xmlXPathCountFunction);
11417 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11418 xmlXPathConcatFunction);
11419 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11420 xmlXPathContainsFunction);
11421 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11422 xmlXPathIdFunction);
11423 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11424 xmlXPathFalseFunction);
11425 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11426 xmlXPathFloorFunction);
11427 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11428 xmlXPathLastFunction);
11429 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11430 xmlXPathLangFunction);
11431 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11432 xmlXPathLocalNameFunction);
11433 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11434 xmlXPathNotFunction);
11435 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11436 xmlXPathNameFunction);
11437 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11438 xmlXPathNamespaceURIFunction);
11439 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11440 xmlXPathNormalizeFunction);
11441 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11442 xmlXPathNumberFunction);
11443 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11444 xmlXPathPositionFunction);
11445 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11446 xmlXPathRoundFunction);
11447 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11448 xmlXPathStringFunction);
11449 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11450 xmlXPathStringLengthFunction);
11451 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11452 xmlXPathStartsWithFunction);
11453 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11454 xmlXPathSubstringFunction);
11455 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11456 xmlXPathSubstringBeforeFunction);
11457 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11458 xmlXPathSubstringAfterFunction);
11459 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11460 xmlXPathSumFunction);
11461 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11462 xmlXPathTrueFunction);
11463 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11464 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011465
11466 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11467 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11468 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011469}
11470
11471#endif /* LIBXML_XPATH_ENABLED */