blob: 9d7187d80716c8614ea51626f3d3d77d154fae3e [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
Daniel Veillard4432df22003-09-28 18:58:27 +000060#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000061/************************************************************************
62 * *
63 * Floating point stuff *
64 * *
65 ************************************************************************/
66
Daniel Veillardc0631a62001-09-20 13:56:06 +000067#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000068#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000069#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000070#include "trionan.c"
71
Owen Taylor3473f882001-02-23 17:55:21 +000072/*
Owen Taylor3473f882001-02-23 17:55:21 +000073 * The lack of portability of this section of the libc is annoying !
74 */
75double xmlXPathNAN = 0;
76double xmlXPathPINF = 1;
77double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000078double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000079static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000080
Owen Taylor3473f882001-02-23 17:55:21 +000081/**
82 * xmlXPathInit:
83 *
84 * Initialize the XPath environment
85 */
86void
87xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000088 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000089
Bjorn Reese45029602001-08-21 09:23:53 +000090 xmlXPathPINF = trio_pinf();
91 xmlXPathNINF = trio_ninf();
92 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +000093 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +000094
Daniel Veillard20ee8c02001-10-05 09:18:14 +000095 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000096}
97
Daniel Veillardcda96922001-08-21 10:56:31 +000098/**
99 * xmlXPathIsNaN:
100 * @val: a double value
101 *
102 * Provides a portable isnan() function to detect whether a double
103 * is a NotaNumber. Based on trio code
104 * http://sourceforge.net/projects/ctrio/
105 *
106 * Returns 1 if the value is a NaN, 0 otherwise
107 */
108int
109xmlXPathIsNaN(double val) {
110 return(trio_isnan(val));
111}
112
113/**
114 * xmlXPathIsInf:
115 * @val: a double value
116 *
117 * Provides a portable isinf() function to detect whether a double
118 * is a +Infinite or -Infinite. Based on trio code
119 * http://sourceforge.net/projects/ctrio/
120 *
121 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
122 */
123int
124xmlXPathIsInf(double val) {
125 return(trio_isinf(val));
126}
127
Daniel Veillard4432df22003-09-28 18:58:27 +0000128#endif /* SCHEMAS or XPATH */
129#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000130/**
131 * xmlXPathGetSign:
132 * @val: a double value
133 *
134 * Provides a portable function to detect the sign of a double
135 * Modified from trio code
136 * http://sourceforge.net/projects/ctrio/
137 *
138 * Returns 1 if the value is Negative, 0 if positive
139 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000140static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000141xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000142 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000143}
144
145
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000146/*
147 * TODO: when compatibility allows remove all "fake node libxslt" strings
148 * the test should just be name[0] = ' '
149 */
150/* #define DEBUG */
151/* #define DEBUG_STEP */
152/* #define DEBUG_STEP_NTH */
153/* #define DEBUG_EXPR */
154/* #define DEBUG_EVAL_COUNTS */
155
156static xmlNs xmlXPathXMLNamespaceStruct = {
157 NULL,
158 XML_NAMESPACE_DECL,
159 XML_XML_NAMESPACE,
160 BAD_CAST "xml",
161 NULL
162};
163static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
164#ifndef LIBXML_THREAD_ENABLED
165/*
166 * Optimizer is disabled only when threaded apps are detected while
167 * the library ain't compiled for thread safety.
168 */
169static int xmlXPathDisableOptimizer = 0;
170#endif
171
Owen Taylor3473f882001-02-23 17:55:21 +0000172/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000173 * *
174 * Error handling routines *
175 * *
176 ************************************************************************/
177
178
179static const char *xmlXPathErrorMessages[] = {
180 "Ok\n",
181 "Number encoding\n",
182 "Unfinished literal\n",
183 "Start of literal\n",
184 "Expected $ for variable reference\n",
185 "Undefined variable\n",
186 "Invalid predicate\n",
187 "Invalid expression\n",
188 "Missing closing curly brace\n",
189 "Unregistered function\n",
190 "Invalid operand\n",
191 "Invalid type\n",
192 "Invalid number of arguments\n",
193 "Invalid context size\n",
194 "Invalid context position\n",
195 "Memory allocation error\n",
196 "Syntax error\n",
197 "Resource error\n",
198 "Sub resource error\n",
199 "Undefined namespace prefix\n",
200 "Encoding error\n",
201 "Char out of XML range\n"
202};
203
204
205/**
206 * xmlXPathErrMemory:
207 * @ctxt: an XPath context
208 * @extra: extra informations
209 *
210 * Handle a redefinition of attribute error
211 */
212static void
213xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
214{
215 if (ctxt != NULL) {
216 if (extra) {
217 xmlChar buf[200];
218
219 xmlStrPrintf(buf, 200,
220 BAD_CAST "Memory allocation failed : %s\n",
221 extra);
222 ctxt->lastError.message = (char *) xmlStrdup(buf);
223 } else {
224 ctxt->lastError.message = (char *)
225 xmlStrdup(BAD_CAST "Memory allocation failed\n");
226 }
227 ctxt->lastError.domain = XML_FROM_XPATH;
228 ctxt->lastError.code = XML_ERR_NO_MEMORY;
229 if (ctxt->error != NULL)
230 ctxt->error(ctxt->userData, &ctxt->lastError);
231 } else {
232 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000233 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000234 NULL, NULL, XML_FROM_XPATH,
235 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
236 extra, NULL, NULL, 0, 0,
237 "Memory allocation failed : %s\n", extra);
238 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000239 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000240 NULL, NULL, XML_FROM_XPATH,
241 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
242 NULL, NULL, NULL, 0, 0,
243 "Memory allocation failed\n");
244 }
245}
246
247/**
248 * xmlXPathErrMemory:
249 * @ctxt: an XPath parser context
250 * @extra: extra informations
251 *
252 * Handle a redefinition of attribute error
253 */
254static void
255xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
256{
257 ctxt->error = XPATH_MEMORY_ERROR;
258 if (ctxt == NULL)
259 xmlXPathErrMemory(NULL, extra);
260 else
261 xmlXPathErrMemory(ctxt->context, extra);
262}
263
264/**
265 * xmlXPathErr:
266 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000267 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000268 *
269 * Handle a Relax NG Parsing error
270 */
271void
272xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
273{
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000274 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000275 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000276 NULL, NULL, XML_FROM_XPATH,
277 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
278 XML_ERR_ERROR, NULL, 0,
279 NULL, NULL, NULL, 0, 0,
280 xmlXPathErrorMessages[error]);
281 return;
282 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000283 ctxt->error = error;
284 if (ctxt->context == NULL) {
285 __xmlRaiseError(NULL, NULL, NULL,
286 NULL, NULL, XML_FROM_XPATH,
287 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
288 XML_ERR_ERROR, NULL, 0,
289 (const char *) ctxt->base, NULL, NULL,
290 ctxt->cur - ctxt->base, 0,
291 xmlXPathErrorMessages[error]);
292 return;
293 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000294 ctxt->context->lastError.domain = XML_FROM_XPATH;
295 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
296 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000297 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000298 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
299 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
300 ctxt->context->lastError.node = ctxt->context->debugNode;
301 if (ctxt->context->error != NULL) {
302 ctxt->context->error(ctxt->context->userData,
303 &ctxt->context->lastError);
304 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000305 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000306 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
307 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
308 XML_ERR_ERROR, NULL, 0,
309 (const char *) ctxt->base, NULL, NULL,
310 ctxt->cur - ctxt->base, 0,
311 xmlXPathErrorMessages[error]);
312 }
313
314}
315
316/**
317 * xmlXPatherror:
318 * @ctxt: the XPath Parser context
319 * @file: the file name
320 * @line: the line number
321 * @no: the error number
322 *
323 * Formats an error message.
324 */
325void
326xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
327 int line ATTRIBUTE_UNUSED, int no) {
328 xmlXPathErr(ctxt, no);
329}
330
331
332/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000333 * *
334 * Parser Types *
335 * *
336 ************************************************************************/
337
338/*
339 * Types are private:
340 */
341
342typedef enum {
343 XPATH_OP_END=0,
344 XPATH_OP_AND,
345 XPATH_OP_OR,
346 XPATH_OP_EQUAL,
347 XPATH_OP_CMP,
348 XPATH_OP_PLUS,
349 XPATH_OP_MULT,
350 XPATH_OP_UNION,
351 XPATH_OP_ROOT,
352 XPATH_OP_NODE,
353 XPATH_OP_RESET,
354 XPATH_OP_COLLECT,
355 XPATH_OP_VALUE,
356 XPATH_OP_VARIABLE,
357 XPATH_OP_FUNCTION,
358 XPATH_OP_ARG,
359 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000360 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000361 XPATH_OP_SORT
362#ifdef LIBXML_XPTR_ENABLED
363 ,XPATH_OP_RANGETO
364#endif
365} xmlXPathOp;
366
367typedef enum {
368 AXIS_ANCESTOR = 1,
369 AXIS_ANCESTOR_OR_SELF,
370 AXIS_ATTRIBUTE,
371 AXIS_CHILD,
372 AXIS_DESCENDANT,
373 AXIS_DESCENDANT_OR_SELF,
374 AXIS_FOLLOWING,
375 AXIS_FOLLOWING_SIBLING,
376 AXIS_NAMESPACE,
377 AXIS_PARENT,
378 AXIS_PRECEDING,
379 AXIS_PRECEDING_SIBLING,
380 AXIS_SELF
381} xmlXPathAxisVal;
382
383typedef enum {
384 NODE_TEST_NONE = 0,
385 NODE_TEST_TYPE = 1,
386 NODE_TEST_PI = 2,
387 NODE_TEST_ALL = 3,
388 NODE_TEST_NS = 4,
389 NODE_TEST_NAME = 5
390} xmlXPathTestVal;
391
392typedef enum {
393 NODE_TYPE_NODE = 0,
394 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
395 NODE_TYPE_TEXT = XML_TEXT_NODE,
396 NODE_TYPE_PI = XML_PI_NODE
397} xmlXPathTypeVal;
398
399
400typedef struct _xmlXPathStepOp xmlXPathStepOp;
401typedef xmlXPathStepOp *xmlXPathStepOpPtr;
402struct _xmlXPathStepOp {
403 xmlXPathOp op;
404 int ch1;
405 int ch2;
406 int value;
407 int value2;
408 int value3;
409 void *value4;
410 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000411 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000412 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000413};
414
415struct _xmlXPathCompExpr {
416 int nbStep;
417 int maxStep;
418 xmlXPathStepOp *steps; /* ops for computation */
419 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000420 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000421#ifdef DEBUG_EVAL_COUNTS
422 int nb;
423 xmlChar *string;
424#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000425};
426
427/************************************************************************
428 * *
429 * Parser Type functions *
430 * *
431 ************************************************************************/
432
433/**
434 * xmlXPathNewCompExpr:
435 *
436 * Create a new Xpath component
437 *
438 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
439 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000440static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000441xmlXPathNewCompExpr(void) {
442 xmlXPathCompExprPtr cur;
443
444 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
445 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000446 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000447 return(NULL);
448 }
449 memset(cur, 0, sizeof(xmlXPathCompExpr));
450 cur->maxStep = 10;
451 cur->nbStep = 0;
452 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
453 sizeof(xmlXPathStepOp));
454 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000455 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000456 xmlFree(cur);
457 return(NULL);
458 }
459 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
460 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000461#ifdef DEBUG_EVAL_COUNTS
462 cur->nb = 0;
463#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000464 return(cur);
465}
466
467/**
468 * xmlXPathFreeCompExpr:
469 * @comp: an XPATH comp
470 *
471 * Free up the memory allocated by @comp
472 */
473void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000474xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
475{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000476 xmlXPathStepOpPtr op;
477 int i;
478
479 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000480 return;
481 for (i = 0; i < comp->nbStep; i++) {
482 op = &comp->steps[i];
483 if (op->value4 != NULL) {
484 if (op->op == XPATH_OP_VALUE)
485 xmlXPathFreeObject(op->value4);
486 else
487 xmlFree(op->value4);
488 }
489 if (op->value5 != NULL)
490 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000491 }
492 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000493 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000494 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000495#ifdef DEBUG_EVAL_COUNTS
496 if (comp->string != NULL) {
497 xmlFree(comp->string);
498 }
499#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000500 if (comp->expr != NULL) {
501 xmlFree(comp->expr);
502 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000503
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000504 xmlFree(comp);
505}
506
507/**
508 * xmlXPathCompExprAdd:
509 * @comp: the compiled expression
510 * @ch1: first child index
511 * @ch2: second child index
512 * @op: an op
513 * @value: the first int value
514 * @value2: the second int value
515 * @value3: the third int value
516 * @value4: the first string value
517 * @value5: the second string value
518 *
519 * Add an step to an XPath Compiled Expression
520 *
521 * Returns -1 in case of failure, the index otherwise
522 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000523static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000524xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
525 xmlXPathOp op, int value,
526 int value2, int value3, void *value4, void *value5) {
527 if (comp->nbStep >= comp->maxStep) {
528 xmlXPathStepOp *real;
529
530 comp->maxStep *= 2;
531 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
532 comp->maxStep * sizeof(xmlXPathStepOp));
533 if (real == NULL) {
534 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000535 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000536 return(-1);
537 }
538 comp->steps = real;
539 }
540 comp->last = comp->nbStep;
541 comp->steps[comp->nbStep].ch1 = ch1;
542 comp->steps[comp->nbStep].ch2 = ch2;
543 comp->steps[comp->nbStep].op = op;
544 comp->steps[comp->nbStep].value = value;
545 comp->steps[comp->nbStep].value2 = value2;
546 comp->steps[comp->nbStep].value3 = value3;
547 comp->steps[comp->nbStep].value4 = value4;
548 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000549 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000550 return(comp->nbStep++);
551}
552
Daniel Veillardf06307e2001-07-03 10:35:50 +0000553/**
554 * xmlXPathCompSwap:
555 * @comp: the compiled expression
556 * @op: operation index
557 *
558 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000559 */
560static void
561xmlXPathCompSwap(xmlXPathStepOpPtr op) {
562 int tmp;
563
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000564#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000565 /*
566 * Since this manipulates possibly shared variables, this is
567 * disable if one detects that the library is used in a multithreaded
568 * application
569 */
570 if (xmlXPathDisableOptimizer)
571 return;
572#endif
573
Daniel Veillardf06307e2001-07-03 10:35:50 +0000574 tmp = op->ch1;
575 op->ch1 = op->ch2;
576 op->ch2 = tmp;
577}
578
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000579#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
580 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
581 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000582#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
583 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
584 (op), (val), (val2), (val3), (val4), (val5))
585
586#define PUSH_LEAVE_EXPR(op, val, val2) \
587xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
588
589#define PUSH_UNARY_EXPR(op, ch, val, val2) \
590xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
591
592#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
593xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
594
595/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000596 * *
597 * Debugging related functions *
598 * *
599 ************************************************************************/
600
Owen Taylor3473f882001-02-23 17:55:21 +0000601#define STRANGE \
602 xmlGenericError(xmlGenericErrorContext, \
603 "Internal error at %s:%d\n", \
604 __FILE__, __LINE__);
605
606#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000607static void
608xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000609 int i;
610 char shift[100];
611
612 for (i = 0;((i < depth) && (i < 25));i++)
613 shift[2 * i] = shift[2 * i + 1] = ' ';
614 shift[2 * i] = shift[2 * i + 1] = 0;
615 if (cur == NULL) {
616 fprintf(output, shift);
617 fprintf(output, "Node is NULL !\n");
618 return;
619
620 }
621
622 if ((cur->type == XML_DOCUMENT_NODE) ||
623 (cur->type == XML_HTML_DOCUMENT_NODE)) {
624 fprintf(output, shift);
625 fprintf(output, " /\n");
626 } else if (cur->type == XML_ATTRIBUTE_NODE)
627 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
628 else
629 xmlDebugDumpOneNode(output, cur, depth);
630}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000631static void
632xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000633 xmlNodePtr tmp;
634 int i;
635 char shift[100];
636
637 for (i = 0;((i < depth) && (i < 25));i++)
638 shift[2 * i] = shift[2 * i + 1] = ' ';
639 shift[2 * i] = shift[2 * i + 1] = 0;
640 if (cur == NULL) {
641 fprintf(output, shift);
642 fprintf(output, "Node is NULL !\n");
643 return;
644
645 }
646
647 while (cur != NULL) {
648 tmp = cur;
649 cur = cur->next;
650 xmlDebugDumpOneNode(output, tmp, depth);
651 }
652}
Owen Taylor3473f882001-02-23 17:55:21 +0000653
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000654static void
655xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000656 int i;
657 char shift[100];
658
659 for (i = 0;((i < depth) && (i < 25));i++)
660 shift[2 * i] = shift[2 * i + 1] = ' ';
661 shift[2 * i] = shift[2 * i + 1] = 0;
662
663 if (cur == NULL) {
664 fprintf(output, shift);
665 fprintf(output, "NodeSet is NULL !\n");
666 return;
667
668 }
669
Daniel Veillard911f49a2001-04-07 15:39:35 +0000670 if (cur != NULL) {
671 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
672 for (i = 0;i < cur->nodeNr;i++) {
673 fprintf(output, shift);
674 fprintf(output, "%d", i + 1);
675 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
676 }
Owen Taylor3473f882001-02-23 17:55:21 +0000677 }
678}
679
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000680static void
681xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000682 int i;
683 char shift[100];
684
685 for (i = 0;((i < depth) && (i < 25));i++)
686 shift[2 * i] = shift[2 * i + 1] = ' ';
687 shift[2 * i] = shift[2 * i + 1] = 0;
688
689 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
690 fprintf(output, shift);
691 fprintf(output, "Value Tree is NULL !\n");
692 return;
693
694 }
695
696 fprintf(output, shift);
697 fprintf(output, "%d", i + 1);
698 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
699}
Owen Taylor3473f882001-02-23 17:55:21 +0000700#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000701static void
702xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000703 int i;
704 char shift[100];
705
706 for (i = 0;((i < depth) && (i < 25));i++)
707 shift[2 * i] = shift[2 * i + 1] = ' ';
708 shift[2 * i] = shift[2 * i + 1] = 0;
709
710 if (cur == NULL) {
711 fprintf(output, shift);
712 fprintf(output, "LocationSet is NULL !\n");
713 return;
714
715 }
716
717 for (i = 0;i < cur->locNr;i++) {
718 fprintf(output, shift);
719 fprintf(output, "%d : ", i + 1);
720 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
721 }
722}
Daniel Veillard017b1082001-06-21 11:20:21 +0000723#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000724
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000725/**
726 * xmlXPathDebugDumpObject:
727 * @output: the FILE * to dump the output
728 * @cur: the object to inspect
729 * @depth: indentation level
730 *
731 * Dump the content of the object for debugging purposes
732 */
733void
734xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000735 int i;
736 char shift[100];
737
738 for (i = 0;((i < depth) && (i < 25));i++)
739 shift[2 * i] = shift[2 * i + 1] = ' ';
740 shift[2 * i] = shift[2 * i + 1] = 0;
741
742 fprintf(output, shift);
743
744 if (cur == NULL) {
745 fprintf(output, "Object is empty (NULL)\n");
746 return;
747 }
748 switch(cur->type) {
749 case XPATH_UNDEFINED:
750 fprintf(output, "Object is uninitialized\n");
751 break;
752 case XPATH_NODESET:
753 fprintf(output, "Object is a Node Set :\n");
754 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
755 break;
756 case XPATH_XSLT_TREE:
757 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000758 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000759 break;
760 case XPATH_BOOLEAN:
761 fprintf(output, "Object is a Boolean : ");
762 if (cur->boolval) fprintf(output, "true\n");
763 else fprintf(output, "false\n");
764 break;
765 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000766 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000767 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000768 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000769 break;
770 case -1:
771 fprintf(output, "Object is a number : -Infinity\n");
772 break;
773 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000774 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000775 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000776 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
777 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000778 } else {
779 fprintf(output, "Object is a number : %0g\n", cur->floatval);
780 }
781 }
Owen Taylor3473f882001-02-23 17:55:21 +0000782 break;
783 case XPATH_STRING:
784 fprintf(output, "Object is a string : ");
785 xmlDebugDumpString(output, cur->stringval);
786 fprintf(output, "\n");
787 break;
788 case XPATH_POINT:
789 fprintf(output, "Object is a point : index %d in node", cur->index);
790 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
791 fprintf(output, "\n");
792 break;
793 case XPATH_RANGE:
794 if ((cur->user2 == NULL) ||
795 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
796 fprintf(output, "Object is a collapsed range :\n");
797 fprintf(output, shift);
798 if (cur->index >= 0)
799 fprintf(output, "index %d in ", cur->index);
800 fprintf(output, "node\n");
801 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
802 depth + 1);
803 } else {
804 fprintf(output, "Object is a range :\n");
805 fprintf(output, shift);
806 fprintf(output, "From ");
807 if (cur->index >= 0)
808 fprintf(output, "index %d in ", cur->index);
809 fprintf(output, "node\n");
810 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
811 depth + 1);
812 fprintf(output, shift);
813 fprintf(output, "To ");
814 if (cur->index2 >= 0)
815 fprintf(output, "index %d in ", cur->index2);
816 fprintf(output, "node\n");
817 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
818 depth + 1);
819 fprintf(output, "\n");
820 }
821 break;
822 case XPATH_LOCATIONSET:
823#if defined(LIBXML_XPTR_ENABLED)
824 fprintf(output, "Object is a Location Set:\n");
825 xmlXPathDebugDumpLocationSet(output,
826 (xmlLocationSetPtr) cur->user, depth);
827#endif
828 break;
829 case XPATH_USERS:
830 fprintf(output, "Object is user defined\n");
831 break;
832 }
833}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000834
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000835static void
836xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000837 xmlXPathStepOpPtr op, int depth) {
838 int i;
839 char shift[100];
840
841 for (i = 0;((i < depth) && (i < 25));i++)
842 shift[2 * i] = shift[2 * i + 1] = ' ';
843 shift[2 * i] = shift[2 * i + 1] = 0;
844
845 fprintf(output, shift);
846 if (op == NULL) {
847 fprintf(output, "Step is NULL\n");
848 return;
849 }
850 switch (op->op) {
851 case XPATH_OP_END:
852 fprintf(output, "END"); break;
853 case XPATH_OP_AND:
854 fprintf(output, "AND"); break;
855 case XPATH_OP_OR:
856 fprintf(output, "OR"); break;
857 case XPATH_OP_EQUAL:
858 if (op->value)
859 fprintf(output, "EQUAL =");
860 else
861 fprintf(output, "EQUAL !=");
862 break;
863 case XPATH_OP_CMP:
864 if (op->value)
865 fprintf(output, "CMP <");
866 else
867 fprintf(output, "CMP >");
868 if (!op->value2)
869 fprintf(output, "=");
870 break;
871 case XPATH_OP_PLUS:
872 if (op->value == 0)
873 fprintf(output, "PLUS -");
874 else if (op->value == 1)
875 fprintf(output, "PLUS +");
876 else if (op->value == 2)
877 fprintf(output, "PLUS unary -");
878 else if (op->value == 3)
879 fprintf(output, "PLUS unary - -");
880 break;
881 case XPATH_OP_MULT:
882 if (op->value == 0)
883 fprintf(output, "MULT *");
884 else if (op->value == 1)
885 fprintf(output, "MULT div");
886 else
887 fprintf(output, "MULT mod");
888 break;
889 case XPATH_OP_UNION:
890 fprintf(output, "UNION"); break;
891 case XPATH_OP_ROOT:
892 fprintf(output, "ROOT"); break;
893 case XPATH_OP_NODE:
894 fprintf(output, "NODE"); break;
895 case XPATH_OP_RESET:
896 fprintf(output, "RESET"); break;
897 case XPATH_OP_SORT:
898 fprintf(output, "SORT"); break;
899 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000900 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
901 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
902 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000903 const xmlChar *prefix = op->value4;
904 const xmlChar *name = op->value5;
905
906 fprintf(output, "COLLECT ");
907 switch (axis) {
908 case AXIS_ANCESTOR:
909 fprintf(output, " 'ancestors' "); break;
910 case AXIS_ANCESTOR_OR_SELF:
911 fprintf(output, " 'ancestors-or-self' "); break;
912 case AXIS_ATTRIBUTE:
913 fprintf(output, " 'attributes' "); break;
914 case AXIS_CHILD:
915 fprintf(output, " 'child' "); break;
916 case AXIS_DESCENDANT:
917 fprintf(output, " 'descendant' "); break;
918 case AXIS_DESCENDANT_OR_SELF:
919 fprintf(output, " 'descendant-or-self' "); break;
920 case AXIS_FOLLOWING:
921 fprintf(output, " 'following' "); break;
922 case AXIS_FOLLOWING_SIBLING:
923 fprintf(output, " 'following-siblings' "); break;
924 case AXIS_NAMESPACE:
925 fprintf(output, " 'namespace' "); break;
926 case AXIS_PARENT:
927 fprintf(output, " 'parent' "); break;
928 case AXIS_PRECEDING:
929 fprintf(output, " 'preceding' "); break;
930 case AXIS_PRECEDING_SIBLING:
931 fprintf(output, " 'preceding-sibling' "); break;
932 case AXIS_SELF:
933 fprintf(output, " 'self' "); break;
934 }
935 switch (test) {
936 case NODE_TEST_NONE:
937 fprintf(output, "'none' "); break;
938 case NODE_TEST_TYPE:
939 fprintf(output, "'type' "); break;
940 case NODE_TEST_PI:
941 fprintf(output, "'PI' "); break;
942 case NODE_TEST_ALL:
943 fprintf(output, "'all' "); break;
944 case NODE_TEST_NS:
945 fprintf(output, "'namespace' "); break;
946 case NODE_TEST_NAME:
947 fprintf(output, "'name' "); break;
948 }
949 switch (type) {
950 case NODE_TYPE_NODE:
951 fprintf(output, "'node' "); break;
952 case NODE_TYPE_COMMENT:
953 fprintf(output, "'comment' "); break;
954 case NODE_TYPE_TEXT:
955 fprintf(output, "'text' "); break;
956 case NODE_TYPE_PI:
957 fprintf(output, "'PI' "); break;
958 }
959 if (prefix != NULL)
960 fprintf(output, "%s:", prefix);
961 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000962 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000963 break;
964
965 }
966 case XPATH_OP_VALUE: {
967 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
968
969 fprintf(output, "ELEM ");
970 xmlXPathDebugDumpObject(output, object, 0);
971 goto finish;
972 }
973 case XPATH_OP_VARIABLE: {
974 const xmlChar *prefix = op->value5;
975 const xmlChar *name = op->value4;
976
977 if (prefix != NULL)
978 fprintf(output, "VARIABLE %s:%s", prefix, name);
979 else
980 fprintf(output, "VARIABLE %s", name);
981 break;
982 }
983 case XPATH_OP_FUNCTION: {
984 int nbargs = op->value;
985 const xmlChar *prefix = op->value5;
986 const xmlChar *name = op->value4;
987
988 if (prefix != NULL)
989 fprintf(output, "FUNCTION %s:%s(%d args)",
990 prefix, name, nbargs);
991 else
992 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
993 break;
994 }
995 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
996 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000997 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000998#ifdef LIBXML_XPTR_ENABLED
999 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1000#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001001 default:
1002 fprintf(output, "UNKNOWN %d\n", op->op); return;
1003 }
1004 fprintf(output, "\n");
1005finish:
1006 if (op->ch1 >= 0)
1007 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1008 if (op->ch2 >= 0)
1009 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1010}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001011
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001012/**
1013 * xmlXPathDebugDumpCompExpr:
1014 * @output: the FILE * for the output
1015 * @comp: the precompiled XPath expression
1016 * @depth: the indentation level.
1017 *
1018 * Dumps the tree of the compiled XPath expression.
1019 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001020void
1021xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1022 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001023 int i;
1024 char shift[100];
1025
1026 for (i = 0;((i < depth) && (i < 25));i++)
1027 shift[2 * i] = shift[2 * i + 1] = ' ';
1028 shift[2 * i] = shift[2 * i + 1] = 0;
1029
1030 fprintf(output, shift);
1031
1032 if (comp == NULL) {
1033 fprintf(output, "Compiled Expression is NULL\n");
1034 return;
1035 }
1036 fprintf(output, "Compiled Expression : %d elements\n",
1037 comp->nbStep);
1038 i = comp->last;
1039 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1040}
Daniel Veillard017b1082001-06-21 11:20:21 +00001041#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001042
1043/************************************************************************
1044 * *
1045 * Parser stacks related functions and macros *
1046 * *
1047 ************************************************************************/
1048
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001049/**
1050 * valuePop:
1051 * @ctxt: an XPath evaluation context
1052 *
1053 * Pops the top XPath object from the value stack
1054 *
1055 * Returns the XPath object just removed
1056 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001057extern xmlXPathObjectPtr
1058valuePop(xmlXPathParserContextPtr ctxt)
1059{
1060 xmlXPathObjectPtr ret;
1061
1062 if (ctxt->valueNr <= 0)
1063 return (0);
1064 ctxt->valueNr--;
1065 if (ctxt->valueNr > 0)
1066 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1067 else
1068 ctxt->value = NULL;
1069 ret = ctxt->valueTab[ctxt->valueNr];
1070 ctxt->valueTab[ctxt->valueNr] = 0;
1071 return (ret);
1072}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001073/**
1074 * valuePush:
1075 * @ctxt: an XPath evaluation context
1076 * @value: the XPath object
1077 *
1078 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001079 *
1080 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001081 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001082extern int
1083valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1084{
1085 if (ctxt->valueNr >= ctxt->valueMax) {
1086 ctxt->valueMax *= 2;
1087 ctxt->valueTab =
1088 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1089 ctxt->valueMax *
1090 sizeof(ctxt->valueTab[0]));
1091 if (ctxt->valueTab == NULL) {
1092 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1093 return (0);
1094 }
1095 }
1096 ctxt->valueTab[ctxt->valueNr] = value;
1097 ctxt->value = value;
1098 return (ctxt->valueNr++);
1099}
Owen Taylor3473f882001-02-23 17:55:21 +00001100
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001101/**
1102 * xmlXPathPopBoolean:
1103 * @ctxt: an XPath parser context
1104 *
1105 * Pops a boolean from the stack, handling conversion if needed.
1106 * Check error with #xmlXPathCheckError.
1107 *
1108 * Returns the boolean
1109 */
1110int
1111xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1112 xmlXPathObjectPtr obj;
1113 int ret;
1114
1115 obj = valuePop(ctxt);
1116 if (obj == NULL) {
1117 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1118 return(0);
1119 }
1120 ret = xmlXPathCastToBoolean(obj);
1121 xmlXPathFreeObject(obj);
1122 return(ret);
1123}
1124
1125/**
1126 * xmlXPathPopNumber:
1127 * @ctxt: an XPath parser context
1128 *
1129 * Pops a number from the stack, handling conversion if needed.
1130 * Check error with #xmlXPathCheckError.
1131 *
1132 * Returns the number
1133 */
1134double
1135xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1136 xmlXPathObjectPtr obj;
1137 double ret;
1138
1139 obj = valuePop(ctxt);
1140 if (obj == NULL) {
1141 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1142 return(0);
1143 }
1144 ret = xmlXPathCastToNumber(obj);
1145 xmlXPathFreeObject(obj);
1146 return(ret);
1147}
1148
1149/**
1150 * xmlXPathPopString:
1151 * @ctxt: an XPath parser context
1152 *
1153 * Pops a string from the stack, handling conversion if needed.
1154 * Check error with #xmlXPathCheckError.
1155 *
1156 * Returns the string
1157 */
1158xmlChar *
1159xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1160 xmlXPathObjectPtr obj;
1161 xmlChar * ret;
1162
1163 obj = valuePop(ctxt);
1164 if (obj == NULL) {
1165 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1166 return(NULL);
1167 }
1168 ret = xmlXPathCastToString(obj);
1169 /* TODO: needs refactoring somewhere else */
1170 if (obj->stringval == ret)
1171 obj->stringval = NULL;
1172 xmlXPathFreeObject(obj);
1173 return(ret);
1174}
1175
1176/**
1177 * xmlXPathPopNodeSet:
1178 * @ctxt: an XPath parser context
1179 *
1180 * Pops a node-set from the stack, handling conversion if needed.
1181 * Check error with #xmlXPathCheckError.
1182 *
1183 * Returns the node-set
1184 */
1185xmlNodeSetPtr
1186xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1187 xmlXPathObjectPtr obj;
1188 xmlNodeSetPtr ret;
1189
1190 if (ctxt->value == NULL) {
1191 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1192 return(NULL);
1193 }
1194 if (!xmlXPathStackIsNodeSet(ctxt)) {
1195 xmlXPathSetTypeError(ctxt);
1196 return(NULL);
1197 }
1198 obj = valuePop(ctxt);
1199 ret = obj->nodesetval;
Daniel Veillard9deb2422003-07-28 20:40:59 +00001200 /* to fix memory leak of not clearing obj->user */
1201 if (obj->boolval && obj->user != NULL)
1202 xmlFreeNodeList((xmlNodePtr) obj->user);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001203 xmlXPathFreeNodeSetList(obj);
1204 return(ret);
1205}
1206
1207/**
1208 * xmlXPathPopExternal:
1209 * @ctxt: an XPath parser context
1210 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001211 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001212 * Check error with #xmlXPathCheckError.
1213 *
1214 * Returns the object
1215 */
1216void *
1217xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1218 xmlXPathObjectPtr obj;
1219 void * ret;
1220
1221 if (ctxt->value == NULL) {
1222 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1223 return(NULL);
1224 }
1225 if (ctxt->value->type != XPATH_USERS) {
1226 xmlXPathSetTypeError(ctxt);
1227 return(NULL);
1228 }
1229 obj = valuePop(ctxt);
1230 ret = obj->user;
1231 xmlXPathFreeObject(obj);
1232 return(ret);
1233}
1234
Owen Taylor3473f882001-02-23 17:55:21 +00001235/*
1236 * Macros for accessing the content. Those should be used only by the parser,
1237 * and not exported.
1238 *
1239 * Dirty macros, i.e. one need to make assumption on the context to use them
1240 *
1241 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1242 * CUR returns the current xmlChar value, i.e. a 8 bit value
1243 * in ISO-Latin or UTF-8.
1244 * This should be used internally by the parser
1245 * only to compare to ASCII values otherwise it would break when
1246 * running with UTF-8 encoding.
1247 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1248 * to compare on ASCII based substring.
1249 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1250 * strings within the parser.
1251 * CURRENT Returns the current char value, with the full decoding of
1252 * UTF-8 if we are using this mode. It returns an int.
1253 * NEXT Skip to the next character, this does the proper decoding
1254 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1255 * It returns the pointer to the current xmlChar.
1256 */
1257
1258#define CUR (*ctxt->cur)
1259#define SKIP(val) ctxt->cur += (val)
1260#define NXT(val) ctxt->cur[(val)]
1261#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001262#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1263
1264#define COPY_BUF(l,b,i,v) \
1265 if (l == 1) b[i++] = (xmlChar) v; \
1266 else i += xmlCopyChar(l,&b[i],v)
1267
1268#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001269
1270#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001271 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001272
1273#define CURRENT (*ctxt->cur)
1274#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1275
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001276
1277#ifndef DBL_DIG
1278#define DBL_DIG 16
1279#endif
1280#ifndef DBL_EPSILON
1281#define DBL_EPSILON 1E-9
1282#endif
1283
1284#define UPPER_DOUBLE 1E9
1285#define LOWER_DOUBLE 1E-5
1286
1287#define INTEGER_DIGITS DBL_DIG
1288#define FRACTION_DIGITS (DBL_DIG + 1)
1289#define EXPONENT_DIGITS (3 + 2)
1290
1291/**
1292 * xmlXPathFormatNumber:
1293 * @number: number to format
1294 * @buffer: output buffer
1295 * @buffersize: size of output buffer
1296 *
1297 * Convert the number into a string representation.
1298 */
1299static void
1300xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1301{
Daniel Veillardcda96922001-08-21 10:56:31 +00001302 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001303 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001304 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001305 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001306 break;
1307 case -1:
1308 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001309 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001310 break;
1311 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001312 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001313 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001314 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001315 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001316 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001317 } else if (number == ((int) number)) {
1318 char work[30];
1319 char *ptr, *cur;
1320 int res, value = (int) number;
1321
1322 ptr = &buffer[0];
1323 if (value < 0) {
1324 *ptr++ = '-';
1325 value = -value;
1326 }
1327 if (value == 0) {
1328 *ptr++ = '0';
1329 } else {
1330 cur = &work[0];
1331 while (value != 0) {
1332 res = value % 10;
1333 value = value / 10;
1334 *cur++ = '0' + res;
1335 }
1336 cur--;
1337 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1338 *ptr++ = *cur--;
1339 }
1340 }
1341 if (ptr - buffer < buffersize) {
1342 *ptr = 0;
1343 } else if (buffersize > 0) {
1344 ptr--;
1345 *ptr = 0;
1346 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001347 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001348 /* 3 is sign, decimal point, and terminating zero */
1349 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1350 int integer_place, fraction_place;
1351 char *ptr;
1352 char *after_fraction;
1353 double absolute_value;
1354 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001355
Bjorn Reese70a9da52001-04-21 16:57:29 +00001356 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001357
Bjorn Reese70a9da52001-04-21 16:57:29 +00001358 /*
1359 * First choose format - scientific or regular floating point.
1360 * In either case, result is in work, and after_fraction points
1361 * just past the fractional part.
1362 */
1363 if ( ((absolute_value > UPPER_DOUBLE) ||
1364 (absolute_value < LOWER_DOUBLE)) &&
1365 (absolute_value != 0.0) ) {
1366 /* Use scientific notation */
1367 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1368 fraction_place = DBL_DIG - 1;
1369 snprintf(work, sizeof(work),"%*.*e",
1370 integer_place, fraction_place, number);
1371 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001372 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001373 else {
1374 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001375 if (absolute_value > 0.0)
1376 integer_place = 1 + (int)log10(absolute_value);
1377 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001378 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001379 fraction_place = (integer_place > 0)
1380 ? DBL_DIG - integer_place
1381 : DBL_DIG;
1382 size = snprintf(work, sizeof(work), "%0.*f",
1383 fraction_place, number);
1384 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001385 }
1386
Bjorn Reese70a9da52001-04-21 16:57:29 +00001387 /* Remove fractional trailing zeroes */
1388 ptr = after_fraction;
1389 while (*(--ptr) == '0')
1390 ;
1391 if (*ptr != '.')
1392 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001393 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001394
1395 /* Finally copy result back to caller */
1396 size = strlen(work) + 1;
1397 if (size > buffersize) {
1398 work[buffersize - 1] = 0;
1399 size = buffersize;
1400 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001401 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001402 }
1403 break;
1404 }
1405}
1406
Owen Taylor3473f882001-02-23 17:55:21 +00001407
1408/************************************************************************
1409 * *
1410 * Routines to handle NodeSets *
1411 * *
1412 ************************************************************************/
1413
1414/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001415 * xmlXPathOrderDocElems:
1416 * @doc: an input document
1417 *
1418 * Call this routine to speed up XPath computation on static documents.
1419 * This stamps all the element nodes with the document order
1420 * Like for line information, the order is kept in the element->content
1421 * field, the value stored is actually - the node number (startting at -1)
1422 * to be able to differenciate from line numbers.
1423 *
1424 * Returns the number of element found in the document or -1 in case
1425 * of error.
1426 */
1427long
1428xmlXPathOrderDocElems(xmlDocPtr doc) {
1429 long count = 0;
1430 xmlNodePtr cur;
1431
1432 if (doc == NULL)
1433 return(-1);
1434 cur = doc->children;
1435 while (cur != NULL) {
1436 if (cur->type == XML_ELEMENT_NODE) {
1437 cur->content = (void *) (-(++count));
1438 if (cur->children != NULL) {
1439 cur = cur->children;
1440 continue;
1441 }
1442 }
1443 if (cur->next != NULL) {
1444 cur = cur->next;
1445 continue;
1446 }
1447 do {
1448 cur = cur->parent;
1449 if (cur == NULL)
1450 break;
1451 if (cur == (xmlNodePtr) doc) {
1452 cur = NULL;
1453 break;
1454 }
1455 if (cur->next != NULL) {
1456 cur = cur->next;
1457 break;
1458 }
1459 } while (cur != NULL);
1460 }
1461 return(count);
1462}
1463
1464/**
Owen Taylor3473f882001-02-23 17:55:21 +00001465 * xmlXPathCmpNodes:
1466 * @node1: the first node
1467 * @node2: the second node
1468 *
1469 * Compare two nodes w.r.t document order
1470 *
1471 * Returns -2 in case of error 1 if first point < second point, 0 if
1472 * that's the same node, -1 otherwise
1473 */
1474int
1475xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1476 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001477 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001478 xmlNodePtr cur, root;
1479
1480 if ((node1 == NULL) || (node2 == NULL))
1481 return(-2);
1482 /*
1483 * a couple of optimizations which will avoid computations in most cases
1484 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001485 if (node1->type == XML_ATTRIBUTE_NODE) {
1486 attr1 = 1;
1487 node1 = node1->parent;
1488 }
1489 if (node2->type == XML_ATTRIBUTE_NODE) {
1490 attr2 = 1;
1491 node2 = node2->parent;
1492 }
1493 if (node1 == node2) {
1494 if (attr1 == attr2)
1495 return(0);
1496 if (attr2 == 1)
1497 return(1);
1498 return(-1);
1499 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001500 if ((node1->type == XML_NAMESPACE_DECL) ||
1501 (node2->type == XML_NAMESPACE_DECL))
1502 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001503 if (node1 == node2->prev)
1504 return(1);
1505 if (node1 == node2->next)
1506 return(-1);
1507
1508 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001509 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001510 */
1511 if ((node1->type == XML_ELEMENT_NODE) &&
1512 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001513 (0 > (long) node1->content) &&
1514 (0 > (long) node2->content) &&
1515 (node1->doc == node2->doc)) {
1516 long l1, l2;
1517
1518 l1 = -((long) node1->content);
1519 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001520 if (l1 < l2)
1521 return(1);
1522 if (l1 > l2)
1523 return(-1);
1524 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001525
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001526 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001527 * compute depth to root
1528 */
1529 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1530 if (cur == node1)
1531 return(1);
1532 depth2++;
1533 }
1534 root = cur;
1535 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1536 if (cur == node2)
1537 return(-1);
1538 depth1++;
1539 }
1540 /*
1541 * Distinct document (or distinct entities :-( ) case.
1542 */
1543 if (root != cur) {
1544 return(-2);
1545 }
1546 /*
1547 * get the nearest common ancestor.
1548 */
1549 while (depth1 > depth2) {
1550 depth1--;
1551 node1 = node1->parent;
1552 }
1553 while (depth2 > depth1) {
1554 depth2--;
1555 node2 = node2->parent;
1556 }
1557 while (node1->parent != node2->parent) {
1558 node1 = node1->parent;
1559 node2 = node2->parent;
1560 /* should not happen but just in case ... */
1561 if ((node1 == NULL) || (node2 == NULL))
1562 return(-2);
1563 }
1564 /*
1565 * Find who's first.
1566 */
1567 if (node1 == node2->next)
1568 return(-1);
1569 for (cur = node1->next;cur != NULL;cur = cur->next)
1570 if (cur == node2)
1571 return(1);
1572 return(-1); /* assume there is no sibling list corruption */
1573}
1574
1575/**
1576 * xmlXPathNodeSetSort:
1577 * @set: the node set
1578 *
1579 * Sort the node set in document order
1580 */
1581void
1582xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001583 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001584 xmlNodePtr tmp;
1585
1586 if (set == NULL)
1587 return;
1588
1589 /* Use Shell's sort to sort the node-set */
1590 len = set->nodeNr;
1591 for (incr = len / 2; incr > 0; incr /= 2) {
1592 for (i = incr; i < len; i++) {
1593 j = i - incr;
1594 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001595 if (xmlXPathCmpNodes(set->nodeTab[j],
1596 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001597 tmp = set->nodeTab[j];
1598 set->nodeTab[j] = set->nodeTab[j + incr];
1599 set->nodeTab[j + incr] = tmp;
1600 j -= incr;
1601 } else
1602 break;
1603 }
1604 }
1605 }
1606}
1607
1608#define XML_NODESET_DEFAULT 10
1609/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001610 * xmlXPathNodeSetDupNs:
1611 * @node: the parent node of the namespace XPath node
1612 * @ns: the libxml namespace declaration node.
1613 *
1614 * Namespace node in libxml don't match the XPath semantic. In a node set
1615 * the namespace nodes are duplicated and the next pointer is set to the
1616 * parent node in the XPath semantic.
1617 *
1618 * Returns the newly created object.
1619 */
1620static xmlNodePtr
1621xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1622 xmlNsPtr cur;
1623
1624 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1625 return(NULL);
1626 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1627 return((xmlNodePtr) ns);
1628
1629 /*
1630 * Allocate a new Namespace and fill the fields.
1631 */
1632 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1633 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001634 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001635 return(NULL);
1636 }
1637 memset(cur, 0, sizeof(xmlNs));
1638 cur->type = XML_NAMESPACE_DECL;
1639 if (ns->href != NULL)
1640 cur->href = xmlStrdup(ns->href);
1641 if (ns->prefix != NULL)
1642 cur->prefix = xmlStrdup(ns->prefix);
1643 cur->next = (xmlNsPtr) node;
1644 return((xmlNodePtr) cur);
1645}
1646
1647/**
1648 * xmlXPathNodeSetFreeNs:
1649 * @ns: the XPath namespace node found in a nodeset.
1650 *
1651 * Namespace node in libxml don't match the XPath semantic. In a node set
1652 * the namespace nodes are duplicated and the next pointer is set to the
1653 * parent node in the XPath semantic. Check if such a node need to be freed
1654 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001655void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001656xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1657 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1658 return;
1659
1660 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1661 if (ns->href != NULL)
1662 xmlFree((xmlChar *)ns->href);
1663 if (ns->prefix != NULL)
1664 xmlFree((xmlChar *)ns->prefix);
1665 xmlFree(ns);
1666 }
1667}
1668
1669/**
Owen Taylor3473f882001-02-23 17:55:21 +00001670 * xmlXPathNodeSetCreate:
1671 * @val: an initial xmlNodePtr, or NULL
1672 *
1673 * Create a new xmlNodeSetPtr of type double and of value @val
1674 *
1675 * Returns the newly created object.
1676 */
1677xmlNodeSetPtr
1678xmlXPathNodeSetCreate(xmlNodePtr val) {
1679 xmlNodeSetPtr ret;
1680
1681 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1682 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001683 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001684 return(NULL);
1685 }
1686 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1687 if (val != NULL) {
1688 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1689 sizeof(xmlNodePtr));
1690 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001691 xmlXPathErrMemory(NULL, "creating nodeset\n");
1692 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001693 return(NULL);
1694 }
1695 memset(ret->nodeTab, 0 ,
1696 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1697 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001698 if (val->type == XML_NAMESPACE_DECL) {
1699 xmlNsPtr ns = (xmlNsPtr) val;
1700
1701 ret->nodeTab[ret->nodeNr++] =
1702 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1703 } else
1704 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001705 }
1706 return(ret);
1707}
1708
1709/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001710 * xmlXPathNodeSetContains:
1711 * @cur: the node-set
1712 * @val: the node
1713 *
1714 * checks whether @cur contains @val
1715 *
1716 * Returns true (1) if @cur contains @val, false (0) otherwise
1717 */
1718int
1719xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1720 int i;
1721
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001722 if (val->type == XML_NAMESPACE_DECL) {
1723 for (i = 0; i < cur->nodeNr; i++) {
1724 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1725 xmlNsPtr ns1, ns2;
1726
1727 ns1 = (xmlNsPtr) val;
1728 ns2 = (xmlNsPtr) cur->nodeTab[i];
1729 if (ns1 == ns2)
1730 return(1);
1731 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1732 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1733 return(1);
1734 }
1735 }
1736 } else {
1737 for (i = 0; i < cur->nodeNr; i++) {
1738 if (cur->nodeTab[i] == val)
1739 return(1);
1740 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001741 }
1742 return(0);
1743}
1744
1745/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001746 * xmlXPathNodeSetAddNs:
1747 * @cur: the initial node set
1748 * @node: the hosting node
1749 * @ns: a the namespace node
1750 *
1751 * add a new namespace node to an existing NodeSet
1752 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001753void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001754xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1755 int i;
1756
1757 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1758 (node->type != XML_ELEMENT_NODE))
1759 return;
1760
1761 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1762 /*
1763 * check against doublons
1764 */
1765 for (i = 0;i < cur->nodeNr;i++) {
1766 if ((cur->nodeTab[i] != NULL) &&
1767 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001768 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001769 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1770 return;
1771 }
1772
1773 /*
1774 * grow the nodeTab if needed
1775 */
1776 if (cur->nodeMax == 0) {
1777 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1778 sizeof(xmlNodePtr));
1779 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001780 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001781 return;
1782 }
1783 memset(cur->nodeTab, 0 ,
1784 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1785 cur->nodeMax = XML_NODESET_DEFAULT;
1786 } else if (cur->nodeNr == cur->nodeMax) {
1787 xmlNodePtr *temp;
1788
1789 cur->nodeMax *= 2;
1790 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1791 sizeof(xmlNodePtr));
1792 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001793 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001794 return;
1795 }
1796 cur->nodeTab = temp;
1797 }
1798 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1799}
1800
1801/**
Owen Taylor3473f882001-02-23 17:55:21 +00001802 * xmlXPathNodeSetAdd:
1803 * @cur: the initial node set
1804 * @val: a new xmlNodePtr
1805 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001806 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001807 */
1808void
1809xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1810 int i;
1811
1812 if (val == NULL) return;
1813
Daniel Veillardef0b4502003-03-24 13:57:34 +00001814#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001815 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1816 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001817#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001818
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001819 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001820 /*
1821 * check against doublons
1822 */
1823 for (i = 0;i < cur->nodeNr;i++)
1824 if (cur->nodeTab[i] == val) return;
1825
1826 /*
1827 * grow the nodeTab if needed
1828 */
1829 if (cur->nodeMax == 0) {
1830 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1831 sizeof(xmlNodePtr));
1832 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001833 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001834 return;
1835 }
1836 memset(cur->nodeTab, 0 ,
1837 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1838 cur->nodeMax = XML_NODESET_DEFAULT;
1839 } else if (cur->nodeNr == cur->nodeMax) {
1840 xmlNodePtr *temp;
1841
1842 cur->nodeMax *= 2;
1843 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1844 sizeof(xmlNodePtr));
1845 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001846 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001847 return;
1848 }
1849 cur->nodeTab = temp;
1850 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001851 if (val->type == XML_NAMESPACE_DECL) {
1852 xmlNsPtr ns = (xmlNsPtr) val;
1853
1854 cur->nodeTab[cur->nodeNr++] =
1855 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1856 } else
1857 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001858}
1859
1860/**
1861 * xmlXPathNodeSetAddUnique:
1862 * @cur: the initial node set
1863 * @val: a new xmlNodePtr
1864 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001865 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001866 * when we are sure the node is not already in the set.
1867 */
1868void
1869xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1870 if (val == NULL) return;
1871
Daniel Veillardef0b4502003-03-24 13:57:34 +00001872#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001873 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1874 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001875#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001876
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001877 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001878 /*
1879 * grow the nodeTab if needed
1880 */
1881 if (cur->nodeMax == 0) {
1882 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1883 sizeof(xmlNodePtr));
1884 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001885 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001886 return;
1887 }
1888 memset(cur->nodeTab, 0 ,
1889 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1890 cur->nodeMax = XML_NODESET_DEFAULT;
1891 } else if (cur->nodeNr == cur->nodeMax) {
1892 xmlNodePtr *temp;
1893
1894 cur->nodeMax *= 2;
1895 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1896 sizeof(xmlNodePtr));
1897 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001898 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001899 return;
1900 }
1901 cur->nodeTab = temp;
1902 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001903 if (val->type == XML_NAMESPACE_DECL) {
1904 xmlNsPtr ns = (xmlNsPtr) val;
1905
1906 cur->nodeTab[cur->nodeNr++] =
1907 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1908 } else
1909 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001910}
1911
1912/**
1913 * xmlXPathNodeSetMerge:
1914 * @val1: the first NodeSet or NULL
1915 * @val2: the second NodeSet
1916 *
1917 * Merges two nodesets, all nodes from @val2 are added to @val1
1918 * if @val1 is NULL, a new set is created and copied from @val2
1919 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001920 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001921 */
1922xmlNodeSetPtr
1923xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001924 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001925
1926 if (val2 == NULL) return(val1);
1927 if (val1 == NULL) {
1928 val1 = xmlXPathNodeSetCreate(NULL);
1929 }
1930
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001931 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001932 initNr = val1->nodeNr;
1933
1934 for (i = 0;i < val2->nodeNr;i++) {
1935 /*
1936 * check against doublons
1937 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001938 skip = 0;
1939 for (j = 0; j < initNr; j++) {
1940 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1941 skip = 1;
1942 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001943 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1944 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1945 xmlNsPtr ns1, ns2;
1946 ns1 = (xmlNsPtr) val1->nodeTab[j];
1947 ns2 = (xmlNsPtr) val2->nodeTab[i];
1948 if ((ns1->next == ns2->next) &&
1949 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1950 skip = 1;
1951 break;
1952 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001953 }
1954 }
1955 if (skip)
1956 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001957
1958 /*
1959 * grow the nodeTab if needed
1960 */
1961 if (val1->nodeMax == 0) {
1962 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1963 sizeof(xmlNodePtr));
1964 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001965 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001966 return(NULL);
1967 }
1968 memset(val1->nodeTab, 0 ,
1969 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1970 val1->nodeMax = XML_NODESET_DEFAULT;
1971 } else if (val1->nodeNr == val1->nodeMax) {
1972 xmlNodePtr *temp;
1973
1974 val1->nodeMax *= 2;
1975 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1976 sizeof(xmlNodePtr));
1977 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001978 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001979 return(NULL);
1980 }
1981 val1->nodeTab = temp;
1982 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001983 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1984 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1985
1986 val1->nodeTab[val1->nodeNr++] =
1987 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1988 } else
1989 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001990 }
1991
1992 return(val1);
1993}
1994
1995/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001996 * xmlXPathNodeSetMergeUnique:
1997 * @val1: the first NodeSet or NULL
1998 * @val2: the second NodeSet
1999 *
2000 * Merges two nodesets, all nodes from @val2 are added to @val1
2001 * if @val1 is NULL, a new set is created and copied from @val2
2002 *
2003 * Returns @val1 once extended or NULL in case of error.
2004 */
2005static xmlNodeSetPtr
2006xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002007 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002008
2009 if (val2 == NULL) return(val1);
2010 if (val1 == NULL) {
2011 val1 = xmlXPathNodeSetCreate(NULL);
2012 }
2013
2014 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002015
2016 for (i = 0;i < val2->nodeNr;i++) {
2017 /*
2018 * grow the nodeTab if needed
2019 */
2020 if (val1->nodeMax == 0) {
2021 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2022 sizeof(xmlNodePtr));
2023 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002024 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002025 return(NULL);
2026 }
2027 memset(val1->nodeTab, 0 ,
2028 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2029 val1->nodeMax = XML_NODESET_DEFAULT;
2030 } else if (val1->nodeNr == val1->nodeMax) {
2031 xmlNodePtr *temp;
2032
2033 val1->nodeMax *= 2;
2034 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2035 sizeof(xmlNodePtr));
2036 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002037 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002038 return(NULL);
2039 }
2040 val1->nodeTab = temp;
2041 }
2042 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2043 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2044
2045 val1->nodeTab[val1->nodeNr++] =
2046 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2047 } else
2048 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2049 }
2050
2051 return(val1);
2052}
2053
2054/**
Owen Taylor3473f882001-02-23 17:55:21 +00002055 * xmlXPathNodeSetDel:
2056 * @cur: the initial node set
2057 * @val: an xmlNodePtr
2058 *
2059 * Removes an xmlNodePtr from an existing NodeSet
2060 */
2061void
2062xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2063 int i;
2064
2065 if (cur == NULL) return;
2066 if (val == NULL) return;
2067
2068 /*
2069 * check against doublons
2070 */
2071 for (i = 0;i < cur->nodeNr;i++)
2072 if (cur->nodeTab[i] == val) break;
2073
2074 if (i >= cur->nodeNr) {
2075#ifdef DEBUG
2076 xmlGenericError(xmlGenericErrorContext,
2077 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2078 val->name);
2079#endif
2080 return;
2081 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002082 if ((cur->nodeTab[i] != NULL) &&
2083 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2084 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002085 cur->nodeNr--;
2086 for (;i < cur->nodeNr;i++)
2087 cur->nodeTab[i] = cur->nodeTab[i + 1];
2088 cur->nodeTab[cur->nodeNr] = NULL;
2089}
2090
2091/**
2092 * xmlXPathNodeSetRemove:
2093 * @cur: the initial node set
2094 * @val: the index to remove
2095 *
2096 * Removes an entry from an existing NodeSet list.
2097 */
2098void
2099xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2100 if (cur == NULL) return;
2101 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002102 if ((cur->nodeTab[val] != NULL) &&
2103 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2104 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002105 cur->nodeNr--;
2106 for (;val < cur->nodeNr;val++)
2107 cur->nodeTab[val] = cur->nodeTab[val + 1];
2108 cur->nodeTab[cur->nodeNr] = NULL;
2109}
2110
2111/**
2112 * xmlXPathFreeNodeSet:
2113 * @obj: the xmlNodeSetPtr to free
2114 *
2115 * Free the NodeSet compound (not the actual nodes !).
2116 */
2117void
2118xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2119 if (obj == NULL) return;
2120 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002121 int i;
2122
2123 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2124 for (i = 0;i < obj->nodeNr;i++)
2125 if ((obj->nodeTab[i] != NULL) &&
2126 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2127 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002128 xmlFree(obj->nodeTab);
2129 }
Owen Taylor3473f882001-02-23 17:55:21 +00002130 xmlFree(obj);
2131}
2132
2133/**
2134 * xmlXPathFreeValueTree:
2135 * @obj: the xmlNodeSetPtr to free
2136 *
2137 * Free the NodeSet compound and the actual tree, this is different
2138 * from xmlXPathFreeNodeSet()
2139 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002140static void
Owen Taylor3473f882001-02-23 17:55:21 +00002141xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2142 int i;
2143
2144 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002145
2146 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002147 for (i = 0;i < obj->nodeNr;i++) {
2148 if (obj->nodeTab[i] != NULL) {
2149 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2150 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2151 } else {
2152 xmlFreeNodeList(obj->nodeTab[i]);
2153 }
2154 }
2155 }
Owen Taylor3473f882001-02-23 17:55:21 +00002156 xmlFree(obj->nodeTab);
2157 }
Owen Taylor3473f882001-02-23 17:55:21 +00002158 xmlFree(obj);
2159}
2160
2161#if defined(DEBUG) || defined(DEBUG_STEP)
2162/**
2163 * xmlGenericErrorContextNodeSet:
2164 * @output: a FILE * for the output
2165 * @obj: the xmlNodeSetPtr to free
2166 *
2167 * Quick display of a NodeSet
2168 */
2169void
2170xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2171 int i;
2172
2173 if (output == NULL) output = xmlGenericErrorContext;
2174 if (obj == NULL) {
2175 fprintf(output, "NodeSet == NULL !\n");
2176 return;
2177 }
2178 if (obj->nodeNr == 0) {
2179 fprintf(output, "NodeSet is empty\n");
2180 return;
2181 }
2182 if (obj->nodeTab == NULL) {
2183 fprintf(output, " nodeTab == NULL !\n");
2184 return;
2185 }
2186 for (i = 0; i < obj->nodeNr; i++) {
2187 if (obj->nodeTab[i] == NULL) {
2188 fprintf(output, " NULL !\n");
2189 return;
2190 }
2191 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2192 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2193 fprintf(output, " /");
2194 else if (obj->nodeTab[i]->name == NULL)
2195 fprintf(output, " noname!");
2196 else fprintf(output, " %s", obj->nodeTab[i]->name);
2197 }
2198 fprintf(output, "\n");
2199}
2200#endif
2201
2202/**
2203 * xmlXPathNewNodeSet:
2204 * @val: the NodePtr value
2205 *
2206 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2207 * it with the single Node @val
2208 *
2209 * Returns the newly created object.
2210 */
2211xmlXPathObjectPtr
2212xmlXPathNewNodeSet(xmlNodePtr val) {
2213 xmlXPathObjectPtr ret;
2214
2215 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2216 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002217 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002218 return(NULL);
2219 }
2220 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2221 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002222 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002223 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002224 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002225 return(ret);
2226}
2227
2228/**
2229 * xmlXPathNewValueTree:
2230 * @val: the NodePtr value
2231 *
2232 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2233 * it with the tree root @val
2234 *
2235 * Returns the newly created object.
2236 */
2237xmlXPathObjectPtr
2238xmlXPathNewValueTree(xmlNodePtr val) {
2239 xmlXPathObjectPtr ret;
2240
2241 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2242 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002243 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002244 return(NULL);
2245 }
2246 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2247 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002248 ret->boolval = 1;
2249 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002250 ret->nodesetval = xmlXPathNodeSetCreate(val);
2251 return(ret);
2252}
2253
2254/**
2255 * xmlXPathNewNodeSetList:
2256 * @val: an existing NodeSet
2257 *
2258 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2259 * it with the Nodeset @val
2260 *
2261 * Returns the newly created object.
2262 */
2263xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002264xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2265{
Owen Taylor3473f882001-02-23 17:55:21 +00002266 xmlXPathObjectPtr ret;
2267 int i;
2268
2269 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002270 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002271 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002272 ret = xmlXPathNewNodeSet(NULL);
2273 else {
2274 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2275 for (i = 1; i < val->nodeNr; ++i)
2276 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2277 }
Owen Taylor3473f882001-02-23 17:55:21 +00002278
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002279 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002280}
2281
2282/**
2283 * xmlXPathWrapNodeSet:
2284 * @val: the NodePtr value
2285 *
2286 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2287 *
2288 * Returns the newly created object.
2289 */
2290xmlXPathObjectPtr
2291xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2292 xmlXPathObjectPtr ret;
2293
2294 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2295 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002296 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002297 return(NULL);
2298 }
2299 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2300 ret->type = XPATH_NODESET;
2301 ret->nodesetval = val;
2302 return(ret);
2303}
2304
2305/**
2306 * xmlXPathFreeNodeSetList:
2307 * @obj: an existing NodeSetList object
2308 *
2309 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2310 * the list contrary to xmlXPathFreeObject().
2311 */
2312void
2313xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2314 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002315 xmlFree(obj);
2316}
2317
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002318/**
2319 * xmlXPathDifference:
2320 * @nodes1: a node-set
2321 * @nodes2: a node-set
2322 *
2323 * Implements the EXSLT - Sets difference() function:
2324 * node-set set:difference (node-set, node-set)
2325 *
2326 * Returns the difference between the two node sets, or nodes1 if
2327 * nodes2 is empty
2328 */
2329xmlNodeSetPtr
2330xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2331 xmlNodeSetPtr ret;
2332 int i, l1;
2333 xmlNodePtr cur;
2334
2335 if (xmlXPathNodeSetIsEmpty(nodes2))
2336 return(nodes1);
2337
2338 ret = xmlXPathNodeSetCreate(NULL);
2339 if (xmlXPathNodeSetIsEmpty(nodes1))
2340 return(ret);
2341
2342 l1 = xmlXPathNodeSetGetLength(nodes1);
2343
2344 for (i = 0; i < l1; i++) {
2345 cur = xmlXPathNodeSetItem(nodes1, i);
2346 if (!xmlXPathNodeSetContains(nodes2, cur))
2347 xmlXPathNodeSetAddUnique(ret, cur);
2348 }
2349 return(ret);
2350}
2351
2352/**
2353 * xmlXPathIntersection:
2354 * @nodes1: a node-set
2355 * @nodes2: a node-set
2356 *
2357 * Implements the EXSLT - Sets intersection() function:
2358 * node-set set:intersection (node-set, node-set)
2359 *
2360 * Returns a node set comprising the nodes that are within both the
2361 * node sets passed as arguments
2362 */
2363xmlNodeSetPtr
2364xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2365 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2366 int i, l1;
2367 xmlNodePtr cur;
2368
2369 if (xmlXPathNodeSetIsEmpty(nodes1))
2370 return(ret);
2371 if (xmlXPathNodeSetIsEmpty(nodes2))
2372 return(ret);
2373
2374 l1 = xmlXPathNodeSetGetLength(nodes1);
2375
2376 for (i = 0; i < l1; i++) {
2377 cur = xmlXPathNodeSetItem(nodes1, i);
2378 if (xmlXPathNodeSetContains(nodes2, cur))
2379 xmlXPathNodeSetAddUnique(ret, cur);
2380 }
2381 return(ret);
2382}
2383
2384/**
2385 * xmlXPathDistinctSorted:
2386 * @nodes: a node-set, sorted by document order
2387 *
2388 * Implements the EXSLT - Sets distinct() function:
2389 * node-set set:distinct (node-set)
2390 *
2391 * Returns a subset of the nodes contained in @nodes, or @nodes if
2392 * it is empty
2393 */
2394xmlNodeSetPtr
2395xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2396 xmlNodeSetPtr ret;
2397 xmlHashTablePtr hash;
2398 int i, l;
2399 xmlChar * strval;
2400 xmlNodePtr cur;
2401
2402 if (xmlXPathNodeSetIsEmpty(nodes))
2403 return(nodes);
2404
2405 ret = xmlXPathNodeSetCreate(NULL);
2406 l = xmlXPathNodeSetGetLength(nodes);
2407 hash = xmlHashCreate (l);
2408 for (i = 0; i < l; i++) {
2409 cur = xmlXPathNodeSetItem(nodes, i);
2410 strval = xmlXPathCastNodeToString(cur);
2411 if (xmlHashLookup(hash, strval) == NULL) {
2412 xmlHashAddEntry(hash, strval, strval);
2413 xmlXPathNodeSetAddUnique(ret, cur);
2414 } else {
2415 xmlFree(strval);
2416 }
2417 }
2418 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2419 return(ret);
2420}
2421
2422/**
2423 * xmlXPathDistinct:
2424 * @nodes: a node-set
2425 *
2426 * Implements the EXSLT - Sets distinct() function:
2427 * node-set set:distinct (node-set)
2428 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2429 * is called with the sorted node-set
2430 *
2431 * Returns a subset of the nodes contained in @nodes, or @nodes if
2432 * it is empty
2433 */
2434xmlNodeSetPtr
2435xmlXPathDistinct (xmlNodeSetPtr nodes) {
2436 if (xmlXPathNodeSetIsEmpty(nodes))
2437 return(nodes);
2438
2439 xmlXPathNodeSetSort(nodes);
2440 return(xmlXPathDistinctSorted(nodes));
2441}
2442
2443/**
2444 * xmlXPathHasSameNodes:
2445 * @nodes1: a node-set
2446 * @nodes2: a node-set
2447 *
2448 * Implements the EXSLT - Sets has-same-nodes function:
2449 * boolean set:has-same-node(node-set, node-set)
2450 *
2451 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2452 * otherwise
2453 */
2454int
2455xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2456 int i, l;
2457 xmlNodePtr cur;
2458
2459 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2460 xmlXPathNodeSetIsEmpty(nodes2))
2461 return(0);
2462
2463 l = xmlXPathNodeSetGetLength(nodes1);
2464 for (i = 0; i < l; i++) {
2465 cur = xmlXPathNodeSetItem(nodes1, i);
2466 if (xmlXPathNodeSetContains(nodes2, cur))
2467 return(1);
2468 }
2469 return(0);
2470}
2471
2472/**
2473 * xmlXPathNodeLeadingSorted:
2474 * @nodes: a node-set, sorted by document order
2475 * @node: a node
2476 *
2477 * Implements the EXSLT - Sets leading() function:
2478 * node-set set:leading (node-set, node-set)
2479 *
2480 * Returns the nodes in @nodes that precede @node in document order,
2481 * @nodes if @node is NULL or an empty node-set if @nodes
2482 * doesn't contain @node
2483 */
2484xmlNodeSetPtr
2485xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2486 int i, l;
2487 xmlNodePtr cur;
2488 xmlNodeSetPtr ret;
2489
2490 if (node == NULL)
2491 return(nodes);
2492
2493 ret = xmlXPathNodeSetCreate(NULL);
2494 if (xmlXPathNodeSetIsEmpty(nodes) ||
2495 (!xmlXPathNodeSetContains(nodes, node)))
2496 return(ret);
2497
2498 l = xmlXPathNodeSetGetLength(nodes);
2499 for (i = 0; i < l; i++) {
2500 cur = xmlXPathNodeSetItem(nodes, i);
2501 if (cur == node)
2502 break;
2503 xmlXPathNodeSetAddUnique(ret, cur);
2504 }
2505 return(ret);
2506}
2507
2508/**
2509 * xmlXPathNodeLeading:
2510 * @nodes: a node-set
2511 * @node: a node
2512 *
2513 * Implements the EXSLT - Sets leading() function:
2514 * node-set set:leading (node-set, node-set)
2515 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2516 * is called.
2517 *
2518 * Returns the nodes in @nodes that precede @node in document order,
2519 * @nodes if @node is NULL or an empty node-set if @nodes
2520 * doesn't contain @node
2521 */
2522xmlNodeSetPtr
2523xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2524 xmlXPathNodeSetSort(nodes);
2525 return(xmlXPathNodeLeadingSorted(nodes, node));
2526}
2527
2528/**
2529 * xmlXPathLeadingSorted:
2530 * @nodes1: a node-set, sorted by document order
2531 * @nodes2: a node-set, sorted by document order
2532 *
2533 * Implements the EXSLT - Sets leading() function:
2534 * node-set set:leading (node-set, node-set)
2535 *
2536 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2537 * in document order, @nodes1 if @nodes2 is NULL or empty or
2538 * an empty node-set if @nodes1 doesn't contain @nodes2
2539 */
2540xmlNodeSetPtr
2541xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2542 if (xmlXPathNodeSetIsEmpty(nodes2))
2543 return(nodes1);
2544 return(xmlXPathNodeLeadingSorted(nodes1,
2545 xmlXPathNodeSetItem(nodes2, 1)));
2546}
2547
2548/**
2549 * xmlXPathLeading:
2550 * @nodes1: a node-set
2551 * @nodes2: a node-set
2552 *
2553 * Implements the EXSLT - Sets leading() function:
2554 * node-set set:leading (node-set, node-set)
2555 * @nodes1 and @nodes2 are sorted by document order, then
2556 * #exslSetsLeadingSorted is called.
2557 *
2558 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2559 * in document order, @nodes1 if @nodes2 is NULL or empty or
2560 * an empty node-set if @nodes1 doesn't contain @nodes2
2561 */
2562xmlNodeSetPtr
2563xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2564 if (xmlXPathNodeSetIsEmpty(nodes2))
2565 return(nodes1);
2566 if (xmlXPathNodeSetIsEmpty(nodes1))
2567 return(xmlXPathNodeSetCreate(NULL));
2568 xmlXPathNodeSetSort(nodes1);
2569 xmlXPathNodeSetSort(nodes2);
2570 return(xmlXPathNodeLeadingSorted(nodes1,
2571 xmlXPathNodeSetItem(nodes2, 1)));
2572}
2573
2574/**
2575 * xmlXPathNodeTrailingSorted:
2576 * @nodes: a node-set, sorted by document order
2577 * @node: a node
2578 *
2579 * Implements the EXSLT - Sets trailing() function:
2580 * node-set set:trailing (node-set, node-set)
2581 *
2582 * Returns the nodes in @nodes that follow @node in document order,
2583 * @nodes if @node is NULL or an empty node-set if @nodes
2584 * doesn't contain @node
2585 */
2586xmlNodeSetPtr
2587xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2588 int i, l;
2589 xmlNodePtr cur;
2590 xmlNodeSetPtr ret;
2591
2592 if (node == NULL)
2593 return(nodes);
2594
2595 ret = xmlXPathNodeSetCreate(NULL);
2596 if (xmlXPathNodeSetIsEmpty(nodes) ||
2597 (!xmlXPathNodeSetContains(nodes, node)))
2598 return(ret);
2599
2600 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002601 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002602 cur = xmlXPathNodeSetItem(nodes, i);
2603 if (cur == node)
2604 break;
2605 xmlXPathNodeSetAddUnique(ret, cur);
2606 }
2607 return(ret);
2608}
2609
2610/**
2611 * xmlXPathNodeTrailing:
2612 * @nodes: a node-set
2613 * @node: a node
2614 *
2615 * Implements the EXSLT - Sets trailing() function:
2616 * node-set set:trailing (node-set, node-set)
2617 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2618 * is called.
2619 *
2620 * Returns the nodes in @nodes that follow @node in document order,
2621 * @nodes if @node is NULL or an empty node-set if @nodes
2622 * doesn't contain @node
2623 */
2624xmlNodeSetPtr
2625xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2626 xmlXPathNodeSetSort(nodes);
2627 return(xmlXPathNodeTrailingSorted(nodes, node));
2628}
2629
2630/**
2631 * xmlXPathTrailingSorted:
2632 * @nodes1: a node-set, sorted by document order
2633 * @nodes2: a node-set, sorted by document order
2634 *
2635 * Implements the EXSLT - Sets trailing() function:
2636 * node-set set:trailing (node-set, node-set)
2637 *
2638 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2639 * in document order, @nodes1 if @nodes2 is NULL or empty or
2640 * an empty node-set if @nodes1 doesn't contain @nodes2
2641 */
2642xmlNodeSetPtr
2643xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2644 if (xmlXPathNodeSetIsEmpty(nodes2))
2645 return(nodes1);
2646 return(xmlXPathNodeTrailingSorted(nodes1,
2647 xmlXPathNodeSetItem(nodes2, 0)));
2648}
2649
2650/**
2651 * xmlXPathTrailing:
2652 * @nodes1: a node-set
2653 * @nodes2: a node-set
2654 *
2655 * Implements the EXSLT - Sets trailing() function:
2656 * node-set set:trailing (node-set, node-set)
2657 * @nodes1 and @nodes2 are sorted by document order, then
2658 * #xmlXPathTrailingSorted is called.
2659 *
2660 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2661 * in document order, @nodes1 if @nodes2 is NULL or empty or
2662 * an empty node-set if @nodes1 doesn't contain @nodes2
2663 */
2664xmlNodeSetPtr
2665xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2666 if (xmlXPathNodeSetIsEmpty(nodes2))
2667 return(nodes1);
2668 if (xmlXPathNodeSetIsEmpty(nodes1))
2669 return(xmlXPathNodeSetCreate(NULL));
2670 xmlXPathNodeSetSort(nodes1);
2671 xmlXPathNodeSetSort(nodes2);
2672 return(xmlXPathNodeTrailingSorted(nodes1,
2673 xmlXPathNodeSetItem(nodes2, 0)));
2674}
2675
Owen Taylor3473f882001-02-23 17:55:21 +00002676/************************************************************************
2677 * *
2678 * Routines to handle extra functions *
2679 * *
2680 ************************************************************************/
2681
2682/**
2683 * xmlXPathRegisterFunc:
2684 * @ctxt: the XPath context
2685 * @name: the function name
2686 * @f: the function implementation or NULL
2687 *
2688 * Register a new function. If @f is NULL it unregisters the function
2689 *
2690 * Returns 0 in case of success, -1 in case of error
2691 */
2692int
2693xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2694 xmlXPathFunction f) {
2695 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2696}
2697
2698/**
2699 * xmlXPathRegisterFuncNS:
2700 * @ctxt: the XPath context
2701 * @name: the function name
2702 * @ns_uri: the function namespace URI
2703 * @f: the function implementation or NULL
2704 *
2705 * Register a new function. If @f is NULL it unregisters the function
2706 *
2707 * Returns 0 in case of success, -1 in case of error
2708 */
2709int
2710xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2711 const xmlChar *ns_uri, xmlXPathFunction f) {
2712 if (ctxt == NULL)
2713 return(-1);
2714 if (name == NULL)
2715 return(-1);
2716
2717 if (ctxt->funcHash == NULL)
2718 ctxt->funcHash = xmlHashCreate(0);
2719 if (ctxt->funcHash == NULL)
2720 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002721 if (f == NULL)
2722 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002723 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2724}
2725
2726/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002727 * xmlXPathRegisterFuncLookup:
2728 * @ctxt: the XPath context
2729 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002730 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002731 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002732 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002733 */
2734void
2735xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2736 xmlXPathFuncLookupFunc f,
2737 void *funcCtxt) {
2738 if (ctxt == NULL)
2739 return;
2740 ctxt->funcLookupFunc = (void *) f;
2741 ctxt->funcLookupData = funcCtxt;
2742}
2743
2744/**
Owen Taylor3473f882001-02-23 17:55:21 +00002745 * xmlXPathFunctionLookup:
2746 * @ctxt: the XPath context
2747 * @name: the function name
2748 *
2749 * Search in the Function array of the context for the given
2750 * function.
2751 *
2752 * Returns the xmlXPathFunction or NULL if not found
2753 */
2754xmlXPathFunction
2755xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002756 if (ctxt == NULL)
2757 return (NULL);
2758
2759 if (ctxt->funcLookupFunc != NULL) {
2760 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002761 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002762
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002763 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002764 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002765 if (ret != NULL)
2766 return(ret);
2767 }
Owen Taylor3473f882001-02-23 17:55:21 +00002768 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2769}
2770
2771/**
2772 * xmlXPathFunctionLookupNS:
2773 * @ctxt: the XPath context
2774 * @name: the function name
2775 * @ns_uri: the function namespace URI
2776 *
2777 * Search in the Function array of the context for the given
2778 * function.
2779 *
2780 * Returns the xmlXPathFunction or NULL if not found
2781 */
2782xmlXPathFunction
2783xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2784 const xmlChar *ns_uri) {
2785 if (ctxt == NULL)
2786 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002787 if (name == NULL)
2788 return(NULL);
2789
Thomas Broyerba4ad322001-07-26 16:55:21 +00002790 if (ctxt->funcLookupFunc != NULL) {
2791 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002792 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002793
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002794 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002795 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002796 if (ret != NULL)
2797 return(ret);
2798 }
2799
2800 if (ctxt->funcHash == NULL)
2801 return(NULL);
2802
Owen Taylor3473f882001-02-23 17:55:21 +00002803 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2804}
2805
2806/**
2807 * xmlXPathRegisteredFuncsCleanup:
2808 * @ctxt: the XPath context
2809 *
2810 * Cleanup the XPath context data associated to registered functions
2811 */
2812void
2813xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2814 if (ctxt == NULL)
2815 return;
2816
2817 xmlHashFree(ctxt->funcHash, NULL);
2818 ctxt->funcHash = NULL;
2819}
2820
2821/************************************************************************
2822 * *
2823 * Routines to handle Variable *
2824 * *
2825 ************************************************************************/
2826
2827/**
2828 * xmlXPathRegisterVariable:
2829 * @ctxt: the XPath context
2830 * @name: the variable name
2831 * @value: the variable value or NULL
2832 *
2833 * Register a new variable value. If @value is NULL it unregisters
2834 * the variable
2835 *
2836 * Returns 0 in case of success, -1 in case of error
2837 */
2838int
2839xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2840 xmlXPathObjectPtr value) {
2841 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2842}
2843
2844/**
2845 * xmlXPathRegisterVariableNS:
2846 * @ctxt: the XPath context
2847 * @name: the variable name
2848 * @ns_uri: the variable namespace URI
2849 * @value: the variable value or NULL
2850 *
2851 * Register a new variable value. If @value is NULL it unregisters
2852 * the variable
2853 *
2854 * Returns 0 in case of success, -1 in case of error
2855 */
2856int
2857xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2858 const xmlChar *ns_uri,
2859 xmlXPathObjectPtr value) {
2860 if (ctxt == NULL)
2861 return(-1);
2862 if (name == NULL)
2863 return(-1);
2864
2865 if (ctxt->varHash == NULL)
2866 ctxt->varHash = xmlHashCreate(0);
2867 if (ctxt->varHash == NULL)
2868 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002869 if (value == NULL)
2870 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2871 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002872 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2873 (void *) value,
2874 (xmlHashDeallocator)xmlXPathFreeObject));
2875}
2876
2877/**
2878 * xmlXPathRegisterVariableLookup:
2879 * @ctxt: the XPath context
2880 * @f: the lookup function
2881 * @data: the lookup data
2882 *
2883 * register an external mechanism to do variable lookup
2884 */
2885void
2886xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2887 xmlXPathVariableLookupFunc f, void *data) {
2888 if (ctxt == NULL)
2889 return;
2890 ctxt->varLookupFunc = (void *) f;
2891 ctxt->varLookupData = data;
2892}
2893
2894/**
2895 * xmlXPathVariableLookup:
2896 * @ctxt: the XPath context
2897 * @name: the variable name
2898 *
2899 * Search in the Variable array of the context for the given
2900 * variable value.
2901 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002902 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002903 */
2904xmlXPathObjectPtr
2905xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2906 if (ctxt == NULL)
2907 return(NULL);
2908
2909 if (ctxt->varLookupFunc != NULL) {
2910 xmlXPathObjectPtr ret;
2911
2912 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2913 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002914 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002915 }
2916 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2917}
2918
2919/**
2920 * xmlXPathVariableLookupNS:
2921 * @ctxt: the XPath context
2922 * @name: the variable name
2923 * @ns_uri: the variable namespace URI
2924 *
2925 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002926 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002927 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002928 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002929 */
2930xmlXPathObjectPtr
2931xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2932 const xmlChar *ns_uri) {
2933 if (ctxt == NULL)
2934 return(NULL);
2935
2936 if (ctxt->varLookupFunc != NULL) {
2937 xmlXPathObjectPtr ret;
2938
2939 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2940 (ctxt->varLookupData, name, ns_uri);
2941 if (ret != NULL) return(ret);
2942 }
2943
2944 if (ctxt->varHash == NULL)
2945 return(NULL);
2946 if (name == NULL)
2947 return(NULL);
2948
Daniel Veillard8c357d52001-07-03 23:43:33 +00002949 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2950 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002951}
2952
2953/**
2954 * xmlXPathRegisteredVariablesCleanup:
2955 * @ctxt: the XPath context
2956 *
2957 * Cleanup the XPath context data associated to registered variables
2958 */
2959void
2960xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2961 if (ctxt == NULL)
2962 return;
2963
Daniel Veillard76d66f42001-05-16 21:05:17 +00002964 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002965 ctxt->varHash = NULL;
2966}
2967
2968/**
2969 * xmlXPathRegisterNs:
2970 * @ctxt: the XPath context
2971 * @prefix: the namespace prefix
2972 * @ns_uri: the namespace name
2973 *
2974 * Register a new namespace. If @ns_uri is NULL it unregisters
2975 * the namespace
2976 *
2977 * Returns 0 in case of success, -1 in case of error
2978 */
2979int
2980xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2981 const xmlChar *ns_uri) {
2982 if (ctxt == NULL)
2983 return(-1);
2984 if (prefix == NULL)
2985 return(-1);
2986
2987 if (ctxt->nsHash == NULL)
2988 ctxt->nsHash = xmlHashCreate(10);
2989 if (ctxt->nsHash == NULL)
2990 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00002991 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00002992 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00002993 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00002994 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002995 (xmlHashDeallocator)xmlFree));
2996}
2997
2998/**
2999 * xmlXPathNsLookup:
3000 * @ctxt: the XPath context
3001 * @prefix: the namespace prefix value
3002 *
3003 * Search in the namespace declaration array of the context for the given
3004 * namespace name associated to the given prefix
3005 *
3006 * Returns the value or NULL if not found
3007 */
3008const xmlChar *
3009xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3010 if (ctxt == NULL)
3011 return(NULL);
3012 if (prefix == NULL)
3013 return(NULL);
3014
3015#ifdef XML_XML_NAMESPACE
3016 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3017 return(XML_XML_NAMESPACE);
3018#endif
3019
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003020 if (ctxt->namespaces != NULL) {
3021 int i;
3022
3023 for (i = 0;i < ctxt->nsNr;i++) {
3024 if ((ctxt->namespaces[i] != NULL) &&
3025 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3026 return(ctxt->namespaces[i]->href);
3027 }
3028 }
Owen Taylor3473f882001-02-23 17:55:21 +00003029
3030 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3031}
3032
3033/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003034 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003035 * @ctxt: the XPath context
3036 *
3037 * Cleanup the XPath context data associated to registered variables
3038 */
3039void
3040xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3041 if (ctxt == NULL)
3042 return;
3043
Daniel Veillard42766c02002-08-22 20:52:17 +00003044 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003045 ctxt->nsHash = NULL;
3046}
3047
3048/************************************************************************
3049 * *
3050 * Routines to handle Values *
3051 * *
3052 ************************************************************************/
3053
3054/* Allocations are terrible, one need to optimize all this !!! */
3055
3056/**
3057 * xmlXPathNewFloat:
3058 * @val: the double value
3059 *
3060 * Create a new xmlXPathObjectPtr of type double and of value @val
3061 *
3062 * Returns the newly created object.
3063 */
3064xmlXPathObjectPtr
3065xmlXPathNewFloat(double val) {
3066 xmlXPathObjectPtr ret;
3067
3068 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3069 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003070 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003071 return(NULL);
3072 }
3073 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3074 ret->type = XPATH_NUMBER;
3075 ret->floatval = val;
3076 return(ret);
3077}
3078
3079/**
3080 * xmlXPathNewBoolean:
3081 * @val: the boolean value
3082 *
3083 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3084 *
3085 * Returns the newly created object.
3086 */
3087xmlXPathObjectPtr
3088xmlXPathNewBoolean(int val) {
3089 xmlXPathObjectPtr ret;
3090
3091 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3092 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003093 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003094 return(NULL);
3095 }
3096 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3097 ret->type = XPATH_BOOLEAN;
3098 ret->boolval = (val != 0);
3099 return(ret);
3100}
3101
3102/**
3103 * xmlXPathNewString:
3104 * @val: the xmlChar * value
3105 *
3106 * Create a new xmlXPathObjectPtr of type string and of value @val
3107 *
3108 * Returns the newly created object.
3109 */
3110xmlXPathObjectPtr
3111xmlXPathNewString(const xmlChar *val) {
3112 xmlXPathObjectPtr ret;
3113
3114 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3115 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003116 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003117 return(NULL);
3118 }
3119 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3120 ret->type = XPATH_STRING;
3121 if (val != NULL)
3122 ret->stringval = xmlStrdup(val);
3123 else
3124 ret->stringval = xmlStrdup((const xmlChar *)"");
3125 return(ret);
3126}
3127
3128/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003129 * xmlXPathWrapString:
3130 * @val: the xmlChar * value
3131 *
3132 * Wraps the @val string into an XPath object.
3133 *
3134 * Returns the newly created object.
3135 */
3136xmlXPathObjectPtr
3137xmlXPathWrapString (xmlChar *val) {
3138 xmlXPathObjectPtr ret;
3139
3140 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3141 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003142 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003143 return(NULL);
3144 }
3145 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3146 ret->type = XPATH_STRING;
3147 ret->stringval = val;
3148 return(ret);
3149}
3150
3151/**
Owen Taylor3473f882001-02-23 17:55:21 +00003152 * xmlXPathNewCString:
3153 * @val: the char * value
3154 *
3155 * Create a new xmlXPathObjectPtr of type string and of value @val
3156 *
3157 * Returns the newly created object.
3158 */
3159xmlXPathObjectPtr
3160xmlXPathNewCString(const char *val) {
3161 xmlXPathObjectPtr ret;
3162
3163 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3164 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003165 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003166 return(NULL);
3167 }
3168 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3169 ret->type = XPATH_STRING;
3170 ret->stringval = xmlStrdup(BAD_CAST val);
3171 return(ret);
3172}
3173
3174/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003175 * xmlXPathWrapCString:
3176 * @val: the char * value
3177 *
3178 * Wraps a string into an XPath object.
3179 *
3180 * Returns the newly created object.
3181 */
3182xmlXPathObjectPtr
3183xmlXPathWrapCString (char * val) {
3184 return(xmlXPathWrapString((xmlChar *)(val)));
3185}
3186
3187/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003188 * xmlXPathWrapExternal:
3189 * @val: the user data
3190 *
3191 * Wraps the @val data into an XPath object.
3192 *
3193 * Returns the newly created object.
3194 */
3195xmlXPathObjectPtr
3196xmlXPathWrapExternal (void *val) {
3197 xmlXPathObjectPtr ret;
3198
3199 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3200 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003201 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003202 return(NULL);
3203 }
3204 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3205 ret->type = XPATH_USERS;
3206 ret->user = val;
3207 return(ret);
3208}
3209
3210/**
Owen Taylor3473f882001-02-23 17:55:21 +00003211 * xmlXPathObjectCopy:
3212 * @val: the original object
3213 *
3214 * allocate a new copy of a given object
3215 *
3216 * Returns the newly created object.
3217 */
3218xmlXPathObjectPtr
3219xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3220 xmlXPathObjectPtr ret;
3221
3222 if (val == NULL)
3223 return(NULL);
3224
3225 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3226 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003227 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003228 return(NULL);
3229 }
3230 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3231 switch (val->type) {
3232 case XPATH_BOOLEAN:
3233 case XPATH_NUMBER:
3234 case XPATH_POINT:
3235 case XPATH_RANGE:
3236 break;
3237 case XPATH_STRING:
3238 ret->stringval = xmlStrdup(val->stringval);
3239 break;
3240 case XPATH_XSLT_TREE:
3241 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003242 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003243 xmlNodePtr cur, tmp;
3244 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003245
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003246 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003247 top = xmlNewDoc(NULL);
3248 top->name = (char *)
3249 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003250 ret->user = top;
3251 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003252 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003253 cur = val->nodesetval->nodeTab[0]->children;
3254 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003255 tmp = xmlDocCopyNode(cur, top, 1);
3256 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003257 cur = cur->next;
3258 }
3259 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003260 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003261 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003262 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003263 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003264 break;
3265 case XPATH_NODESET:
3266 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003267 /* Do not deallocate the copied tree value */
3268 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003269 break;
3270 case XPATH_LOCATIONSET:
3271#ifdef LIBXML_XPTR_ENABLED
3272 {
3273 xmlLocationSetPtr loc = val->user;
3274 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3275 break;
3276 }
3277#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003278 case XPATH_USERS:
3279 ret->user = val->user;
3280 break;
3281 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003282 xmlGenericError(xmlGenericErrorContext,
3283 "xmlXPathObjectCopy: unsupported type %d\n",
3284 val->type);
3285 break;
3286 }
3287 return(ret);
3288}
3289
3290/**
3291 * xmlXPathFreeObject:
3292 * @obj: the object to free
3293 *
3294 * Free up an xmlXPathObjectPtr object.
3295 */
3296void
3297xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3298 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003299 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003300 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003301 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003302 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003303 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003304 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003305 xmlXPathFreeValueTree(obj->nodesetval);
3306 } else {
3307 if (obj->nodesetval != NULL)
3308 xmlXPathFreeNodeSet(obj->nodesetval);
3309 }
Owen Taylor3473f882001-02-23 17:55:21 +00003310#ifdef LIBXML_XPTR_ENABLED
3311 } else if (obj->type == XPATH_LOCATIONSET) {
3312 if (obj->user != NULL)
3313 xmlXPtrFreeLocationSet(obj->user);
3314#endif
3315 } else if (obj->type == XPATH_STRING) {
3316 if (obj->stringval != NULL)
3317 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003318 }
3319
Owen Taylor3473f882001-02-23 17:55:21 +00003320 xmlFree(obj);
3321}
3322
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003323
3324/************************************************************************
3325 * *
3326 * Type Casting Routines *
3327 * *
3328 ************************************************************************/
3329
3330/**
3331 * xmlXPathCastBooleanToString:
3332 * @val: a boolean
3333 *
3334 * Converts a boolean to its string value.
3335 *
3336 * Returns a newly allocated string.
3337 */
3338xmlChar *
3339xmlXPathCastBooleanToString (int val) {
3340 xmlChar *ret;
3341 if (val)
3342 ret = xmlStrdup((const xmlChar *) "true");
3343 else
3344 ret = xmlStrdup((const xmlChar *) "false");
3345 return(ret);
3346}
3347
3348/**
3349 * xmlXPathCastNumberToString:
3350 * @val: a number
3351 *
3352 * Converts a number to its string value.
3353 *
3354 * Returns a newly allocated string.
3355 */
3356xmlChar *
3357xmlXPathCastNumberToString (double val) {
3358 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003359 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003360 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003361 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003362 break;
3363 case -1:
3364 ret = xmlStrdup((const xmlChar *) "-Infinity");
3365 break;
3366 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003367 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003368 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003369 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3370 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003371 } else {
3372 /* could be improved */
3373 char buf[100];
3374 xmlXPathFormatNumber(val, buf, 100);
3375 ret = xmlStrdup((const xmlChar *) buf);
3376 }
3377 }
3378 return(ret);
3379}
3380
3381/**
3382 * xmlXPathCastNodeToString:
3383 * @node: a node
3384 *
3385 * Converts a node to its string value.
3386 *
3387 * Returns a newly allocated string.
3388 */
3389xmlChar *
3390xmlXPathCastNodeToString (xmlNodePtr node) {
3391 return(xmlNodeGetContent(node));
3392}
3393
3394/**
3395 * xmlXPathCastNodeSetToString:
3396 * @ns: a node-set
3397 *
3398 * Converts a node-set to its string value.
3399 *
3400 * Returns a newly allocated string.
3401 */
3402xmlChar *
3403xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3404 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3405 return(xmlStrdup((const xmlChar *) ""));
3406
3407 xmlXPathNodeSetSort(ns);
3408 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3409}
3410
3411/**
3412 * xmlXPathCastToString:
3413 * @val: an XPath object
3414 *
3415 * Converts an existing object to its string() equivalent
3416 *
3417 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003418 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003419 * string object).
3420 */
3421xmlChar *
3422xmlXPathCastToString(xmlXPathObjectPtr val) {
3423 xmlChar *ret = NULL;
3424
3425 if (val == NULL)
3426 return(xmlStrdup((const xmlChar *) ""));
3427 switch (val->type) {
3428 case XPATH_UNDEFINED:
3429#ifdef DEBUG_EXPR
3430 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3431#endif
3432 ret = xmlStrdup((const xmlChar *) "");
3433 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003434 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003435 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003436 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3437 break;
3438 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003439 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003440 case XPATH_BOOLEAN:
3441 ret = xmlXPathCastBooleanToString(val->boolval);
3442 break;
3443 case XPATH_NUMBER: {
3444 ret = xmlXPathCastNumberToString(val->floatval);
3445 break;
3446 }
3447 case XPATH_USERS:
3448 case XPATH_POINT:
3449 case XPATH_RANGE:
3450 case XPATH_LOCATIONSET:
3451 TODO
3452 ret = xmlStrdup((const xmlChar *) "");
3453 break;
3454 }
3455 return(ret);
3456}
3457
3458/**
3459 * xmlXPathConvertString:
3460 * @val: an XPath object
3461 *
3462 * Converts an existing object to its string() equivalent
3463 *
3464 * Returns the new object, the old one is freed (or the operation
3465 * is done directly on @val)
3466 */
3467xmlXPathObjectPtr
3468xmlXPathConvertString(xmlXPathObjectPtr val) {
3469 xmlChar *res = NULL;
3470
3471 if (val == NULL)
3472 return(xmlXPathNewCString(""));
3473
3474 switch (val->type) {
3475 case XPATH_UNDEFINED:
3476#ifdef DEBUG_EXPR
3477 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3478#endif
3479 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003480 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003481 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003482 res = xmlXPathCastNodeSetToString(val->nodesetval);
3483 break;
3484 case XPATH_STRING:
3485 return(val);
3486 case XPATH_BOOLEAN:
3487 res = xmlXPathCastBooleanToString(val->boolval);
3488 break;
3489 case XPATH_NUMBER:
3490 res = xmlXPathCastNumberToString(val->floatval);
3491 break;
3492 case XPATH_USERS:
3493 case XPATH_POINT:
3494 case XPATH_RANGE:
3495 case XPATH_LOCATIONSET:
3496 TODO;
3497 break;
3498 }
3499 xmlXPathFreeObject(val);
3500 if (res == NULL)
3501 return(xmlXPathNewCString(""));
3502 return(xmlXPathWrapString(res));
3503}
3504
3505/**
3506 * xmlXPathCastBooleanToNumber:
3507 * @val: a boolean
3508 *
3509 * Converts a boolean to its number value
3510 *
3511 * Returns the number value
3512 */
3513double
3514xmlXPathCastBooleanToNumber(int val) {
3515 if (val)
3516 return(1.0);
3517 return(0.0);
3518}
3519
3520/**
3521 * xmlXPathCastStringToNumber:
3522 * @val: a string
3523 *
3524 * Converts a string to its number value
3525 *
3526 * Returns the number value
3527 */
3528double
3529xmlXPathCastStringToNumber(const xmlChar * val) {
3530 return(xmlXPathStringEvalNumber(val));
3531}
3532
3533/**
3534 * xmlXPathCastNodeToNumber:
3535 * @node: a node
3536 *
3537 * Converts a node to its number value
3538 *
3539 * Returns the number value
3540 */
3541double
3542xmlXPathCastNodeToNumber (xmlNodePtr node) {
3543 xmlChar *strval;
3544 double ret;
3545
3546 if (node == NULL)
3547 return(xmlXPathNAN);
3548 strval = xmlXPathCastNodeToString(node);
3549 if (strval == NULL)
3550 return(xmlXPathNAN);
3551 ret = xmlXPathCastStringToNumber(strval);
3552 xmlFree(strval);
3553
3554 return(ret);
3555}
3556
3557/**
3558 * xmlXPathCastNodeSetToNumber:
3559 * @ns: a node-set
3560 *
3561 * Converts a node-set to its number value
3562 *
3563 * Returns the number value
3564 */
3565double
3566xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3567 xmlChar *str;
3568 double ret;
3569
3570 if (ns == NULL)
3571 return(xmlXPathNAN);
3572 str = xmlXPathCastNodeSetToString(ns);
3573 ret = xmlXPathCastStringToNumber(str);
3574 xmlFree(str);
3575 return(ret);
3576}
3577
3578/**
3579 * xmlXPathCastToNumber:
3580 * @val: an XPath object
3581 *
3582 * Converts an XPath object to its number value
3583 *
3584 * Returns the number value
3585 */
3586double
3587xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3588 double ret = 0.0;
3589
3590 if (val == NULL)
3591 return(xmlXPathNAN);
3592 switch (val->type) {
3593 case XPATH_UNDEFINED:
3594#ifdef DEGUB_EXPR
3595 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3596#endif
3597 ret = xmlXPathNAN;
3598 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003599 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003600 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003601 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3602 break;
3603 case XPATH_STRING:
3604 ret = xmlXPathCastStringToNumber(val->stringval);
3605 break;
3606 case XPATH_NUMBER:
3607 ret = val->floatval;
3608 break;
3609 case XPATH_BOOLEAN:
3610 ret = xmlXPathCastBooleanToNumber(val->boolval);
3611 break;
3612 case XPATH_USERS:
3613 case XPATH_POINT:
3614 case XPATH_RANGE:
3615 case XPATH_LOCATIONSET:
3616 TODO;
3617 ret = xmlXPathNAN;
3618 break;
3619 }
3620 return(ret);
3621}
3622
3623/**
3624 * xmlXPathConvertNumber:
3625 * @val: an XPath object
3626 *
3627 * Converts an existing object to its number() equivalent
3628 *
3629 * Returns the new object, the old one is freed (or the operation
3630 * is done directly on @val)
3631 */
3632xmlXPathObjectPtr
3633xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3634 xmlXPathObjectPtr ret;
3635
3636 if (val == NULL)
3637 return(xmlXPathNewFloat(0.0));
3638 if (val->type == XPATH_NUMBER)
3639 return(val);
3640 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3641 xmlXPathFreeObject(val);
3642 return(ret);
3643}
3644
3645/**
3646 * xmlXPathCastNumberToBoolean:
3647 * @val: a number
3648 *
3649 * Converts a number to its boolean value
3650 *
3651 * Returns the boolean value
3652 */
3653int
3654xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003655 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003656 return(0);
3657 return(1);
3658}
3659
3660/**
3661 * xmlXPathCastStringToBoolean:
3662 * @val: a string
3663 *
3664 * Converts a string to its boolean value
3665 *
3666 * Returns the boolean value
3667 */
3668int
3669xmlXPathCastStringToBoolean (const xmlChar *val) {
3670 if ((val == NULL) || (xmlStrlen(val) == 0))
3671 return(0);
3672 return(1);
3673}
3674
3675/**
3676 * xmlXPathCastNodeSetToBoolean:
3677 * @ns: a node-set
3678 *
3679 * Converts a node-set to its boolean value
3680 *
3681 * Returns the boolean value
3682 */
3683int
3684xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3685 if ((ns == NULL) || (ns->nodeNr == 0))
3686 return(0);
3687 return(1);
3688}
3689
3690/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003691 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003692 * @val: an XPath object
3693 *
3694 * Converts an XPath object to its boolean value
3695 *
3696 * Returns the boolean value
3697 */
3698int
3699xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3700 int ret = 0;
3701
3702 if (val == NULL)
3703 return(0);
3704 switch (val->type) {
3705 case XPATH_UNDEFINED:
3706#ifdef DEBUG_EXPR
3707 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3708#endif
3709 ret = 0;
3710 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003711 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003712 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003713 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3714 break;
3715 case XPATH_STRING:
3716 ret = xmlXPathCastStringToBoolean(val->stringval);
3717 break;
3718 case XPATH_NUMBER:
3719 ret = xmlXPathCastNumberToBoolean(val->floatval);
3720 break;
3721 case XPATH_BOOLEAN:
3722 ret = val->boolval;
3723 break;
3724 case XPATH_USERS:
3725 case XPATH_POINT:
3726 case XPATH_RANGE:
3727 case XPATH_LOCATIONSET:
3728 TODO;
3729 ret = 0;
3730 break;
3731 }
3732 return(ret);
3733}
3734
3735
3736/**
3737 * xmlXPathConvertBoolean:
3738 * @val: an XPath object
3739 *
3740 * Converts an existing object to its boolean() equivalent
3741 *
3742 * Returns the new object, the old one is freed (or the operation
3743 * is done directly on @val)
3744 */
3745xmlXPathObjectPtr
3746xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3747 xmlXPathObjectPtr ret;
3748
3749 if (val == NULL)
3750 return(xmlXPathNewBoolean(0));
3751 if (val->type == XPATH_BOOLEAN)
3752 return(val);
3753 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3754 xmlXPathFreeObject(val);
3755 return(ret);
3756}
3757
Owen Taylor3473f882001-02-23 17:55:21 +00003758/************************************************************************
3759 * *
3760 * Routines to handle XPath contexts *
3761 * *
3762 ************************************************************************/
3763
3764/**
3765 * xmlXPathNewContext:
3766 * @doc: the XML document
3767 *
3768 * Create a new xmlXPathContext
3769 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003770 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003771 */
3772xmlXPathContextPtr
3773xmlXPathNewContext(xmlDocPtr doc) {
3774 xmlXPathContextPtr ret;
3775
3776 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3777 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003778 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003779 return(NULL);
3780 }
3781 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3782 ret->doc = doc;
3783 ret->node = NULL;
3784
3785 ret->varHash = NULL;
3786
3787 ret->nb_types = 0;
3788 ret->max_types = 0;
3789 ret->types = NULL;
3790
3791 ret->funcHash = xmlHashCreate(0);
3792
3793 ret->nb_axis = 0;
3794 ret->max_axis = 0;
3795 ret->axis = NULL;
3796
3797 ret->nsHash = NULL;
3798 ret->user = NULL;
3799
3800 ret->contextSize = -1;
3801 ret->proximityPosition = -1;
3802
3803 xmlXPathRegisterAllFunctions(ret);
3804
3805 return(ret);
3806}
3807
3808/**
3809 * xmlXPathFreeContext:
3810 * @ctxt: the context to free
3811 *
3812 * Free up an xmlXPathContext
3813 */
3814void
3815xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3816 xmlXPathRegisteredNsCleanup(ctxt);
3817 xmlXPathRegisteredFuncsCleanup(ctxt);
3818 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003819 xmlFree(ctxt);
3820}
3821
3822/************************************************************************
3823 * *
3824 * Routines to handle XPath parser contexts *
3825 * *
3826 ************************************************************************/
3827
3828#define CHECK_CTXT(ctxt) \
3829 if (ctxt == NULL) { \
3830 xmlGenericError(xmlGenericErrorContext, \
3831 "%s:%d Internal error: ctxt == NULL\n", \
3832 __FILE__, __LINE__); \
3833 } \
3834
3835
3836#define CHECK_CONTEXT(ctxt) \
3837 if (ctxt == NULL) { \
3838 xmlGenericError(xmlGenericErrorContext, \
3839 "%s:%d Internal error: no context\n", \
3840 __FILE__, __LINE__); \
3841 } \
3842 else if (ctxt->doc == NULL) { \
3843 xmlGenericError(xmlGenericErrorContext, \
3844 "%s:%d Internal error: no document\n", \
3845 __FILE__, __LINE__); \
3846 } \
3847 else if (ctxt->doc->children == NULL) { \
3848 xmlGenericError(xmlGenericErrorContext, \
3849 "%s:%d Internal error: document without root\n", \
3850 __FILE__, __LINE__); \
3851 } \
3852
3853
3854/**
3855 * xmlXPathNewParserContext:
3856 * @str: the XPath expression
3857 * @ctxt: the XPath context
3858 *
3859 * Create a new xmlXPathParserContext
3860 *
3861 * Returns the xmlXPathParserContext just allocated.
3862 */
3863xmlXPathParserContextPtr
3864xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3865 xmlXPathParserContextPtr ret;
3866
3867 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3868 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003869 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003870 return(NULL);
3871 }
3872 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3873 ret->cur = ret->base = str;
3874 ret->context = ctxt;
3875
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003876 ret->comp = xmlXPathNewCompExpr();
3877 if (ret->comp == NULL) {
3878 xmlFree(ret->valueTab);
3879 xmlFree(ret);
3880 return(NULL);
3881 }
3882
3883 return(ret);
3884}
3885
3886/**
3887 * xmlXPathCompParserContext:
3888 * @comp: the XPath compiled expression
3889 * @ctxt: the XPath context
3890 *
3891 * Create a new xmlXPathParserContext when processing a compiled expression
3892 *
3893 * Returns the xmlXPathParserContext just allocated.
3894 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003895static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003896xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3897 xmlXPathParserContextPtr ret;
3898
3899 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3900 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003901 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003902 return(NULL);
3903 }
3904 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3905
Owen Taylor3473f882001-02-23 17:55:21 +00003906 /* Allocate the value stack */
3907 ret->valueTab = (xmlXPathObjectPtr *)
3908 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003909 if (ret->valueTab == NULL) {
3910 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003911 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003912 return(NULL);
3913 }
Owen Taylor3473f882001-02-23 17:55:21 +00003914 ret->valueNr = 0;
3915 ret->valueMax = 10;
3916 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003917
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003918 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003919 ret->comp = comp;
3920
Owen Taylor3473f882001-02-23 17:55:21 +00003921 return(ret);
3922}
3923
3924/**
3925 * xmlXPathFreeParserContext:
3926 * @ctxt: the context to free
3927 *
3928 * Free up an xmlXPathParserContext
3929 */
3930void
3931xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3932 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003933 xmlFree(ctxt->valueTab);
3934 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003935 if (ctxt->comp)
3936 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003937 xmlFree(ctxt);
3938}
3939
3940/************************************************************************
3941 * *
3942 * The implicit core function library *
3943 * *
3944 ************************************************************************/
3945
Owen Taylor3473f882001-02-23 17:55:21 +00003946/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003947 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003948 * @node: a node pointer
3949 *
3950 * Function computing the beginning of the string value of the node,
3951 * used to speed up comparisons
3952 *
3953 * Returns an int usable as a hash
3954 */
3955static unsigned int
3956xmlXPathNodeValHash(xmlNodePtr node) {
3957 int len = 2;
3958 const xmlChar * string = NULL;
3959 xmlNodePtr tmp = NULL;
3960 unsigned int ret = 0;
3961
3962 if (node == NULL)
3963 return(0);
3964
Daniel Veillard9adc0462003-03-24 18:39:54 +00003965 if (node->type == XML_DOCUMENT_NODE) {
3966 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3967 if (tmp == NULL)
3968 node = node->children;
3969 else
3970 node = tmp;
3971
3972 if (node == NULL)
3973 return(0);
3974 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003975
3976 switch (node->type) {
3977 case XML_COMMENT_NODE:
3978 case XML_PI_NODE:
3979 case XML_CDATA_SECTION_NODE:
3980 case XML_TEXT_NODE:
3981 string = node->content;
3982 if (string == NULL)
3983 return(0);
3984 if (string[0] == 0)
3985 return(0);
3986 return(((unsigned int) string[0]) +
3987 (((unsigned int) string[1]) << 8));
3988 case XML_NAMESPACE_DECL:
3989 string = ((xmlNsPtr)node)->href;
3990 if (string == NULL)
3991 return(0);
3992 if (string[0] == 0)
3993 return(0);
3994 return(((unsigned int) string[0]) +
3995 (((unsigned int) string[1]) << 8));
3996 case XML_ATTRIBUTE_NODE:
3997 tmp = ((xmlAttrPtr) node)->children;
3998 break;
3999 case XML_ELEMENT_NODE:
4000 tmp = node->children;
4001 break;
4002 default:
4003 return(0);
4004 }
4005 while (tmp != NULL) {
4006 switch (tmp->type) {
4007 case XML_COMMENT_NODE:
4008 case XML_PI_NODE:
4009 case XML_CDATA_SECTION_NODE:
4010 case XML_TEXT_NODE:
4011 string = tmp->content;
4012 break;
4013 case XML_NAMESPACE_DECL:
4014 string = ((xmlNsPtr)tmp)->href;
4015 break;
4016 default:
4017 break;
4018 }
4019 if ((string != NULL) && (string[0] != 0)) {
4020 if (string[0] == 0)
4021 return(0);
4022 if (len == 1) {
4023 return(ret + (((unsigned int) string[0]) << 8));
4024 }
4025 if (string[1] == 0) {
4026 len = 1;
4027 ret = (unsigned int) string[0];
4028 } else {
4029 return(((unsigned int) string[0]) +
4030 (((unsigned int) string[1]) << 8));
4031 }
4032 }
4033 /*
4034 * Skip to next node
4035 */
4036 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4037 if (tmp->children->type != XML_ENTITY_DECL) {
4038 tmp = tmp->children;
4039 continue;
4040 }
4041 }
4042 if (tmp == node)
4043 break;
4044
4045 if (tmp->next != NULL) {
4046 tmp = tmp->next;
4047 continue;
4048 }
4049
4050 do {
4051 tmp = tmp->parent;
4052 if (tmp == NULL)
4053 break;
4054 if (tmp == node) {
4055 tmp = NULL;
4056 break;
4057 }
4058 if (tmp->next != NULL) {
4059 tmp = tmp->next;
4060 break;
4061 }
4062 } while (tmp != NULL);
4063 }
4064 return(ret);
4065}
4066
4067/**
4068 * xmlXPathStringHash:
4069 * @string: a string
4070 *
4071 * Function computing the beginning of the string value of the node,
4072 * used to speed up comparisons
4073 *
4074 * Returns an int usable as a hash
4075 */
4076static unsigned int
4077xmlXPathStringHash(const xmlChar * string) {
4078 if (string == NULL)
4079 return((unsigned int) 0);
4080 if (string[0] == 0)
4081 return(0);
4082 return(((unsigned int) string[0]) +
4083 (((unsigned int) string[1]) << 8));
4084}
4085
4086/**
Owen Taylor3473f882001-02-23 17:55:21 +00004087 * xmlXPathCompareNodeSetFloat:
4088 * @ctxt: the XPath Parser context
4089 * @inf: less than (1) or greater than (0)
4090 * @strict: is the comparison strict
4091 * @arg: the node set
4092 * @f: the value
4093 *
4094 * Implement the compare operation between a nodeset and a number
4095 * @ns < @val (1, 1, ...
4096 * @ns <= @val (1, 0, ...
4097 * @ns > @val (0, 1, ...
4098 * @ns >= @val (0, 0, ...
4099 *
4100 * If one object to be compared is a node-set and the other is a number,
4101 * then the comparison will be true if and only if there is a node in the
4102 * node-set such that the result of performing the comparison on the number
4103 * to be compared and on the result of converting the string-value of that
4104 * node to a number using the number function is true.
4105 *
4106 * Returns 0 or 1 depending on the results of the test.
4107 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004108static int
Owen Taylor3473f882001-02-23 17:55:21 +00004109xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4110 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4111 int i, ret = 0;
4112 xmlNodeSetPtr ns;
4113 xmlChar *str2;
4114
4115 if ((f == NULL) || (arg == NULL) ||
4116 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4117 xmlXPathFreeObject(arg);
4118 xmlXPathFreeObject(f);
4119 return(0);
4120 }
4121 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004122 if (ns != NULL) {
4123 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004124 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004125 if (str2 != NULL) {
4126 valuePush(ctxt,
4127 xmlXPathNewString(str2));
4128 xmlFree(str2);
4129 xmlXPathNumberFunction(ctxt, 1);
4130 valuePush(ctxt, xmlXPathObjectCopy(f));
4131 ret = xmlXPathCompareValues(ctxt, inf, strict);
4132 if (ret)
4133 break;
4134 }
4135 }
Owen Taylor3473f882001-02-23 17:55:21 +00004136 }
4137 xmlXPathFreeObject(arg);
4138 xmlXPathFreeObject(f);
4139 return(ret);
4140}
4141
4142/**
4143 * xmlXPathCompareNodeSetString:
4144 * @ctxt: the XPath Parser context
4145 * @inf: less than (1) or greater than (0)
4146 * @strict: is the comparison strict
4147 * @arg: the node set
4148 * @s: the value
4149 *
4150 * Implement the compare operation between a nodeset and a string
4151 * @ns < @val (1, 1, ...
4152 * @ns <= @val (1, 0, ...
4153 * @ns > @val (0, 1, ...
4154 * @ns >= @val (0, 0, ...
4155 *
4156 * If one object to be compared is a node-set and the other is a string,
4157 * then the comparison will be true if and only if there is a node in
4158 * the node-set such that the result of performing the comparison on the
4159 * string-value of the node and the other string is true.
4160 *
4161 * Returns 0 or 1 depending on the results of the test.
4162 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004163static int
Owen Taylor3473f882001-02-23 17:55:21 +00004164xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4165 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4166 int i, ret = 0;
4167 xmlNodeSetPtr ns;
4168 xmlChar *str2;
4169
4170 if ((s == NULL) || (arg == NULL) ||
4171 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4172 xmlXPathFreeObject(arg);
4173 xmlXPathFreeObject(s);
4174 return(0);
4175 }
4176 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004177 if (ns != NULL) {
4178 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004179 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004180 if (str2 != NULL) {
4181 valuePush(ctxt,
4182 xmlXPathNewString(str2));
4183 xmlFree(str2);
4184 valuePush(ctxt, xmlXPathObjectCopy(s));
4185 ret = xmlXPathCompareValues(ctxt, inf, strict);
4186 if (ret)
4187 break;
4188 }
4189 }
Owen Taylor3473f882001-02-23 17:55:21 +00004190 }
4191 xmlXPathFreeObject(arg);
4192 xmlXPathFreeObject(s);
4193 return(ret);
4194}
4195
4196/**
4197 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004198 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004199 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004200 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004201 * @arg2: the second node set object
4202 *
4203 * Implement the compare operation on nodesets:
4204 *
4205 * If both objects to be compared are node-sets, then the comparison
4206 * will be true if and only if there is a node in the first node-set
4207 * and a node in the second node-set such that the result of performing
4208 * the comparison on the string-values of the two nodes is true.
4209 * ....
4210 * When neither object to be compared is a node-set and the operator
4211 * is <=, <, >= or >, then the objects are compared by converting both
4212 * objects to numbers and comparing the numbers according to IEEE 754.
4213 * ....
4214 * The number function converts its argument to a number as follows:
4215 * - a string that consists of optional whitespace followed by an
4216 * optional minus sign followed by a Number followed by whitespace
4217 * is converted to the IEEE 754 number that is nearest (according
4218 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4219 * represented by the string; any other string is converted to NaN
4220 *
4221 * Conclusion all nodes need to be converted first to their string value
4222 * and then the comparison must be done when possible
4223 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004224static int
4225xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004226 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4227 int i, j, init = 0;
4228 double val1;
4229 double *values2;
4230 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004231 xmlNodeSetPtr ns1;
4232 xmlNodeSetPtr ns2;
4233
4234 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004235 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4236 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004237 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004238 }
Owen Taylor3473f882001-02-23 17:55:21 +00004239 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004240 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4241 xmlXPathFreeObject(arg1);
4242 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004243 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004244 }
Owen Taylor3473f882001-02-23 17:55:21 +00004245
4246 ns1 = arg1->nodesetval;
4247 ns2 = arg2->nodesetval;
4248
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004249 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004250 xmlXPathFreeObject(arg1);
4251 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004252 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004253 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004254 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004255 xmlXPathFreeObject(arg1);
4256 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004257 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004258 }
Owen Taylor3473f882001-02-23 17:55:21 +00004259
4260 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4261 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004262 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004263 xmlXPathFreeObject(arg1);
4264 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004265 return(0);
4266 }
4267 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004268 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004269 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004270 continue;
4271 for (j = 0;j < ns2->nodeNr;j++) {
4272 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004273 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004274 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004275 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004276 continue;
4277 if (inf && strict)
4278 ret = (val1 < values2[j]);
4279 else if (inf && !strict)
4280 ret = (val1 <= values2[j]);
4281 else if (!inf && strict)
4282 ret = (val1 > values2[j]);
4283 else if (!inf && !strict)
4284 ret = (val1 >= values2[j]);
4285 if (ret)
4286 break;
4287 }
4288 if (ret)
4289 break;
4290 init = 1;
4291 }
4292 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004293 xmlXPathFreeObject(arg1);
4294 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004295 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004296}
4297
4298/**
4299 * xmlXPathCompareNodeSetValue:
4300 * @ctxt: the XPath Parser context
4301 * @inf: less than (1) or greater than (0)
4302 * @strict: is the comparison strict
4303 * @arg: the node set
4304 * @val: the value
4305 *
4306 * Implement the compare operation between a nodeset and a value
4307 * @ns < @val (1, 1, ...
4308 * @ns <= @val (1, 0, ...
4309 * @ns > @val (0, 1, ...
4310 * @ns >= @val (0, 0, ...
4311 *
4312 * If one object to be compared is a node-set and the other is a boolean,
4313 * then the comparison will be true if and only if the result of performing
4314 * the comparison on the boolean and on the result of converting
4315 * the node-set to a boolean using the boolean function is true.
4316 *
4317 * Returns 0 or 1 depending on the results of the test.
4318 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004319static int
Owen Taylor3473f882001-02-23 17:55:21 +00004320xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4321 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4322 if ((val == NULL) || (arg == NULL) ||
4323 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4324 return(0);
4325
4326 switch(val->type) {
4327 case XPATH_NUMBER:
4328 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4329 case XPATH_NODESET:
4330 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004331 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004332 case XPATH_STRING:
4333 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4334 case XPATH_BOOLEAN:
4335 valuePush(ctxt, arg);
4336 xmlXPathBooleanFunction(ctxt, 1);
4337 valuePush(ctxt, val);
4338 return(xmlXPathCompareValues(ctxt, inf, strict));
4339 default:
4340 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004341 }
4342 return(0);
4343}
4344
4345/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004346 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004347 * @arg: the nodeset object argument
4348 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004349 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004350 *
4351 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4352 * If one object to be compared is a node-set and the other is a string,
4353 * then the comparison will be true if and only if there is a node in
4354 * the node-set such that the result of performing the comparison on the
4355 * string-value of the node and the other string is true.
4356 *
4357 * Returns 0 or 1 depending on the results of the test.
4358 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004359static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004360xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004361{
Owen Taylor3473f882001-02-23 17:55:21 +00004362 int i;
4363 xmlNodeSetPtr ns;
4364 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004365 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004366
4367 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004368 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4369 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004370 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004371 /*
4372 * A NULL nodeset compared with a string is always false
4373 * (since there is no node equal, and no node not equal)
4374 */
4375 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004376 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004377 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004378 for (i = 0; i < ns->nodeNr; i++) {
4379 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4380 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4381 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4382 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004383 if (neq)
4384 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004385 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004386 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4387 if (neq)
4388 continue;
4389 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004390 } else if (neq) {
4391 if (str2 != NULL)
4392 xmlFree(str2);
4393 return (1);
4394 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004395 if (str2 != NULL)
4396 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004397 } else if (neq)
4398 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004399 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004400 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004401}
4402
4403/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004404 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004405 * @arg: the nodeset object argument
4406 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004407 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004408 *
4409 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4410 * If one object to be compared is a node-set and the other is a number,
4411 * then the comparison will be true if and only if there is a node in
4412 * the node-set such that the result of performing the comparison on the
4413 * number to be compared and on the result of converting the string-value
4414 * of that node to a number using the number function is true.
4415 *
4416 * Returns 0 or 1 depending on the results of the test.
4417 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004418static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004419xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4420 xmlXPathObjectPtr arg, double f, int neq) {
4421 int i, ret=0;
4422 xmlNodeSetPtr ns;
4423 xmlChar *str2;
4424 xmlXPathObjectPtr val;
4425 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004426
4427 if ((arg == NULL) ||
4428 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4429 return(0);
4430
William M. Brack0c022ad2002-07-12 00:56:01 +00004431 ns = arg->nodesetval;
4432 if (ns != NULL) {
4433 for (i=0;i<ns->nodeNr;i++) {
4434 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4435 if (str2 != NULL) {
4436 valuePush(ctxt, xmlXPathNewString(str2));
4437 xmlFree(str2);
4438 xmlXPathNumberFunction(ctxt, 1);
4439 val = valuePop(ctxt);
4440 v = val->floatval;
4441 xmlXPathFreeObject(val);
4442 if (!xmlXPathIsNaN(v)) {
4443 if ((!neq) && (v==f)) {
4444 ret = 1;
4445 break;
4446 } else if ((neq) && (v!=f)) {
4447 ret = 1;
4448 break;
4449 }
4450 }
4451 }
4452 }
4453 }
4454
4455 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004456}
4457
4458
4459/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004460 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004461 * @arg1: first nodeset object argument
4462 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004463 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004464 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004465 * Implement the equal / not equal operation on XPath nodesets:
4466 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004467 * If both objects to be compared are node-sets, then the comparison
4468 * will be true if and only if there is a node in the first node-set and
4469 * a node in the second node-set such that the result of performing the
4470 * comparison on the string-values of the two nodes is true.
4471 *
4472 * (needless to say, this is a costly operation)
4473 *
4474 * Returns 0 or 1 depending on the results of the test.
4475 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004476static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004477xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004478 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004479 unsigned int *hashs1;
4480 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004481 xmlChar **values1;
4482 xmlChar **values2;
4483 int ret = 0;
4484 xmlNodeSetPtr ns1;
4485 xmlNodeSetPtr ns2;
4486
4487 if ((arg1 == NULL) ||
4488 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4489 return(0);
4490 if ((arg2 == NULL) ||
4491 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4492 return(0);
4493
4494 ns1 = arg1->nodesetval;
4495 ns2 = arg2->nodesetval;
4496
Daniel Veillard911f49a2001-04-07 15:39:35 +00004497 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004498 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004499 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004500 return(0);
4501
4502 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004503 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004504 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004505 if (neq == 0)
4506 for (i = 0;i < ns1->nodeNr;i++)
4507 for (j = 0;j < ns2->nodeNr;j++)
4508 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4509 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004510
4511 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004512 if (values1 == NULL) {
4513 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004514 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004515 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004516 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4517 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004518 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004519 xmlFree(values1);
4520 return(0);
4521 }
Owen Taylor3473f882001-02-23 17:55:21 +00004522 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4523 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4524 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004525 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004526 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004527 xmlFree(values1);
4528 return(0);
4529 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004530 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4531 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004532 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004533 xmlFree(hashs1);
4534 xmlFree(values1);
4535 xmlFree(values2);
4536 return(0);
4537 }
Owen Taylor3473f882001-02-23 17:55:21 +00004538 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4539 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004540 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004541 for (j = 0;j < ns2->nodeNr;j++) {
4542 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004543 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004544 if (hashs1[i] != hashs2[j]) {
4545 if (neq) {
4546 ret = 1;
4547 break;
4548 }
4549 }
4550 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004551 if (values1[i] == NULL)
4552 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4553 if (values2[j] == NULL)
4554 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004555 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004556 if (ret)
4557 break;
4558 }
Owen Taylor3473f882001-02-23 17:55:21 +00004559 }
4560 if (ret)
4561 break;
4562 }
4563 for (i = 0;i < ns1->nodeNr;i++)
4564 if (values1[i] != NULL)
4565 xmlFree(values1[i]);
4566 for (j = 0;j < ns2->nodeNr;j++)
4567 if (values2[j] != NULL)
4568 xmlFree(values2[j]);
4569 xmlFree(values1);
4570 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004571 xmlFree(hashs1);
4572 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004573 return(ret);
4574}
4575
William M. Brack0c022ad2002-07-12 00:56:01 +00004576static int
4577xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4578 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004579 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004580 /*
4581 *At this point we are assured neither arg1 nor arg2
4582 *is a nodeset, so we can just pick the appropriate routine.
4583 */
Owen Taylor3473f882001-02-23 17:55:21 +00004584 switch (arg1->type) {
4585 case XPATH_UNDEFINED:
4586#ifdef DEBUG_EXPR
4587 xmlGenericError(xmlGenericErrorContext,
4588 "Equal: undefined\n");
4589#endif
4590 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004591 case XPATH_BOOLEAN:
4592 switch (arg2->type) {
4593 case XPATH_UNDEFINED:
4594#ifdef DEBUG_EXPR
4595 xmlGenericError(xmlGenericErrorContext,
4596 "Equal: undefined\n");
4597#endif
4598 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004599 case XPATH_BOOLEAN:
4600#ifdef DEBUG_EXPR
4601 xmlGenericError(xmlGenericErrorContext,
4602 "Equal: %d boolean %d \n",
4603 arg1->boolval, arg2->boolval);
4604#endif
4605 ret = (arg1->boolval == arg2->boolval);
4606 break;
4607 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004608 ret = (arg1->boolval ==
4609 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004610 break;
4611 case XPATH_STRING:
4612 if ((arg2->stringval == NULL) ||
4613 (arg2->stringval[0] == 0)) ret = 0;
4614 else
4615 ret = 1;
4616 ret = (arg1->boolval == ret);
4617 break;
4618 case XPATH_USERS:
4619 case XPATH_POINT:
4620 case XPATH_RANGE:
4621 case XPATH_LOCATIONSET:
4622 TODO
4623 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004624 case XPATH_NODESET:
4625 case XPATH_XSLT_TREE:
4626 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004627 }
4628 break;
4629 case XPATH_NUMBER:
4630 switch (arg2->type) {
4631 case XPATH_UNDEFINED:
4632#ifdef DEBUG_EXPR
4633 xmlGenericError(xmlGenericErrorContext,
4634 "Equal: undefined\n");
4635#endif
4636 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004637 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004638 ret = (arg2->boolval==
4639 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004640 break;
4641 case XPATH_STRING:
4642 valuePush(ctxt, arg2);
4643 xmlXPathNumberFunction(ctxt, 1);
4644 arg2 = valuePop(ctxt);
4645 /* no break on purpose */
4646 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004647 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004648 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4649 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004650 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4651 if (xmlXPathIsInf(arg2->floatval) == 1)
4652 ret = 1;
4653 else
4654 ret = 0;
4655 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4656 if (xmlXPathIsInf(arg2->floatval) == -1)
4657 ret = 1;
4658 else
4659 ret = 0;
4660 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4661 if (xmlXPathIsInf(arg1->floatval) == 1)
4662 ret = 1;
4663 else
4664 ret = 0;
4665 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4666 if (xmlXPathIsInf(arg1->floatval) == -1)
4667 ret = 1;
4668 else
4669 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004670 } else {
4671 ret = (arg1->floatval == arg2->floatval);
4672 }
Owen Taylor3473f882001-02-23 17:55:21 +00004673 break;
4674 case XPATH_USERS:
4675 case XPATH_POINT:
4676 case XPATH_RANGE:
4677 case XPATH_LOCATIONSET:
4678 TODO
4679 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004680 case XPATH_NODESET:
4681 case XPATH_XSLT_TREE:
4682 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004683 }
4684 break;
4685 case XPATH_STRING:
4686 switch (arg2->type) {
4687 case XPATH_UNDEFINED:
4688#ifdef DEBUG_EXPR
4689 xmlGenericError(xmlGenericErrorContext,
4690 "Equal: undefined\n");
4691#endif
4692 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004693 case XPATH_BOOLEAN:
4694 if ((arg1->stringval == NULL) ||
4695 (arg1->stringval[0] == 0)) ret = 0;
4696 else
4697 ret = 1;
4698 ret = (arg2->boolval == ret);
4699 break;
4700 case XPATH_STRING:
4701 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4702 break;
4703 case XPATH_NUMBER:
4704 valuePush(ctxt, arg1);
4705 xmlXPathNumberFunction(ctxt, 1);
4706 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004707 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004708 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4709 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004710 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4711 if (xmlXPathIsInf(arg2->floatval) == 1)
4712 ret = 1;
4713 else
4714 ret = 0;
4715 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4716 if (xmlXPathIsInf(arg2->floatval) == -1)
4717 ret = 1;
4718 else
4719 ret = 0;
4720 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4721 if (xmlXPathIsInf(arg1->floatval) == 1)
4722 ret = 1;
4723 else
4724 ret = 0;
4725 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4726 if (xmlXPathIsInf(arg1->floatval) == -1)
4727 ret = 1;
4728 else
4729 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004730 } else {
4731 ret = (arg1->floatval == arg2->floatval);
4732 }
Owen Taylor3473f882001-02-23 17:55:21 +00004733 break;
4734 case XPATH_USERS:
4735 case XPATH_POINT:
4736 case XPATH_RANGE:
4737 case XPATH_LOCATIONSET:
4738 TODO
4739 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004740 case XPATH_NODESET:
4741 case XPATH_XSLT_TREE:
4742 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004743 }
4744 break;
4745 case XPATH_USERS:
4746 case XPATH_POINT:
4747 case XPATH_RANGE:
4748 case XPATH_LOCATIONSET:
4749 TODO
4750 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004751 case XPATH_NODESET:
4752 case XPATH_XSLT_TREE:
4753 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004754 }
4755 xmlXPathFreeObject(arg1);
4756 xmlXPathFreeObject(arg2);
4757 return(ret);
4758}
4759
William M. Brack0c022ad2002-07-12 00:56:01 +00004760/**
4761 * xmlXPathEqualValues:
4762 * @ctxt: the XPath Parser context
4763 *
4764 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4765 *
4766 * Returns 0 or 1 depending on the results of the test.
4767 */
4768int
4769xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4770 xmlXPathObjectPtr arg1, arg2, argtmp;
4771 int ret = 0;
4772
4773 arg2 = valuePop(ctxt);
4774 arg1 = valuePop(ctxt);
4775 if ((arg1 == NULL) || (arg2 == NULL)) {
4776 if (arg1 != NULL)
4777 xmlXPathFreeObject(arg1);
4778 else
4779 xmlXPathFreeObject(arg2);
4780 XP_ERROR0(XPATH_INVALID_OPERAND);
4781 }
4782
4783 if (arg1 == arg2) {
4784#ifdef DEBUG_EXPR
4785 xmlGenericError(xmlGenericErrorContext,
4786 "Equal: by pointer\n");
4787#endif
4788 return(1);
4789 }
4790
4791 /*
4792 *If either argument is a nodeset, it's a 'special case'
4793 */
4794 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4795 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4796 /*
4797 *Hack it to assure arg1 is the nodeset
4798 */
4799 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4800 argtmp = arg2;
4801 arg2 = arg1;
4802 arg1 = argtmp;
4803 }
4804 switch (arg2->type) {
4805 case XPATH_UNDEFINED:
4806#ifdef DEBUG_EXPR
4807 xmlGenericError(xmlGenericErrorContext,
4808 "Equal: undefined\n");
4809#endif
4810 break;
4811 case XPATH_NODESET:
4812 case XPATH_XSLT_TREE:
4813 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4814 break;
4815 case XPATH_BOOLEAN:
4816 if ((arg1->nodesetval == NULL) ||
4817 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4818 else
4819 ret = 1;
4820 ret = (ret == arg2->boolval);
4821 break;
4822 case XPATH_NUMBER:
4823 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4824 break;
4825 case XPATH_STRING:
4826 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4827 break;
4828 case XPATH_USERS:
4829 case XPATH_POINT:
4830 case XPATH_RANGE:
4831 case XPATH_LOCATIONSET:
4832 TODO
4833 break;
4834 }
4835 xmlXPathFreeObject(arg1);
4836 xmlXPathFreeObject(arg2);
4837 return(ret);
4838 }
4839
4840 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4841}
4842
4843/**
4844 * xmlXPathNotEqualValues:
4845 * @ctxt: the XPath Parser context
4846 *
4847 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4848 *
4849 * Returns 0 or 1 depending on the results of the test.
4850 */
4851int
4852xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4853 xmlXPathObjectPtr arg1, arg2, argtmp;
4854 int ret = 0;
4855
4856 arg2 = valuePop(ctxt);
4857 arg1 = valuePop(ctxt);
4858 if ((arg1 == NULL) || (arg2 == NULL)) {
4859 if (arg1 != NULL)
4860 xmlXPathFreeObject(arg1);
4861 else
4862 xmlXPathFreeObject(arg2);
4863 XP_ERROR0(XPATH_INVALID_OPERAND);
4864 }
4865
4866 if (arg1 == arg2) {
4867#ifdef DEBUG_EXPR
4868 xmlGenericError(xmlGenericErrorContext,
4869 "NotEqual: by pointer\n");
4870#endif
4871 return(0);
4872 }
4873
4874 /*
4875 *If either argument is a nodeset, it's a 'special case'
4876 */
4877 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4878 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4879 /*
4880 *Hack it to assure arg1 is the nodeset
4881 */
4882 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4883 argtmp = arg2;
4884 arg2 = arg1;
4885 arg1 = argtmp;
4886 }
4887 switch (arg2->type) {
4888 case XPATH_UNDEFINED:
4889#ifdef DEBUG_EXPR
4890 xmlGenericError(xmlGenericErrorContext,
4891 "NotEqual: undefined\n");
4892#endif
4893 break;
4894 case XPATH_NODESET:
4895 case XPATH_XSLT_TREE:
4896 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4897 break;
4898 case XPATH_BOOLEAN:
4899 if ((arg1->nodesetval == NULL) ||
4900 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4901 else
4902 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004903 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004904 break;
4905 case XPATH_NUMBER:
4906 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4907 break;
4908 case XPATH_STRING:
4909 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4910 break;
4911 case XPATH_USERS:
4912 case XPATH_POINT:
4913 case XPATH_RANGE:
4914 case XPATH_LOCATIONSET:
4915 TODO
4916 break;
4917 }
4918 xmlXPathFreeObject(arg1);
4919 xmlXPathFreeObject(arg2);
4920 return(ret);
4921 }
4922
4923 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4924}
Owen Taylor3473f882001-02-23 17:55:21 +00004925
4926/**
4927 * xmlXPathCompareValues:
4928 * @ctxt: the XPath Parser context
4929 * @inf: less than (1) or greater than (0)
4930 * @strict: is the comparison strict
4931 *
4932 * Implement the compare operation on XPath objects:
4933 * @arg1 < @arg2 (1, 1, ...
4934 * @arg1 <= @arg2 (1, 0, ...
4935 * @arg1 > @arg2 (0, 1, ...
4936 * @arg1 >= @arg2 (0, 0, ...
4937 *
4938 * When neither object to be compared is a node-set and the operator is
4939 * <=, <, >=, >, then the objects are compared by converted both objects
4940 * to numbers and comparing the numbers according to IEEE 754. The <
4941 * comparison will be true if and only if the first number is less than the
4942 * second number. The <= comparison will be true if and only if the first
4943 * number is less than or equal to the second number. The > comparison
4944 * will be true if and only if the first number is greater than the second
4945 * number. The >= comparison will be true if and only if the first number
4946 * is greater than or equal to the second number.
4947 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004948 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004949 */
4950int
4951xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004952 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004953 xmlXPathObjectPtr arg1, arg2;
4954
William M. Brack0c022ad2002-07-12 00:56:01 +00004955 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004956 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004957 if ((arg1 == NULL) || (arg2 == NULL)) {
4958 if (arg1 != NULL)
4959 xmlXPathFreeObject(arg1);
4960 else
4961 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004962 XP_ERROR0(XPATH_INVALID_OPERAND);
4963 }
4964
William M. Brack0c022ad2002-07-12 00:56:01 +00004965 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4966 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4967 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4968 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004969 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004970 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004971 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004972 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4973 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004974 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004975 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4976 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004977 }
4978 }
4979 return(ret);
4980 }
4981
4982 if (arg1->type != XPATH_NUMBER) {
4983 valuePush(ctxt, arg1);
4984 xmlXPathNumberFunction(ctxt, 1);
4985 arg1 = valuePop(ctxt);
4986 }
4987 if (arg1->type != XPATH_NUMBER) {
4988 xmlXPathFreeObject(arg1);
4989 xmlXPathFreeObject(arg2);
4990 XP_ERROR0(XPATH_INVALID_OPERAND);
4991 }
4992 if (arg2->type != XPATH_NUMBER) {
4993 valuePush(ctxt, arg2);
4994 xmlXPathNumberFunction(ctxt, 1);
4995 arg2 = valuePop(ctxt);
4996 }
4997 if (arg2->type != XPATH_NUMBER) {
4998 xmlXPathFreeObject(arg1);
4999 xmlXPathFreeObject(arg2);
5000 XP_ERROR0(XPATH_INVALID_OPERAND);
5001 }
5002 /*
5003 * Add tests for infinity and nan
5004 * => feedback on 3.4 for Inf and NaN
5005 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005006 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005007 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005008 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005009 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005010 arg1i=xmlXPathIsInf(arg1->floatval);
5011 arg2i=xmlXPathIsInf(arg2->floatval);
5012 if (inf && strict) {
5013 if ((arg1i == -1 && arg2i != -1) ||
5014 (arg2i == 1 && arg1i != 1)) {
5015 ret = 1;
5016 } else if (arg1i == 0 && arg2i == 0) {
5017 ret = (arg1->floatval < arg2->floatval);
5018 } else {
5019 ret = 0;
5020 }
5021 }
5022 else if (inf && !strict) {
5023 if (arg1i == -1 || arg2i == 1) {
5024 ret = 1;
5025 } else if (arg1i == 0 && arg2i == 0) {
5026 ret = (arg1->floatval <= arg2->floatval);
5027 } else {
5028 ret = 0;
5029 }
5030 }
5031 else if (!inf && strict) {
5032 if ((arg1i == 1 && arg2i != 1) ||
5033 (arg2i == -1 && arg1i != -1)) {
5034 ret = 1;
5035 } else if (arg1i == 0 && arg2i == 0) {
5036 ret = (arg1->floatval > arg2->floatval);
5037 } else {
5038 ret = 0;
5039 }
5040 }
5041 else if (!inf && !strict) {
5042 if (arg1i == 1 || arg2i == -1) {
5043 ret = 1;
5044 } else if (arg1i == 0 && arg2i == 0) {
5045 ret = (arg1->floatval >= arg2->floatval);
5046 } else {
5047 ret = 0;
5048 }
5049 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005050 }
Owen Taylor3473f882001-02-23 17:55:21 +00005051 xmlXPathFreeObject(arg1);
5052 xmlXPathFreeObject(arg2);
5053 return(ret);
5054}
5055
5056/**
5057 * xmlXPathValueFlipSign:
5058 * @ctxt: the XPath Parser context
5059 *
5060 * Implement the unary - operation on an XPath object
5061 * The numeric operators convert their operands to numbers as if
5062 * by calling the number function.
5063 */
5064void
5065xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005066 CAST_TO_NUMBER;
5067 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005068 if (xmlXPathIsNaN(ctxt->value->floatval))
5069 ctxt->value->floatval=xmlXPathNAN;
5070 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5071 ctxt->value->floatval=xmlXPathNINF;
5072 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5073 ctxt->value->floatval=xmlXPathPINF;
5074 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005075 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5076 ctxt->value->floatval = xmlXPathNZERO;
5077 else
5078 ctxt->value->floatval = 0;
5079 }
5080 else
5081 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005082}
5083
5084/**
5085 * xmlXPathAddValues:
5086 * @ctxt: the XPath Parser context
5087 *
5088 * Implement the add operation on XPath objects:
5089 * The numeric operators convert their operands to numbers as if
5090 * by calling the number function.
5091 */
5092void
5093xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5094 xmlXPathObjectPtr arg;
5095 double val;
5096
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005097 arg = valuePop(ctxt);
5098 if (arg == NULL)
5099 XP_ERROR(XPATH_INVALID_OPERAND);
5100 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005101 xmlXPathFreeObject(arg);
5102
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005103 CAST_TO_NUMBER;
5104 CHECK_TYPE(XPATH_NUMBER);
5105 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005106}
5107
5108/**
5109 * xmlXPathSubValues:
5110 * @ctxt: the XPath Parser context
5111 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005112 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005113 * The numeric operators convert their operands to numbers as if
5114 * by calling the number function.
5115 */
5116void
5117xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5118 xmlXPathObjectPtr arg;
5119 double val;
5120
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005121 arg = valuePop(ctxt);
5122 if (arg == NULL)
5123 XP_ERROR(XPATH_INVALID_OPERAND);
5124 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005125 xmlXPathFreeObject(arg);
5126
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005127 CAST_TO_NUMBER;
5128 CHECK_TYPE(XPATH_NUMBER);
5129 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005130}
5131
5132/**
5133 * xmlXPathMultValues:
5134 * @ctxt: the XPath Parser context
5135 *
5136 * Implement the multiply operation on XPath objects:
5137 * The numeric operators convert their operands to numbers as if
5138 * by calling the number function.
5139 */
5140void
5141xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5142 xmlXPathObjectPtr arg;
5143 double val;
5144
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005145 arg = valuePop(ctxt);
5146 if (arg == NULL)
5147 XP_ERROR(XPATH_INVALID_OPERAND);
5148 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005149 xmlXPathFreeObject(arg);
5150
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005151 CAST_TO_NUMBER;
5152 CHECK_TYPE(XPATH_NUMBER);
5153 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005154}
5155
5156/**
5157 * xmlXPathDivValues:
5158 * @ctxt: the XPath Parser context
5159 *
5160 * Implement the div operation on XPath objects @arg1 / @arg2:
5161 * The numeric operators convert their operands to numbers as if
5162 * by calling the number function.
5163 */
5164void
5165xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5166 xmlXPathObjectPtr arg;
5167 double val;
5168
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005169 arg = valuePop(ctxt);
5170 if (arg == NULL)
5171 XP_ERROR(XPATH_INVALID_OPERAND);
5172 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005173 xmlXPathFreeObject(arg);
5174
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(val) || xmlXPathIsNaN(ctxt->value->floatval))
5178 ctxt->value->floatval = xmlXPathNAN;
5179 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005180 if (ctxt->value->floatval == 0)
5181 ctxt->value->floatval = xmlXPathNAN;
5182 else if (ctxt->value->floatval > 0)
5183 ctxt->value->floatval = xmlXPathNINF;
5184 else if (ctxt->value->floatval < 0)
5185 ctxt->value->floatval = xmlXPathPINF;
5186 }
5187 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005188 if (ctxt->value->floatval == 0)
5189 ctxt->value->floatval = xmlXPathNAN;
5190 else if (ctxt->value->floatval > 0)
5191 ctxt->value->floatval = xmlXPathPINF;
5192 else if (ctxt->value->floatval < 0)
5193 ctxt->value->floatval = xmlXPathNINF;
5194 } else
5195 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005196}
5197
5198/**
5199 * xmlXPathModValues:
5200 * @ctxt: the XPath Parser context
5201 *
5202 * Implement the mod operation on XPath objects: @arg1 / @arg2
5203 * The numeric operators convert their operands to numbers as if
5204 * by calling the number function.
5205 */
5206void
5207xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5208 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005209 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005210
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005211 arg = valuePop(ctxt);
5212 if (arg == NULL)
5213 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005214 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005215 xmlXPathFreeObject(arg);
5216
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005217 CAST_TO_NUMBER;
5218 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005219 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005220 if (arg2 == 0)
5221 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005222 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005223 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005224 }
Owen Taylor3473f882001-02-23 17:55:21 +00005225}
5226
5227/************************************************************************
5228 * *
5229 * The traversal functions *
5230 * *
5231 ************************************************************************/
5232
Owen Taylor3473f882001-02-23 17:55:21 +00005233/*
5234 * A traversal function enumerates nodes along an axis.
5235 * Initially it must be called with NULL, and it indicates
5236 * termination on the axis by returning NULL.
5237 */
5238typedef xmlNodePtr (*xmlXPathTraversalFunction)
5239 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5240
5241/**
5242 * xmlXPathNextSelf:
5243 * @ctxt: the XPath Parser context
5244 * @cur: the current node in the traversal
5245 *
5246 * Traversal function for the "self" direction
5247 * The self axis contains just the context node itself
5248 *
5249 * Returns the next element following that axis
5250 */
5251xmlNodePtr
5252xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5253 if (cur == NULL)
5254 return(ctxt->context->node);
5255 return(NULL);
5256}
5257
5258/**
5259 * xmlXPathNextChild:
5260 * @ctxt: the XPath Parser context
5261 * @cur: the current node in the traversal
5262 *
5263 * Traversal function for the "child" direction
5264 * The child axis contains the children of the context node in document order.
5265 *
5266 * Returns the next element following that axis
5267 */
5268xmlNodePtr
5269xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5270 if (cur == NULL) {
5271 if (ctxt->context->node == NULL) return(NULL);
5272 switch (ctxt->context->node->type) {
5273 case XML_ELEMENT_NODE:
5274 case XML_TEXT_NODE:
5275 case XML_CDATA_SECTION_NODE:
5276 case XML_ENTITY_REF_NODE:
5277 case XML_ENTITY_NODE:
5278 case XML_PI_NODE:
5279 case XML_COMMENT_NODE:
5280 case XML_NOTATION_NODE:
5281 case XML_DTD_NODE:
5282 return(ctxt->context->node->children);
5283 case XML_DOCUMENT_NODE:
5284 case XML_DOCUMENT_TYPE_NODE:
5285 case XML_DOCUMENT_FRAG_NODE:
5286 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005287#ifdef LIBXML_DOCB_ENABLED
5288 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005289#endif
5290 return(((xmlDocPtr) ctxt->context->node)->children);
5291 case XML_ELEMENT_DECL:
5292 case XML_ATTRIBUTE_DECL:
5293 case XML_ENTITY_DECL:
5294 case XML_ATTRIBUTE_NODE:
5295 case XML_NAMESPACE_DECL:
5296 case XML_XINCLUDE_START:
5297 case XML_XINCLUDE_END:
5298 return(NULL);
5299 }
5300 return(NULL);
5301 }
5302 if ((cur->type == XML_DOCUMENT_NODE) ||
5303 (cur->type == XML_HTML_DOCUMENT_NODE))
5304 return(NULL);
5305 return(cur->next);
5306}
5307
5308/**
5309 * xmlXPathNextDescendant:
5310 * @ctxt: the XPath Parser context
5311 * @cur: the current node in the traversal
5312 *
5313 * Traversal function for the "descendant" direction
5314 * the descendant axis contains the descendants of the context node in document
5315 * order; a descendant is a child or a child of a child and so on.
5316 *
5317 * Returns the next element following that axis
5318 */
5319xmlNodePtr
5320xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5321 if (cur == NULL) {
5322 if (ctxt->context->node == NULL)
5323 return(NULL);
5324 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5325 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5326 return(NULL);
5327
5328 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5329 return(ctxt->context->doc->children);
5330 return(ctxt->context->node->children);
5331 }
5332
Daniel Veillard567e1b42001-08-01 15:53:47 +00005333 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005334 /*
5335 * Do not descend on entities declarations
5336 */
5337 if (cur->children->type != XML_ENTITY_DECL) {
5338 cur = cur->children;
5339 /*
5340 * Skip DTDs
5341 */
5342 if (cur->type != XML_DTD_NODE)
5343 return(cur);
5344 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005345 }
5346
5347 if (cur == ctxt->context->node) return(NULL);
5348
Daniel Veillard68e9e742002-11-16 15:35:11 +00005349 while (cur->next != NULL) {
5350 cur = cur->next;
5351 if ((cur->type != XML_ENTITY_DECL) &&
5352 (cur->type != XML_DTD_NODE))
5353 return(cur);
5354 }
Owen Taylor3473f882001-02-23 17:55:21 +00005355
5356 do {
5357 cur = cur->parent;
5358 if (cur == NULL) return(NULL);
5359 if (cur == ctxt->context->node) return(NULL);
5360 if (cur->next != NULL) {
5361 cur = cur->next;
5362 return(cur);
5363 }
5364 } while (cur != NULL);
5365 return(cur);
5366}
5367
5368/**
5369 * xmlXPathNextDescendantOrSelf:
5370 * @ctxt: the XPath Parser context
5371 * @cur: the current node in the traversal
5372 *
5373 * Traversal function for the "descendant-or-self" direction
5374 * the descendant-or-self axis contains the context node and the descendants
5375 * of the context node in document order; thus the context node is the first
5376 * node on the axis, and the first child of the context node is the second node
5377 * on the axis
5378 *
5379 * Returns the next element following that axis
5380 */
5381xmlNodePtr
5382xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5383 if (cur == NULL) {
5384 if (ctxt->context->node == NULL)
5385 return(NULL);
5386 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5387 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5388 return(NULL);
5389 return(ctxt->context->node);
5390 }
5391
5392 return(xmlXPathNextDescendant(ctxt, cur));
5393}
5394
5395/**
5396 * xmlXPathNextParent:
5397 * @ctxt: the XPath Parser context
5398 * @cur: the current node in the traversal
5399 *
5400 * Traversal function for the "parent" direction
5401 * The parent axis contains the parent of the context node, if there is one.
5402 *
5403 * Returns the next element following that axis
5404 */
5405xmlNodePtr
5406xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5407 /*
5408 * the parent of an attribute or namespace node is the element
5409 * to which the attribute or namespace node is attached
5410 * Namespace handling !!!
5411 */
5412 if (cur == NULL) {
5413 if (ctxt->context->node == NULL) return(NULL);
5414 switch (ctxt->context->node->type) {
5415 case XML_ELEMENT_NODE:
5416 case XML_TEXT_NODE:
5417 case XML_CDATA_SECTION_NODE:
5418 case XML_ENTITY_REF_NODE:
5419 case XML_ENTITY_NODE:
5420 case XML_PI_NODE:
5421 case XML_COMMENT_NODE:
5422 case XML_NOTATION_NODE:
5423 case XML_DTD_NODE:
5424 case XML_ELEMENT_DECL:
5425 case XML_ATTRIBUTE_DECL:
5426 case XML_XINCLUDE_START:
5427 case XML_XINCLUDE_END:
5428 case XML_ENTITY_DECL:
5429 if (ctxt->context->node->parent == NULL)
5430 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005431 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005432 ((ctxt->context->node->parent->name[0] == ' ') ||
5433 (xmlStrEqual(ctxt->context->node->parent->name,
5434 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005435 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005436 return(ctxt->context->node->parent);
5437 case XML_ATTRIBUTE_NODE: {
5438 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5439
5440 return(att->parent);
5441 }
5442 case XML_DOCUMENT_NODE:
5443 case XML_DOCUMENT_TYPE_NODE:
5444 case XML_DOCUMENT_FRAG_NODE:
5445 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005446#ifdef LIBXML_DOCB_ENABLED
5447 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005448#endif
5449 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005450 case XML_NAMESPACE_DECL: {
5451 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5452
5453 if ((ns->next != NULL) &&
5454 (ns->next->type != XML_NAMESPACE_DECL))
5455 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005456 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005457 }
Owen Taylor3473f882001-02-23 17:55:21 +00005458 }
5459 }
5460 return(NULL);
5461}
5462
5463/**
5464 * xmlXPathNextAncestor:
5465 * @ctxt: the XPath Parser context
5466 * @cur: the current node in the traversal
5467 *
5468 * Traversal function for the "ancestor" direction
5469 * the ancestor axis contains the ancestors of the context node; the ancestors
5470 * of the context node consist of the parent of context node and the parent's
5471 * parent and so on; the nodes are ordered in reverse document order; thus the
5472 * parent is the first node on the axis, and the parent's parent is the second
5473 * node on the axis
5474 *
5475 * Returns the next element following that axis
5476 */
5477xmlNodePtr
5478xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5479 /*
5480 * the parent of an attribute or namespace node is the element
5481 * to which the attribute or namespace node is attached
5482 * !!!!!!!!!!!!!
5483 */
5484 if (cur == NULL) {
5485 if (ctxt->context->node == NULL) return(NULL);
5486 switch (ctxt->context->node->type) {
5487 case XML_ELEMENT_NODE:
5488 case XML_TEXT_NODE:
5489 case XML_CDATA_SECTION_NODE:
5490 case XML_ENTITY_REF_NODE:
5491 case XML_ENTITY_NODE:
5492 case XML_PI_NODE:
5493 case XML_COMMENT_NODE:
5494 case XML_DTD_NODE:
5495 case XML_ELEMENT_DECL:
5496 case XML_ATTRIBUTE_DECL:
5497 case XML_ENTITY_DECL:
5498 case XML_NOTATION_NODE:
5499 case XML_XINCLUDE_START:
5500 case XML_XINCLUDE_END:
5501 if (ctxt->context->node->parent == NULL)
5502 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005503 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005504 ((ctxt->context->node->parent->name[0] == ' ') ||
5505 (xmlStrEqual(ctxt->context->node->parent->name,
5506 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005507 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005508 return(ctxt->context->node->parent);
5509 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005510 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005511
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005512 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005513 }
5514 case XML_DOCUMENT_NODE:
5515 case XML_DOCUMENT_TYPE_NODE:
5516 case XML_DOCUMENT_FRAG_NODE:
5517 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005518#ifdef LIBXML_DOCB_ENABLED
5519 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005520#endif
5521 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005522 case XML_NAMESPACE_DECL: {
5523 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5524
5525 if ((ns->next != NULL) &&
5526 (ns->next->type != XML_NAMESPACE_DECL))
5527 return((xmlNodePtr) ns->next);
5528 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005529 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005530 }
Owen Taylor3473f882001-02-23 17:55:21 +00005531 }
5532 return(NULL);
5533 }
5534 if (cur == ctxt->context->doc->children)
5535 return((xmlNodePtr) ctxt->context->doc);
5536 if (cur == (xmlNodePtr) ctxt->context->doc)
5537 return(NULL);
5538 switch (cur->type) {
5539 case XML_ELEMENT_NODE:
5540 case XML_TEXT_NODE:
5541 case XML_CDATA_SECTION_NODE:
5542 case XML_ENTITY_REF_NODE:
5543 case XML_ENTITY_NODE:
5544 case XML_PI_NODE:
5545 case XML_COMMENT_NODE:
5546 case XML_NOTATION_NODE:
5547 case XML_DTD_NODE:
5548 case XML_ELEMENT_DECL:
5549 case XML_ATTRIBUTE_DECL:
5550 case XML_ENTITY_DECL:
5551 case XML_XINCLUDE_START:
5552 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005553 if (cur->parent == NULL)
5554 return(NULL);
5555 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005556 ((cur->parent->name[0] == ' ') ||
5557 (xmlStrEqual(cur->parent->name,
5558 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005559 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005560 return(cur->parent);
5561 case XML_ATTRIBUTE_NODE: {
5562 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5563
5564 return(att->parent);
5565 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005566 case XML_NAMESPACE_DECL: {
5567 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5568
5569 if ((ns->next != NULL) &&
5570 (ns->next->type != XML_NAMESPACE_DECL))
5571 return((xmlNodePtr) ns->next);
5572 /* Bad, how did that namespace ended-up there ? */
5573 return(NULL);
5574 }
Owen Taylor3473f882001-02-23 17:55:21 +00005575 case XML_DOCUMENT_NODE:
5576 case XML_DOCUMENT_TYPE_NODE:
5577 case XML_DOCUMENT_FRAG_NODE:
5578 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005579#ifdef LIBXML_DOCB_ENABLED
5580 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005581#endif
5582 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005583 }
5584 return(NULL);
5585}
5586
5587/**
5588 * xmlXPathNextAncestorOrSelf:
5589 * @ctxt: the XPath Parser context
5590 * @cur: the current node in the traversal
5591 *
5592 * Traversal function for the "ancestor-or-self" direction
5593 * he ancestor-or-self axis contains the context node and ancestors of
5594 * the context node in reverse document order; thus the context node is
5595 * the first node on the axis, and the context node's parent the second;
5596 * parent here is defined the same as with the parent axis.
5597 *
5598 * Returns the next element following that axis
5599 */
5600xmlNodePtr
5601xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5602 if (cur == NULL)
5603 return(ctxt->context->node);
5604 return(xmlXPathNextAncestor(ctxt, cur));
5605}
5606
5607/**
5608 * xmlXPathNextFollowingSibling:
5609 * @ctxt: the XPath Parser context
5610 * @cur: the current node in the traversal
5611 *
5612 * Traversal function for the "following-sibling" direction
5613 * The following-sibling axis contains the following siblings of the context
5614 * node in document order.
5615 *
5616 * Returns the next element following that axis
5617 */
5618xmlNodePtr
5619xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5620 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5621 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5622 return(NULL);
5623 if (cur == (xmlNodePtr) ctxt->context->doc)
5624 return(NULL);
5625 if (cur == NULL)
5626 return(ctxt->context->node->next);
5627 return(cur->next);
5628}
5629
5630/**
5631 * xmlXPathNextPrecedingSibling:
5632 * @ctxt: the XPath Parser context
5633 * @cur: the current node in the traversal
5634 *
5635 * Traversal function for the "preceding-sibling" direction
5636 * The preceding-sibling axis contains the preceding siblings of the context
5637 * node in reverse document order; the first preceding sibling is first on the
5638 * axis; the sibling preceding that node is the second on the axis and so on.
5639 *
5640 * Returns the next element following that axis
5641 */
5642xmlNodePtr
5643xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5644 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5645 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5646 return(NULL);
5647 if (cur == (xmlNodePtr) ctxt->context->doc)
5648 return(NULL);
5649 if (cur == NULL)
5650 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005651 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5652 cur = cur->prev;
5653 if (cur == NULL)
5654 return(ctxt->context->node->prev);
5655 }
Owen Taylor3473f882001-02-23 17:55:21 +00005656 return(cur->prev);
5657}
5658
5659/**
5660 * xmlXPathNextFollowing:
5661 * @ctxt: the XPath Parser context
5662 * @cur: the current node in the traversal
5663 *
5664 * Traversal function for the "following" direction
5665 * The following axis contains all nodes in the same document as the context
5666 * node that are after the context node in document order, excluding any
5667 * descendants and excluding attribute nodes and namespace nodes; the nodes
5668 * are ordered in document order
5669 *
5670 * Returns the next element following that axis
5671 */
5672xmlNodePtr
5673xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5674 if (cur != NULL && cur->children != NULL)
5675 return cur->children ;
5676 if (cur == NULL) cur = ctxt->context->node;
5677 if (cur == NULL) return(NULL) ; /* ERROR */
5678 if (cur->next != NULL) return(cur->next) ;
5679 do {
5680 cur = cur->parent;
5681 if (cur == NULL) return(NULL);
5682 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5683 if (cur->next != NULL) return(cur->next);
5684 } while (cur != NULL);
5685 return(cur);
5686}
5687
5688/*
5689 * xmlXPathIsAncestor:
5690 * @ancestor: the ancestor node
5691 * @node: the current node
5692 *
5693 * Check that @ancestor is a @node's ancestor
5694 *
5695 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5696 */
5697static int
5698xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5699 if ((ancestor == NULL) || (node == NULL)) return(0);
5700 /* nodes need to be in the same document */
5701 if (ancestor->doc != node->doc) return(0);
5702 /* avoid searching if ancestor or node is the root node */
5703 if (ancestor == (xmlNodePtr) node->doc) return(1);
5704 if (node == (xmlNodePtr) ancestor->doc) return(0);
5705 while (node->parent != NULL) {
5706 if (node->parent == ancestor)
5707 return(1);
5708 node = node->parent;
5709 }
5710 return(0);
5711}
5712
5713/**
5714 * xmlXPathNextPreceding:
5715 * @ctxt: the XPath Parser context
5716 * @cur: the current node in the traversal
5717 *
5718 * Traversal function for the "preceding" direction
5719 * the preceding axis contains all nodes in the same document as the context
5720 * node that are before the context node in document order, excluding any
5721 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5722 * ordered in reverse document order
5723 *
5724 * Returns the next element following that axis
5725 */
5726xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005727xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5728{
Owen Taylor3473f882001-02-23 17:55:21 +00005729 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005730 cur = ctxt->context->node;
5731 if (cur == NULL)
5732 return (NULL);
5733 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5734 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005735 do {
5736 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005737 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5738 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005739 }
5740
5741 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005742 if (cur == NULL)
5743 return (NULL);
5744 if (cur == ctxt->context->doc->children)
5745 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005746 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005747 return (cur);
5748}
5749
5750/**
5751 * xmlXPathNextPrecedingInternal:
5752 * @ctxt: the XPath Parser context
5753 * @cur: the current node in the traversal
5754 *
5755 * Traversal function for the "preceding" direction
5756 * the preceding axis contains all nodes in the same document as the context
5757 * node that are before the context node in document order, excluding any
5758 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5759 * ordered in reverse document order
5760 * This is a faster implementation but internal only since it requires a
5761 * state kept in the parser context: ctxt->ancestor.
5762 *
5763 * Returns the next element following that axis
5764 */
5765static xmlNodePtr
5766xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5767 xmlNodePtr cur)
5768{
5769 if (cur == NULL) {
5770 cur = ctxt->context->node;
5771 if (cur == NULL)
5772 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005773 if (cur->type == XML_NAMESPACE_DECL)
5774 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005775 ctxt->ancestor = cur->parent;
5776 }
5777 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5778 cur = cur->prev;
5779 while (cur->prev == NULL) {
5780 cur = cur->parent;
5781 if (cur == NULL)
5782 return (NULL);
5783 if (cur == ctxt->context->doc->children)
5784 return (NULL);
5785 if (cur != ctxt->ancestor)
5786 return (cur);
5787 ctxt->ancestor = cur->parent;
5788 }
5789 cur = cur->prev;
5790 while (cur->last != NULL)
5791 cur = cur->last;
5792 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005793}
5794
5795/**
5796 * xmlXPathNextNamespace:
5797 * @ctxt: the XPath Parser context
5798 * @cur: the current attribute in the traversal
5799 *
5800 * Traversal function for the "namespace" direction
5801 * the namespace axis contains the namespace nodes of the context node;
5802 * the order of nodes on this axis is implementation-defined; the axis will
5803 * be empty unless the context node is an element
5804 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005805 * We keep the XML namespace node at the end of the list.
5806 *
Owen Taylor3473f882001-02-23 17:55:21 +00005807 * Returns the next element following that axis
5808 */
5809xmlNodePtr
5810xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5811 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005812 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005813 if (ctxt->context->tmpNsList != NULL)
5814 xmlFree(ctxt->context->tmpNsList);
5815 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005816 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005817 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005818 if (ctxt->context->tmpNsList != NULL) {
5819 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5820 ctxt->context->tmpNsNr++;
5821 }
5822 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005823 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005824 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005825 if (ctxt->context->tmpNsNr > 0) {
5826 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5827 } else {
5828 if (ctxt->context->tmpNsList != NULL)
5829 xmlFree(ctxt->context->tmpNsList);
5830 ctxt->context->tmpNsList = NULL;
5831 return(NULL);
5832 }
Owen Taylor3473f882001-02-23 17:55:21 +00005833}
5834
5835/**
5836 * xmlXPathNextAttribute:
5837 * @ctxt: the XPath Parser context
5838 * @cur: the current attribute in the traversal
5839 *
5840 * Traversal function for the "attribute" direction
5841 * TODO: support DTD inherited default attributes
5842 *
5843 * Returns the next element following that axis
5844 */
5845xmlNodePtr
5846xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005847 if (ctxt->context->node == NULL)
5848 return(NULL);
5849 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5850 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005851 if (cur == NULL) {
5852 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5853 return(NULL);
5854 return((xmlNodePtr)ctxt->context->node->properties);
5855 }
5856 return((xmlNodePtr)cur->next);
5857}
5858
5859/************************************************************************
5860 * *
5861 * NodeTest Functions *
5862 * *
5863 ************************************************************************/
5864
Owen Taylor3473f882001-02-23 17:55:21 +00005865#define IS_FUNCTION 200
5866
Owen Taylor3473f882001-02-23 17:55:21 +00005867
5868/************************************************************************
5869 * *
5870 * Implicit tree core function library *
5871 * *
5872 ************************************************************************/
5873
5874/**
5875 * xmlXPathRoot:
5876 * @ctxt: the XPath Parser context
5877 *
5878 * Initialize the context to the root of the document
5879 */
5880void
5881xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5882 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5883 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5884}
5885
5886/************************************************************************
5887 * *
5888 * The explicit core function library *
5889 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5890 * *
5891 ************************************************************************/
5892
5893
5894/**
5895 * xmlXPathLastFunction:
5896 * @ctxt: the XPath Parser context
5897 * @nargs: the number of arguments
5898 *
5899 * Implement the last() XPath function
5900 * number last()
5901 * The last function returns the number of nodes in the context node list.
5902 */
5903void
5904xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5905 CHECK_ARITY(0);
5906 if (ctxt->context->contextSize >= 0) {
5907 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5908#ifdef DEBUG_EXPR
5909 xmlGenericError(xmlGenericErrorContext,
5910 "last() : %d\n", ctxt->context->contextSize);
5911#endif
5912 } else {
5913 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5914 }
5915}
5916
5917/**
5918 * xmlXPathPositionFunction:
5919 * @ctxt: the XPath Parser context
5920 * @nargs: the number of arguments
5921 *
5922 * Implement the position() XPath function
5923 * number position()
5924 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005925 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005926 * will be equal to last().
5927 */
5928void
5929xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5930 CHECK_ARITY(0);
5931 if (ctxt->context->proximityPosition >= 0) {
5932 valuePush(ctxt,
5933 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5934#ifdef DEBUG_EXPR
5935 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5936 ctxt->context->proximityPosition);
5937#endif
5938 } else {
5939 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5940 }
5941}
5942
5943/**
5944 * xmlXPathCountFunction:
5945 * @ctxt: the XPath Parser context
5946 * @nargs: the number of arguments
5947 *
5948 * Implement the count() XPath function
5949 * number count(node-set)
5950 */
5951void
5952xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5953 xmlXPathObjectPtr cur;
5954
5955 CHECK_ARITY(1);
5956 if ((ctxt->value == NULL) ||
5957 ((ctxt->value->type != XPATH_NODESET) &&
5958 (ctxt->value->type != XPATH_XSLT_TREE)))
5959 XP_ERROR(XPATH_INVALID_TYPE);
5960 cur = valuePop(ctxt);
5961
Daniel Veillard911f49a2001-04-07 15:39:35 +00005962 if ((cur == NULL) || (cur->nodesetval == NULL))
5963 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005964 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005965 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005966 } else {
5967 if ((cur->nodesetval->nodeNr != 1) ||
5968 (cur->nodesetval->nodeTab == NULL)) {
5969 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5970 } else {
5971 xmlNodePtr tmp;
5972 int i = 0;
5973
5974 tmp = cur->nodesetval->nodeTab[0];
5975 if (tmp != NULL) {
5976 tmp = tmp->children;
5977 while (tmp != NULL) {
5978 tmp = tmp->next;
5979 i++;
5980 }
5981 }
5982 valuePush(ctxt, xmlXPathNewFloat((double) i));
5983 }
5984 }
Owen Taylor3473f882001-02-23 17:55:21 +00005985 xmlXPathFreeObject(cur);
5986}
5987
5988/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005989 * xmlXPathGetElementsByIds:
5990 * @doc: the document
5991 * @ids: a whitespace separated list of IDs
5992 *
5993 * Selects elements by their unique ID.
5994 *
5995 * Returns a node-set of selected elements.
5996 */
5997static xmlNodeSetPtr
5998xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5999 xmlNodeSetPtr ret;
6000 const xmlChar *cur = ids;
6001 xmlChar *ID;
6002 xmlAttrPtr attr;
6003 xmlNodePtr elem = NULL;
6004
Daniel Veillard7a985a12003-07-06 17:57:42 +00006005 if (ids == NULL) return(NULL);
6006
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006007 ret = xmlXPathNodeSetCreate(NULL);
6008
William M. Brack76e95df2003-10-18 16:20:14 +00006009 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006010 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006011 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006012 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006013
6014 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006015 if (ID != NULL) {
6016 if (xmlValidateNCName(ID, 1) == 0) {
6017 attr = xmlGetID(doc, ID);
6018 if (attr != NULL) {
6019 if (attr->type == XML_ATTRIBUTE_NODE)
6020 elem = attr->parent;
6021 else if (attr->type == XML_ELEMENT_NODE)
6022 elem = (xmlNodePtr) attr;
6023 else
6024 elem = NULL;
6025 if (elem != NULL)
6026 xmlXPathNodeSetAdd(ret, elem);
6027 }
6028 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006029 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006030 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006031
William M. Brack76e95df2003-10-18 16:20:14 +00006032 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006033 ids = cur;
6034 }
6035 return(ret);
6036}
6037
6038/**
Owen Taylor3473f882001-02-23 17:55:21 +00006039 * xmlXPathIdFunction:
6040 * @ctxt: the XPath Parser context
6041 * @nargs: the number of arguments
6042 *
6043 * Implement the id() XPath function
6044 * node-set id(object)
6045 * The id function selects elements by their unique ID
6046 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6047 * then the result is the union of the result of applying id to the
6048 * string value of each of the nodes in the argument node-set. When the
6049 * argument to id is of any other type, the argument is converted to a
6050 * string as if by a call to the string function; the string is split
6051 * into a whitespace-separated list of tokens (whitespace is any sequence
6052 * of characters matching the production S); the result is a node-set
6053 * containing the elements in the same document as the context node that
6054 * have a unique ID equal to any of the tokens in the list.
6055 */
6056void
6057xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006058 xmlChar *tokens;
6059 xmlNodeSetPtr ret;
6060 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006061
6062 CHECK_ARITY(1);
6063 obj = valuePop(ctxt);
6064 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006065 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006066 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006067 int i;
6068
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006069 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006070
Daniel Veillard911f49a2001-04-07 15:39:35 +00006071 if (obj->nodesetval != NULL) {
6072 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006073 tokens =
6074 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6075 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6076 ret = xmlXPathNodeSetMerge(ret, ns);
6077 xmlXPathFreeNodeSet(ns);
6078 if (tokens != NULL)
6079 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006080 }
Owen Taylor3473f882001-02-23 17:55:21 +00006081 }
6082
6083 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006084 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006085 return;
6086 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006087 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006088
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006089 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6090 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006091
Owen Taylor3473f882001-02-23 17:55:21 +00006092 xmlXPathFreeObject(obj);
6093 return;
6094}
6095
6096/**
6097 * xmlXPathLocalNameFunction:
6098 * @ctxt: the XPath Parser context
6099 * @nargs: the number of arguments
6100 *
6101 * Implement the local-name() XPath function
6102 * string local-name(node-set?)
6103 * The local-name function returns a string containing the local part
6104 * of the name of the node in the argument node-set that is first in
6105 * document order. If the node-set is empty or the first node has no
6106 * name, an empty string is returned. If the argument is omitted it
6107 * defaults to the context node.
6108 */
6109void
6110xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6111 xmlXPathObjectPtr cur;
6112
6113 if (nargs == 0) {
6114 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6115 nargs = 1;
6116 }
6117
6118 CHECK_ARITY(1);
6119 if ((ctxt->value == NULL) ||
6120 ((ctxt->value->type != XPATH_NODESET) &&
6121 (ctxt->value->type != XPATH_XSLT_TREE)))
6122 XP_ERROR(XPATH_INVALID_TYPE);
6123 cur = valuePop(ctxt);
6124
Daniel Veillard911f49a2001-04-07 15:39:35 +00006125 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006126 valuePush(ctxt, xmlXPathNewCString(""));
6127 } else {
6128 int i = 0; /* Should be first in document order !!!!! */
6129 switch (cur->nodesetval->nodeTab[i]->type) {
6130 case XML_ELEMENT_NODE:
6131 case XML_ATTRIBUTE_NODE:
6132 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006133 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6134 valuePush(ctxt, xmlXPathNewCString(""));
6135 else
6136 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006137 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6138 break;
6139 case XML_NAMESPACE_DECL:
6140 valuePush(ctxt, xmlXPathNewString(
6141 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6142 break;
6143 default:
6144 valuePush(ctxt, xmlXPathNewCString(""));
6145 }
6146 }
6147 xmlXPathFreeObject(cur);
6148}
6149
6150/**
6151 * xmlXPathNamespaceURIFunction:
6152 * @ctxt: the XPath Parser context
6153 * @nargs: the number of arguments
6154 *
6155 * Implement the namespace-uri() XPath function
6156 * string namespace-uri(node-set?)
6157 * The namespace-uri function returns a string containing the
6158 * namespace URI of the expanded name of the node in the argument
6159 * node-set that is first in document order. If the node-set is empty,
6160 * the first node has no name, or the expanded name has no namespace
6161 * URI, an empty string is returned. If the argument is omitted it
6162 * defaults to the context node.
6163 */
6164void
6165xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6166 xmlXPathObjectPtr cur;
6167
6168 if (nargs == 0) {
6169 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6170 nargs = 1;
6171 }
6172 CHECK_ARITY(1);
6173 if ((ctxt->value == NULL) ||
6174 ((ctxt->value->type != XPATH_NODESET) &&
6175 (ctxt->value->type != XPATH_XSLT_TREE)))
6176 XP_ERROR(XPATH_INVALID_TYPE);
6177 cur = valuePop(ctxt);
6178
Daniel Veillard911f49a2001-04-07 15:39:35 +00006179 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006180 valuePush(ctxt, xmlXPathNewCString(""));
6181 } else {
6182 int i = 0; /* Should be first in document order !!!!! */
6183 switch (cur->nodesetval->nodeTab[i]->type) {
6184 case XML_ELEMENT_NODE:
6185 case XML_ATTRIBUTE_NODE:
6186 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6187 valuePush(ctxt, xmlXPathNewCString(""));
6188 else
6189 valuePush(ctxt, xmlXPathNewString(
6190 cur->nodesetval->nodeTab[i]->ns->href));
6191 break;
6192 default:
6193 valuePush(ctxt, xmlXPathNewCString(""));
6194 }
6195 }
6196 xmlXPathFreeObject(cur);
6197}
6198
6199/**
6200 * xmlXPathNameFunction:
6201 * @ctxt: the XPath Parser context
6202 * @nargs: the number of arguments
6203 *
6204 * Implement the name() XPath function
6205 * string name(node-set?)
6206 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006207 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006208 * order. The QName must represent the name with respect to the namespace
6209 * declarations in effect on the node whose name is being represented.
6210 * Typically, this will be the form in which the name occurred in the XML
6211 * source. This need not be the case if there are namespace declarations
6212 * in effect on the node that associate multiple prefixes with the same
6213 * namespace. However, an implementation may include information about
6214 * the original prefix in its representation of nodes; in this case, an
6215 * implementation can ensure that the returned string is always the same
6216 * as the QName used in the XML source. If the argument it omitted it
6217 * defaults to the context node.
6218 * Libxml keep the original prefix so the "real qualified name" used is
6219 * returned.
6220 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006221static void
Daniel Veillard04383752001-07-08 14:27:15 +00006222xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6223{
Owen Taylor3473f882001-02-23 17:55:21 +00006224 xmlXPathObjectPtr cur;
6225
6226 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006227 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6228 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006229 }
6230
6231 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006232 if ((ctxt->value == NULL) ||
6233 ((ctxt->value->type != XPATH_NODESET) &&
6234 (ctxt->value->type != XPATH_XSLT_TREE)))
6235 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006236 cur = valuePop(ctxt);
6237
Daniel Veillard911f49a2001-04-07 15:39:35 +00006238 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006239 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006240 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006241 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006242
Daniel Veillard04383752001-07-08 14:27:15 +00006243 switch (cur->nodesetval->nodeTab[i]->type) {
6244 case XML_ELEMENT_NODE:
6245 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006246 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6247 valuePush(ctxt, xmlXPathNewCString(""));
6248 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6249 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006250 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006251 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006252
Daniel Veillard652d8a92003-02-04 19:28:49 +00006253 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006254 xmlChar *fullname;
6255
6256 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6257 cur->nodesetval->nodeTab[i]->ns->prefix,
6258 NULL, 0);
6259 if (fullname == cur->nodesetval->nodeTab[i]->name)
6260 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6261 if (fullname == NULL) {
6262 XP_ERROR(XPATH_MEMORY_ERROR);
6263 }
6264 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006265 }
6266 break;
6267 default:
6268 valuePush(ctxt,
6269 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6270 xmlXPathLocalNameFunction(ctxt, 1);
6271 }
Owen Taylor3473f882001-02-23 17:55:21 +00006272 }
6273 xmlXPathFreeObject(cur);
6274}
6275
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006276
6277/**
Owen Taylor3473f882001-02-23 17:55:21 +00006278 * xmlXPathStringFunction:
6279 * @ctxt: the XPath Parser context
6280 * @nargs: the number of arguments
6281 *
6282 * Implement the string() XPath function
6283 * string string(object?)
6284 * he string function converts an object to a string as follows:
6285 * - A node-set is converted to a string by returning the value of
6286 * the node in the node-set that is first in document order.
6287 * If the node-set is empty, an empty string is returned.
6288 * - A number is converted to a string as follows
6289 * + NaN is converted to the string NaN
6290 * + positive zero is converted to the string 0
6291 * + negative zero is converted to the string 0
6292 * + positive infinity is converted to the string Infinity
6293 * + negative infinity is converted to the string -Infinity
6294 * + if the number is an integer, the number is represented in
6295 * decimal form as a Number with no decimal point and no leading
6296 * zeros, preceded by a minus sign (-) if the number is negative
6297 * + otherwise, the number is represented in decimal form as a
6298 * Number including a decimal point with at least one digit
6299 * before the decimal point and at least one digit after the
6300 * decimal point, preceded by a minus sign (-) if the number
6301 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006302 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006303 * before the decimal point; beyond the one required digit
6304 * after the decimal point there must be as many, but only as
6305 * many, more digits as are needed to uniquely distinguish the
6306 * number from all other IEEE 754 numeric values.
6307 * - The boolean false value is converted to the string false.
6308 * The boolean true value is converted to the string true.
6309 *
6310 * If the argument is omitted, it defaults to a node-set with the
6311 * context node as its only member.
6312 */
6313void
6314xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6315 xmlXPathObjectPtr cur;
6316
6317 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006318 valuePush(ctxt,
6319 xmlXPathWrapString(
6320 xmlXPathCastNodeToString(ctxt->context->node)));
6321 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006322 }
6323
6324 CHECK_ARITY(1);
6325 cur = valuePop(ctxt);
6326 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006327 cur = xmlXPathConvertString(cur);
6328 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006329}
6330
6331/**
6332 * xmlXPathStringLengthFunction:
6333 * @ctxt: the XPath Parser context
6334 * @nargs: the number of arguments
6335 *
6336 * Implement the string-length() XPath function
6337 * number string-length(string?)
6338 * The string-length returns the number of characters in the string
6339 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6340 * the context node converted to a string, in other words the value
6341 * of the context node.
6342 */
6343void
6344xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6345 xmlXPathObjectPtr cur;
6346
6347 if (nargs == 0) {
6348 if (ctxt->context->node == NULL) {
6349 valuePush(ctxt, xmlXPathNewFloat(0));
6350 } else {
6351 xmlChar *content;
6352
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006353 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006354 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006355 xmlFree(content);
6356 }
6357 return;
6358 }
6359 CHECK_ARITY(1);
6360 CAST_TO_STRING;
6361 CHECK_TYPE(XPATH_STRING);
6362 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006363 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006364 xmlXPathFreeObject(cur);
6365}
6366
6367/**
6368 * xmlXPathConcatFunction:
6369 * @ctxt: the XPath Parser context
6370 * @nargs: the number of arguments
6371 *
6372 * Implement the concat() XPath function
6373 * string concat(string, string, string*)
6374 * The concat function returns the concatenation of its arguments.
6375 */
6376void
6377xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6378 xmlXPathObjectPtr cur, newobj;
6379 xmlChar *tmp;
6380
6381 if (nargs < 2) {
6382 CHECK_ARITY(2);
6383 }
6384
6385 CAST_TO_STRING;
6386 cur = valuePop(ctxt);
6387 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6388 xmlXPathFreeObject(cur);
6389 return;
6390 }
6391 nargs--;
6392
6393 while (nargs > 0) {
6394 CAST_TO_STRING;
6395 newobj = valuePop(ctxt);
6396 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6397 xmlXPathFreeObject(newobj);
6398 xmlXPathFreeObject(cur);
6399 XP_ERROR(XPATH_INVALID_TYPE);
6400 }
6401 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6402 newobj->stringval = cur->stringval;
6403 cur->stringval = tmp;
6404
6405 xmlXPathFreeObject(newobj);
6406 nargs--;
6407 }
6408 valuePush(ctxt, cur);
6409}
6410
6411/**
6412 * xmlXPathContainsFunction:
6413 * @ctxt: the XPath Parser context
6414 * @nargs: the number of arguments
6415 *
6416 * Implement the contains() XPath function
6417 * boolean contains(string, string)
6418 * The contains function returns true if the first argument string
6419 * contains the second argument string, and otherwise returns false.
6420 */
6421void
6422xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6423 xmlXPathObjectPtr hay, needle;
6424
6425 CHECK_ARITY(2);
6426 CAST_TO_STRING;
6427 CHECK_TYPE(XPATH_STRING);
6428 needle = valuePop(ctxt);
6429 CAST_TO_STRING;
6430 hay = valuePop(ctxt);
6431 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6432 xmlXPathFreeObject(hay);
6433 xmlXPathFreeObject(needle);
6434 XP_ERROR(XPATH_INVALID_TYPE);
6435 }
6436 if (xmlStrstr(hay->stringval, needle->stringval))
6437 valuePush(ctxt, xmlXPathNewBoolean(1));
6438 else
6439 valuePush(ctxt, xmlXPathNewBoolean(0));
6440 xmlXPathFreeObject(hay);
6441 xmlXPathFreeObject(needle);
6442}
6443
6444/**
6445 * xmlXPathStartsWithFunction:
6446 * @ctxt: the XPath Parser context
6447 * @nargs: the number of arguments
6448 *
6449 * Implement the starts-with() XPath function
6450 * boolean starts-with(string, string)
6451 * The starts-with function returns true if the first argument string
6452 * starts with the second argument string, and otherwise returns false.
6453 */
6454void
6455xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6456 xmlXPathObjectPtr hay, needle;
6457 int n;
6458
6459 CHECK_ARITY(2);
6460 CAST_TO_STRING;
6461 CHECK_TYPE(XPATH_STRING);
6462 needle = valuePop(ctxt);
6463 CAST_TO_STRING;
6464 hay = valuePop(ctxt);
6465 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6466 xmlXPathFreeObject(hay);
6467 xmlXPathFreeObject(needle);
6468 XP_ERROR(XPATH_INVALID_TYPE);
6469 }
6470 n = xmlStrlen(needle->stringval);
6471 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6472 valuePush(ctxt, xmlXPathNewBoolean(0));
6473 else
6474 valuePush(ctxt, xmlXPathNewBoolean(1));
6475 xmlXPathFreeObject(hay);
6476 xmlXPathFreeObject(needle);
6477}
6478
6479/**
6480 * xmlXPathSubstringFunction:
6481 * @ctxt: the XPath Parser context
6482 * @nargs: the number of arguments
6483 *
6484 * Implement the substring() XPath function
6485 * string substring(string, number, number?)
6486 * The substring function returns the substring of the first argument
6487 * starting at the position specified in the second argument with
6488 * length specified in the third argument. For example,
6489 * substring("12345",2,3) returns "234". If the third argument is not
6490 * specified, it returns the substring starting at the position specified
6491 * in the second argument and continuing to the end of the string. For
6492 * example, substring("12345",2) returns "2345". More precisely, each
6493 * character in the string (see [3.6 Strings]) is considered to have a
6494 * numeric position: the position of the first character is 1, the position
6495 * of the second character is 2 and so on. The returned substring contains
6496 * those characters for which the position of the character is greater than
6497 * or equal to the second argument and, if the third argument is specified,
6498 * less than the sum of the second and third arguments; the comparisons
6499 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6500 * - substring("12345", 1.5, 2.6) returns "234"
6501 * - substring("12345", 0, 3) returns "12"
6502 * - substring("12345", 0 div 0, 3) returns ""
6503 * - substring("12345", 1, 0 div 0) returns ""
6504 * - substring("12345", -42, 1 div 0) returns "12345"
6505 * - substring("12345", -1 div 0, 1 div 0) returns ""
6506 */
6507void
6508xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6509 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006510 double le=0, in;
6511 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006512 xmlChar *ret;
6513
Owen Taylor3473f882001-02-23 17:55:21 +00006514 if (nargs < 2) {
6515 CHECK_ARITY(2);
6516 }
6517 if (nargs > 3) {
6518 CHECK_ARITY(3);
6519 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006520 /*
6521 * take care of possible last (position) argument
6522 */
Owen Taylor3473f882001-02-23 17:55:21 +00006523 if (nargs == 3) {
6524 CAST_TO_NUMBER;
6525 CHECK_TYPE(XPATH_NUMBER);
6526 len = valuePop(ctxt);
6527 le = len->floatval;
6528 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006529 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006530
Owen Taylor3473f882001-02-23 17:55:21 +00006531 CAST_TO_NUMBER;
6532 CHECK_TYPE(XPATH_NUMBER);
6533 start = valuePop(ctxt);
6534 in = start->floatval;
6535 xmlXPathFreeObject(start);
6536 CAST_TO_STRING;
6537 CHECK_TYPE(XPATH_STRING);
6538 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006539 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006540
Daniel Veillard97ac1312001-05-30 19:14:17 +00006541 /*
6542 * If last pos not present, calculate last position
6543 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006544 if (nargs != 3) {
6545 le = (double)m;
6546 if (in < 1.0)
6547 in = 1.0;
6548 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006549
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006550 /* Need to check for the special cases where either
6551 * the index is NaN, the length is NaN, or both
6552 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006553 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006554 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006555 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006556 * To meet the requirements of the spec, the arguments
6557 * must be converted to integer format before
6558 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006559 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006560 * First we go to integer form, rounding up
6561 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006562 */
6563 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006564 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006565
Daniel Veillard9e412302002-06-10 15:59:44 +00006566 if (xmlXPathIsInf(le) == 1) {
6567 l = m;
6568 if (i < 1)
6569 i = 1;
6570 }
6571 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6572 l = 0;
6573 else {
6574 l = (int) le;
6575 if (((double)l)+0.5 <= le) l++;
6576 }
6577
6578 /* Now we normalize inidices */
6579 i -= 1;
6580 l += i;
6581 if (i < 0)
6582 i = 0;
6583 if (l > m)
6584 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006585
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006586 /* number of chars to copy */
6587 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006588
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006589 ret = xmlUTF8Strsub(str->stringval, i, l);
6590 }
6591 else {
6592 ret = NULL;
6593 }
6594
Owen Taylor3473f882001-02-23 17:55:21 +00006595 if (ret == NULL)
6596 valuePush(ctxt, xmlXPathNewCString(""));
6597 else {
6598 valuePush(ctxt, xmlXPathNewString(ret));
6599 xmlFree(ret);
6600 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006601
Owen Taylor3473f882001-02-23 17:55:21 +00006602 xmlXPathFreeObject(str);
6603}
6604
6605/**
6606 * xmlXPathSubstringBeforeFunction:
6607 * @ctxt: the XPath Parser context
6608 * @nargs: the number of arguments
6609 *
6610 * Implement the substring-before() XPath function
6611 * string substring-before(string, string)
6612 * The substring-before function returns the substring of the first
6613 * argument string that precedes the first occurrence of the second
6614 * argument string in the first argument string, or the empty string
6615 * if the first argument string does not contain the second argument
6616 * string. For example, substring-before("1999/04/01","/") returns 1999.
6617 */
6618void
6619xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6620 xmlXPathObjectPtr str;
6621 xmlXPathObjectPtr find;
6622 xmlBufferPtr target;
6623 const xmlChar *point;
6624 int offset;
6625
6626 CHECK_ARITY(2);
6627 CAST_TO_STRING;
6628 find = valuePop(ctxt);
6629 CAST_TO_STRING;
6630 str = valuePop(ctxt);
6631
6632 target = xmlBufferCreate();
6633 if (target) {
6634 point = xmlStrstr(str->stringval, find->stringval);
6635 if (point) {
6636 offset = (int)(point - str->stringval);
6637 xmlBufferAdd(target, str->stringval, offset);
6638 }
6639 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6640 xmlBufferFree(target);
6641 }
6642
6643 xmlXPathFreeObject(str);
6644 xmlXPathFreeObject(find);
6645}
6646
6647/**
6648 * xmlXPathSubstringAfterFunction:
6649 * @ctxt: the XPath Parser context
6650 * @nargs: the number of arguments
6651 *
6652 * Implement the substring-after() XPath function
6653 * string substring-after(string, string)
6654 * The substring-after function returns the substring of the first
6655 * argument string that follows the first occurrence of the second
6656 * argument string in the first argument string, or the empty stringi
6657 * if the first argument string does not contain the second argument
6658 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6659 * and substring-after("1999/04/01","19") returns 99/04/01.
6660 */
6661void
6662xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6663 xmlXPathObjectPtr str;
6664 xmlXPathObjectPtr find;
6665 xmlBufferPtr target;
6666 const xmlChar *point;
6667 int offset;
6668
6669 CHECK_ARITY(2);
6670 CAST_TO_STRING;
6671 find = valuePop(ctxt);
6672 CAST_TO_STRING;
6673 str = valuePop(ctxt);
6674
6675 target = xmlBufferCreate();
6676 if (target) {
6677 point = xmlStrstr(str->stringval, find->stringval);
6678 if (point) {
6679 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6680 xmlBufferAdd(target, &str->stringval[offset],
6681 xmlStrlen(str->stringval) - offset);
6682 }
6683 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6684 xmlBufferFree(target);
6685 }
6686
6687 xmlXPathFreeObject(str);
6688 xmlXPathFreeObject(find);
6689}
6690
6691/**
6692 * xmlXPathNormalizeFunction:
6693 * @ctxt: the XPath Parser context
6694 * @nargs: the number of arguments
6695 *
6696 * Implement the normalize-space() XPath function
6697 * string normalize-space(string?)
6698 * The normalize-space function returns the argument string with white
6699 * space normalized by stripping leading and trailing whitespace
6700 * and replacing sequences of whitespace characters by a single
6701 * space. Whitespace characters are the same allowed by the S production
6702 * in XML. If the argument is omitted, it defaults to the context
6703 * node converted to a string, in other words the value of the context node.
6704 */
6705void
6706xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6707 xmlXPathObjectPtr obj = NULL;
6708 xmlChar *source = NULL;
6709 xmlBufferPtr target;
6710 xmlChar blank;
6711
6712 if (nargs == 0) {
6713 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006714 valuePush(ctxt,
6715 xmlXPathWrapString(
6716 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006717 nargs = 1;
6718 }
6719
6720 CHECK_ARITY(1);
6721 CAST_TO_STRING;
6722 CHECK_TYPE(XPATH_STRING);
6723 obj = valuePop(ctxt);
6724 source = obj->stringval;
6725
6726 target = xmlBufferCreate();
6727 if (target && source) {
6728
6729 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006730 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006731 source++;
6732
6733 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6734 blank = 0;
6735 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006736 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006737 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006738 } else {
6739 if (blank) {
6740 xmlBufferAdd(target, &blank, 1);
6741 blank = 0;
6742 }
6743 xmlBufferAdd(target, source, 1);
6744 }
6745 source++;
6746 }
6747
6748 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6749 xmlBufferFree(target);
6750 }
6751 xmlXPathFreeObject(obj);
6752}
6753
6754/**
6755 * xmlXPathTranslateFunction:
6756 * @ctxt: the XPath Parser context
6757 * @nargs: the number of arguments
6758 *
6759 * Implement the translate() XPath function
6760 * string translate(string, string, string)
6761 * The translate function returns the first argument string with
6762 * occurrences of characters in the second argument string replaced
6763 * by the character at the corresponding position in the third argument
6764 * string. For example, translate("bar","abc","ABC") returns the string
6765 * BAr. If there is a character in the second argument string with no
6766 * character at a corresponding position in the third argument string
6767 * (because the second argument string is longer than the third argument
6768 * string), then occurrences of that character in the first argument
6769 * string are removed. For example, translate("--aaa--","abc-","ABC")
6770 * returns "AAA". If a character occurs more than once in second
6771 * argument string, then the first occurrence determines the replacement
6772 * character. If the third argument string is longer than the second
6773 * argument string, then excess characters are ignored.
6774 */
6775void
6776xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006777 xmlXPathObjectPtr str;
6778 xmlXPathObjectPtr from;
6779 xmlXPathObjectPtr to;
6780 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006781 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006782 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006783 xmlChar *point;
6784 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006785
Daniel Veillarde043ee12001-04-16 14:08:07 +00006786 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006787
Daniel Veillarde043ee12001-04-16 14:08:07 +00006788 CAST_TO_STRING;
6789 to = valuePop(ctxt);
6790 CAST_TO_STRING;
6791 from = valuePop(ctxt);
6792 CAST_TO_STRING;
6793 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006794
Daniel Veillarde043ee12001-04-16 14:08:07 +00006795 target = xmlBufferCreate();
6796 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006797 max = xmlUTF8Strlen(to->stringval);
6798 for (cptr = str->stringval; (ch=*cptr); ) {
6799 offset = xmlUTF8Strloc(from->stringval, cptr);
6800 if (offset >= 0) {
6801 if (offset < max) {
6802 point = xmlUTF8Strpos(to->stringval, offset);
6803 if (point)
6804 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6805 }
6806 } else
6807 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6808
6809 /* Step to next character in input */
6810 cptr++;
6811 if ( ch & 0x80 ) {
6812 /* if not simple ascii, verify proper format */
6813 if ( (ch & 0xc0) != 0xc0 ) {
6814 xmlGenericError(xmlGenericErrorContext,
6815 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6816 break;
6817 }
6818 /* then skip over remaining bytes for this char */
6819 while ( (ch <<= 1) & 0x80 )
6820 if ( (*cptr++ & 0xc0) != 0x80 ) {
6821 xmlGenericError(xmlGenericErrorContext,
6822 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6823 break;
6824 }
6825 if (ch & 0x80) /* must have had error encountered */
6826 break;
6827 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006828 }
Owen Taylor3473f882001-02-23 17:55:21 +00006829 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006830 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6831 xmlBufferFree(target);
6832 xmlXPathFreeObject(str);
6833 xmlXPathFreeObject(from);
6834 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006835}
6836
6837/**
6838 * xmlXPathBooleanFunction:
6839 * @ctxt: the XPath Parser context
6840 * @nargs: the number of arguments
6841 *
6842 * Implement the boolean() XPath function
6843 * boolean boolean(object)
6844 * he boolean function converts its argument to a boolean as follows:
6845 * - a number is true if and only if it is neither positive or
6846 * negative zero nor NaN
6847 * - a node-set is true if and only if it is non-empty
6848 * - a string is true if and only if its length is non-zero
6849 */
6850void
6851xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6852 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006853
6854 CHECK_ARITY(1);
6855 cur = valuePop(ctxt);
6856 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006857 cur = xmlXPathConvertBoolean(cur);
6858 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006859}
6860
6861/**
6862 * xmlXPathNotFunction:
6863 * @ctxt: the XPath Parser context
6864 * @nargs: the number of arguments
6865 *
6866 * Implement the not() XPath function
6867 * boolean not(boolean)
6868 * The not function returns true if its argument is false,
6869 * and false otherwise.
6870 */
6871void
6872xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6873 CHECK_ARITY(1);
6874 CAST_TO_BOOLEAN;
6875 CHECK_TYPE(XPATH_BOOLEAN);
6876 ctxt->value->boolval = ! ctxt->value->boolval;
6877}
6878
6879/**
6880 * xmlXPathTrueFunction:
6881 * @ctxt: the XPath Parser context
6882 * @nargs: the number of arguments
6883 *
6884 * Implement the true() XPath function
6885 * boolean true()
6886 */
6887void
6888xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6889 CHECK_ARITY(0);
6890 valuePush(ctxt, xmlXPathNewBoolean(1));
6891}
6892
6893/**
6894 * xmlXPathFalseFunction:
6895 * @ctxt: the XPath Parser context
6896 * @nargs: the number of arguments
6897 *
6898 * Implement the false() XPath function
6899 * boolean false()
6900 */
6901void
6902xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6903 CHECK_ARITY(0);
6904 valuePush(ctxt, xmlXPathNewBoolean(0));
6905}
6906
6907/**
6908 * xmlXPathLangFunction:
6909 * @ctxt: the XPath Parser context
6910 * @nargs: the number of arguments
6911 *
6912 * Implement the lang() XPath function
6913 * boolean lang(string)
6914 * The lang function returns true or false depending on whether the
6915 * language of the context node as specified by xml:lang attributes
6916 * is the same as or is a sublanguage of the language specified by
6917 * the argument string. The language of the context node is determined
6918 * by the value of the xml:lang attribute on the context node, or, if
6919 * the context node has no xml:lang attribute, by the value of the
6920 * xml:lang attribute on the nearest ancestor of the context node that
6921 * has an xml:lang attribute. If there is no such attribute, then lang
6922 * returns false. If there is such an attribute, then lang returns
6923 * true if the attribute value is equal to the argument ignoring case,
6924 * or if there is some suffix starting with - such that the attribute
6925 * value is equal to the argument ignoring that suffix of the attribute
6926 * value and ignoring case.
6927 */
6928void
6929xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6930 xmlXPathObjectPtr val;
6931 const xmlChar *theLang;
6932 const xmlChar *lang;
6933 int ret = 0;
6934 int i;
6935
6936 CHECK_ARITY(1);
6937 CAST_TO_STRING;
6938 CHECK_TYPE(XPATH_STRING);
6939 val = valuePop(ctxt);
6940 lang = val->stringval;
6941 theLang = xmlNodeGetLang(ctxt->context->node);
6942 if ((theLang != NULL) && (lang != NULL)) {
6943 for (i = 0;lang[i] != 0;i++)
6944 if (toupper(lang[i]) != toupper(theLang[i]))
6945 goto not_equal;
6946 ret = 1;
6947 }
6948not_equal:
6949 xmlXPathFreeObject(val);
6950 valuePush(ctxt, xmlXPathNewBoolean(ret));
6951}
6952
6953/**
6954 * xmlXPathNumberFunction:
6955 * @ctxt: the XPath Parser context
6956 * @nargs: the number of arguments
6957 *
6958 * Implement the number() XPath function
6959 * number number(object?)
6960 */
6961void
6962xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6963 xmlXPathObjectPtr cur;
6964 double res;
6965
6966 if (nargs == 0) {
6967 if (ctxt->context->node == NULL) {
6968 valuePush(ctxt, xmlXPathNewFloat(0.0));
6969 } else {
6970 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6971
6972 res = xmlXPathStringEvalNumber(content);
6973 valuePush(ctxt, xmlXPathNewFloat(res));
6974 xmlFree(content);
6975 }
6976 return;
6977 }
6978
6979 CHECK_ARITY(1);
6980 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006981 cur = xmlXPathConvertNumber(cur);
6982 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006983}
6984
6985/**
6986 * xmlXPathSumFunction:
6987 * @ctxt: the XPath Parser context
6988 * @nargs: the number of arguments
6989 *
6990 * Implement the sum() XPath function
6991 * number sum(node-set)
6992 * The sum function returns the sum of the values of the nodes in
6993 * the argument node-set.
6994 */
6995void
6996xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6997 xmlXPathObjectPtr cur;
6998 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006999 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007000
7001 CHECK_ARITY(1);
7002 if ((ctxt->value == NULL) ||
7003 ((ctxt->value->type != XPATH_NODESET) &&
7004 (ctxt->value->type != XPATH_XSLT_TREE)))
7005 XP_ERROR(XPATH_INVALID_TYPE);
7006 cur = valuePop(ctxt);
7007
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007008 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007009 valuePush(ctxt, xmlXPathNewFloat(0.0));
7010 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007011 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7012 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007013 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007014 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007015 }
7016 xmlXPathFreeObject(cur);
7017}
7018
7019/**
7020 * xmlXPathFloorFunction:
7021 * @ctxt: the XPath Parser context
7022 * @nargs: the number of arguments
7023 *
7024 * Implement the floor() XPath function
7025 * number floor(number)
7026 * The floor function returns the largest (closest to positive infinity)
7027 * number that is not greater than the argument and that is an integer.
7028 */
7029void
7030xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007031 double f;
7032
Owen Taylor3473f882001-02-23 17:55:21 +00007033 CHECK_ARITY(1);
7034 CAST_TO_NUMBER;
7035 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007036
7037 f = (double)((int) ctxt->value->floatval);
7038 if (f != ctxt->value->floatval) {
7039 if (ctxt->value->floatval > 0)
7040 ctxt->value->floatval = f;
7041 else
7042 ctxt->value->floatval = f - 1;
7043 }
Owen Taylor3473f882001-02-23 17:55:21 +00007044}
7045
7046/**
7047 * xmlXPathCeilingFunction:
7048 * @ctxt: the XPath Parser context
7049 * @nargs: the number of arguments
7050 *
7051 * Implement the ceiling() XPath function
7052 * number ceiling(number)
7053 * The ceiling function returns the smallest (closest to negative infinity)
7054 * number that is not less than the argument and that is an integer.
7055 */
7056void
7057xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7058 double f;
7059
7060 CHECK_ARITY(1);
7061 CAST_TO_NUMBER;
7062 CHECK_TYPE(XPATH_NUMBER);
7063
7064#if 0
7065 ctxt->value->floatval = ceil(ctxt->value->floatval);
7066#else
7067 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007068 if (f != ctxt->value->floatval) {
7069 if (ctxt->value->floatval > 0)
7070 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007071 else {
7072 if (ctxt->value->floatval < 0 && f == 0)
7073 ctxt->value->floatval = xmlXPathNZERO;
7074 else
7075 ctxt->value->floatval = f;
7076 }
7077
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007078 }
Owen Taylor3473f882001-02-23 17:55:21 +00007079#endif
7080}
7081
7082/**
7083 * xmlXPathRoundFunction:
7084 * @ctxt: the XPath Parser context
7085 * @nargs: the number of arguments
7086 *
7087 * Implement the round() XPath function
7088 * number round(number)
7089 * The round function returns the number that is closest to the
7090 * argument and that is an integer. If there are two such numbers,
7091 * then the one that is even is returned.
7092 */
7093void
7094xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7095 double f;
7096
7097 CHECK_ARITY(1);
7098 CAST_TO_NUMBER;
7099 CHECK_TYPE(XPATH_NUMBER);
7100
Daniel Veillardcda96922001-08-21 10:56:31 +00007101 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7102 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7103 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007104 (ctxt->value->floatval == 0.0))
7105 return;
7106
Owen Taylor3473f882001-02-23 17:55:21 +00007107 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007108 if (ctxt->value->floatval < 0) {
7109 if (ctxt->value->floatval < f - 0.5)
7110 ctxt->value->floatval = f - 1;
7111 else
7112 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007113 if (ctxt->value->floatval == 0)
7114 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007115 } else {
7116 if (ctxt->value->floatval < f + 0.5)
7117 ctxt->value->floatval = f;
7118 else
7119 ctxt->value->floatval = f + 1;
7120 }
Owen Taylor3473f882001-02-23 17:55:21 +00007121}
7122
7123/************************************************************************
7124 * *
7125 * The Parser *
7126 * *
7127 ************************************************************************/
7128
7129/*
7130 * a couple of forward declarations since we use a recursive call based
7131 * implementation.
7132 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007133static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007134static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007135static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007136static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007137static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7138 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007139
7140/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007141 * xmlXPathCurrentChar:
7142 * @ctxt: the XPath parser context
7143 * @cur: pointer to the beginning of the char
7144 * @len: pointer to the length of the char read
7145 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007146 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007147 * bytes in the input buffer.
7148 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007149 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007150 */
7151
7152static int
7153xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7154 unsigned char c;
7155 unsigned int val;
7156 const xmlChar *cur;
7157
7158 if (ctxt == NULL)
7159 return(0);
7160 cur = ctxt->cur;
7161
7162 /*
7163 * We are supposed to handle UTF8, check it's valid
7164 * From rfc2044: encoding of the Unicode values on UTF-8:
7165 *
7166 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7167 * 0000 0000-0000 007F 0xxxxxxx
7168 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7169 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7170 *
7171 * Check for the 0x110000 limit too
7172 */
7173 c = *cur;
7174 if (c & 0x80) {
7175 if ((cur[1] & 0xc0) != 0x80)
7176 goto encoding_error;
7177 if ((c & 0xe0) == 0xe0) {
7178
7179 if ((cur[2] & 0xc0) != 0x80)
7180 goto encoding_error;
7181 if ((c & 0xf0) == 0xf0) {
7182 if (((c & 0xf8) != 0xf0) ||
7183 ((cur[3] & 0xc0) != 0x80))
7184 goto encoding_error;
7185 /* 4-byte code */
7186 *len = 4;
7187 val = (cur[0] & 0x7) << 18;
7188 val |= (cur[1] & 0x3f) << 12;
7189 val |= (cur[2] & 0x3f) << 6;
7190 val |= cur[3] & 0x3f;
7191 } else {
7192 /* 3-byte code */
7193 *len = 3;
7194 val = (cur[0] & 0xf) << 12;
7195 val |= (cur[1] & 0x3f) << 6;
7196 val |= cur[2] & 0x3f;
7197 }
7198 } else {
7199 /* 2-byte code */
7200 *len = 2;
7201 val = (cur[0] & 0x1f) << 6;
7202 val |= cur[1] & 0x3f;
7203 }
7204 if (!IS_CHAR(val)) {
7205 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7206 }
7207 return(val);
7208 } else {
7209 /* 1-byte code */
7210 *len = 1;
7211 return((int) *cur);
7212 }
7213encoding_error:
7214 /*
7215 * If we detect an UTF8 error that probably mean that the
7216 * input encoding didn't get properly advertized in the
7217 * declaration header. Report the error and switch the encoding
7218 * to ISO-Latin-1 (if you don't like this policy, just declare the
7219 * encoding !)
7220 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007221 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007222 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007223}
7224
7225/**
Owen Taylor3473f882001-02-23 17:55:21 +00007226 * xmlXPathParseNCName:
7227 * @ctxt: the XPath Parser context
7228 *
7229 * parse an XML namespace non qualified name.
7230 *
7231 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7232 *
7233 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7234 * CombiningChar | Extender
7235 *
7236 * Returns the namespace name or NULL
7237 */
7238
7239xmlChar *
7240xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007241 const xmlChar *in;
7242 xmlChar *ret;
7243 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007244
Daniel Veillard2156a562001-04-28 12:24:34 +00007245 /*
7246 * Accelerator for simple ASCII names
7247 */
7248 in = ctxt->cur;
7249 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7250 ((*in >= 0x41) && (*in <= 0x5A)) ||
7251 (*in == '_')) {
7252 in++;
7253 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7254 ((*in >= 0x41) && (*in <= 0x5A)) ||
7255 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007256 (*in == '_') || (*in == '.') ||
7257 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007258 in++;
7259 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7260 (*in == '[') || (*in == ']') || (*in == ':') ||
7261 (*in == '@') || (*in == '*')) {
7262 count = in - ctxt->cur;
7263 if (count == 0)
7264 return(NULL);
7265 ret = xmlStrndup(ctxt->cur, count);
7266 ctxt->cur = in;
7267 return(ret);
7268 }
7269 }
7270 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007271}
7272
Daniel Veillard2156a562001-04-28 12:24:34 +00007273
Owen Taylor3473f882001-02-23 17:55:21 +00007274/**
7275 * xmlXPathParseQName:
7276 * @ctxt: the XPath Parser context
7277 * @prefix: a xmlChar **
7278 *
7279 * parse an XML qualified name
7280 *
7281 * [NS 5] QName ::= (Prefix ':')? LocalPart
7282 *
7283 * [NS 6] Prefix ::= NCName
7284 *
7285 * [NS 7] LocalPart ::= NCName
7286 *
7287 * Returns the function returns the local part, and prefix is updated
7288 * to get the Prefix if any.
7289 */
7290
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007291static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007292xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7293 xmlChar *ret = NULL;
7294
7295 *prefix = NULL;
7296 ret = xmlXPathParseNCName(ctxt);
7297 if (CUR == ':') {
7298 *prefix = ret;
7299 NEXT;
7300 ret = xmlXPathParseNCName(ctxt);
7301 }
7302 return(ret);
7303}
7304
7305/**
7306 * xmlXPathParseName:
7307 * @ctxt: the XPath Parser context
7308 *
7309 * parse an XML name
7310 *
7311 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7312 * CombiningChar | Extender
7313 *
7314 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7315 *
7316 * Returns the namespace name or NULL
7317 */
7318
7319xmlChar *
7320xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007321 const xmlChar *in;
7322 xmlChar *ret;
7323 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007324
Daniel Veillard61d80a22001-04-27 17:13:01 +00007325 /*
7326 * Accelerator for simple ASCII names
7327 */
7328 in = ctxt->cur;
7329 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7330 ((*in >= 0x41) && (*in <= 0x5A)) ||
7331 (*in == '_') || (*in == ':')) {
7332 in++;
7333 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7334 ((*in >= 0x41) && (*in <= 0x5A)) ||
7335 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007336 (*in == '_') || (*in == '-') ||
7337 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007338 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007339 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007340 count = in - ctxt->cur;
7341 ret = xmlStrndup(ctxt->cur, count);
7342 ctxt->cur = in;
7343 return(ret);
7344 }
7345 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007346 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007347}
7348
Daniel Veillard61d80a22001-04-27 17:13:01 +00007349static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007350xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007351 xmlChar buf[XML_MAX_NAMELEN + 5];
7352 int len = 0, l;
7353 int c;
7354
7355 /*
7356 * Handler for more complex cases
7357 */
7358 c = CUR_CHAR(l);
7359 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007360 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7361 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007362 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007363 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007364 return(NULL);
7365 }
7366
7367 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7368 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7369 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007370 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007371 (IS_COMBINING(c)) ||
7372 (IS_EXTENDER(c)))) {
7373 COPY_BUF(l,buf,len,c);
7374 NEXTL(l);
7375 c = CUR_CHAR(l);
7376 if (len >= XML_MAX_NAMELEN) {
7377 /*
7378 * Okay someone managed to make a huge name, so he's ready to pay
7379 * for the processing speed.
7380 */
7381 xmlChar *buffer;
7382 int max = len * 2;
7383
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007384 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007385 if (buffer == NULL) {
7386 XP_ERROR0(XPATH_MEMORY_ERROR);
7387 }
7388 memcpy(buffer, buf, len);
7389 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7390 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007391 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007392 (IS_COMBINING(c)) ||
7393 (IS_EXTENDER(c))) {
7394 if (len + 10 > max) {
7395 max *= 2;
7396 buffer = (xmlChar *) xmlRealloc(buffer,
7397 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007398 if (buffer == NULL) {
7399 XP_ERROR0(XPATH_MEMORY_ERROR);
7400 }
7401 }
7402 COPY_BUF(l,buffer,len,c);
7403 NEXTL(l);
7404 c = CUR_CHAR(l);
7405 }
7406 buffer[len] = 0;
7407 return(buffer);
7408 }
7409 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007410 if (len == 0)
7411 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007412 return(xmlStrndup(buf, len));
7413}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007414
7415#define MAX_FRAC 20
7416
7417static double my_pow10[MAX_FRAC] = {
7418 1.0, 10.0, 100.0, 1000.0, 10000.0,
7419 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7420 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7421 100000000000000.0,
7422 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7423 1000000000000000000.0, 10000000000000000000.0
7424};
7425
Owen Taylor3473f882001-02-23 17:55:21 +00007426/**
7427 * xmlXPathStringEvalNumber:
7428 * @str: A string to scan
7429 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007430 * [30a] Float ::= Number ('e' Digits?)?
7431 *
Owen Taylor3473f882001-02-23 17:55:21 +00007432 * [30] Number ::= Digits ('.' Digits?)?
7433 * | '.' Digits
7434 * [31] Digits ::= [0-9]+
7435 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007436 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007437 * In complement of the Number expression, this function also handles
7438 * negative values : '-' Number.
7439 *
7440 * Returns the double value.
7441 */
7442double
7443xmlXPathStringEvalNumber(const xmlChar *str) {
7444 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007445 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007446 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007447 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007448 int exponent = 0;
7449 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007450#ifdef __GNUC__
7451 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007452 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007453#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007454 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007455 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007456 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7457 return(xmlXPathNAN);
7458 }
7459 if (*cur == '-') {
7460 isneg = 1;
7461 cur++;
7462 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007463
7464#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007465 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007466 * tmp/temp is a workaround against a gcc compiler bug
7467 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007468 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007469 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007470 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007471 ret = ret * 10;
7472 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007473 ok = 1;
7474 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007475 temp = (double) tmp;
7476 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007477 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007478#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007479 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007480 while ((*cur >= '0') && (*cur <= '9')) {
7481 ret = ret * 10 + (*cur - '0');
7482 ok = 1;
7483 cur++;
7484 }
7485#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007486
Owen Taylor3473f882001-02-23 17:55:21 +00007487 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007488 int v, frac = 0;
7489 double fraction = 0;
7490
Owen Taylor3473f882001-02-23 17:55:21 +00007491 cur++;
7492 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7493 return(xmlXPathNAN);
7494 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007495 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7496 v = (*cur - '0');
7497 fraction = fraction * 10 + v;
7498 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007499 cur++;
7500 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007501 fraction /= my_pow10[frac];
7502 ret = ret + fraction;
7503 while ((*cur >= '0') && (*cur <= '9'))
7504 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007505 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007506 if ((*cur == 'e') || (*cur == 'E')) {
7507 cur++;
7508 if (*cur == '-') {
7509 is_exponent_negative = 1;
7510 cur++;
7511 }
7512 while ((*cur >= '0') && (*cur <= '9')) {
7513 exponent = exponent * 10 + (*cur - '0');
7514 cur++;
7515 }
7516 }
William M. Brack76e95df2003-10-18 16:20:14 +00007517 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007518 if (*cur != 0) return(xmlXPathNAN);
7519 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007520 if (is_exponent_negative) exponent = -exponent;
7521 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007522 return(ret);
7523}
7524
7525/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007526 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007527 * @ctxt: the XPath Parser context
7528 *
7529 * [30] Number ::= Digits ('.' Digits?)?
7530 * | '.' Digits
7531 * [31] Digits ::= [0-9]+
7532 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007533 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007534 *
7535 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007536static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007537xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7538{
Owen Taylor3473f882001-02-23 17:55:21 +00007539 double ret = 0.0;
7540 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007541 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007542 int exponent = 0;
7543 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007544#ifdef __GNUC__
7545 unsigned long tmp = 0;
7546 double temp;
7547#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007548
7549 CHECK_ERROR;
7550 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7551 XP_ERROR(XPATH_NUMBER_ERROR);
7552 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007553#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007554 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007555 * tmp/temp is a workaround against a gcc compiler bug
7556 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007557 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007558 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007559 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007560 ret = ret * 10;
7561 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007562 ok = 1;
7563 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007564 temp = (double) tmp;
7565 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007566 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007567#else
7568 ret = 0;
7569 while ((CUR >= '0') && (CUR <= '9')) {
7570 ret = ret * 10 + (CUR - '0');
7571 ok = 1;
7572 NEXT;
7573 }
7574#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007575 if (CUR == '.') {
7576 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007577 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7578 XP_ERROR(XPATH_NUMBER_ERROR);
7579 }
7580 while ((CUR >= '0') && (CUR <= '9')) {
7581 mult /= 10;
7582 ret = ret + (CUR - '0') * mult;
7583 NEXT;
7584 }
Owen Taylor3473f882001-02-23 17:55:21 +00007585 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007586 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007587 NEXT;
7588 if (CUR == '-') {
7589 is_exponent_negative = 1;
7590 NEXT;
7591 }
7592 while ((CUR >= '0') && (CUR <= '9')) {
7593 exponent = exponent * 10 + (CUR - '0');
7594 NEXT;
7595 }
7596 if (is_exponent_negative)
7597 exponent = -exponent;
7598 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007599 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007600 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007601 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007602}
7603
7604/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007605 * xmlXPathParseLiteral:
7606 * @ctxt: the XPath Parser context
7607 *
7608 * Parse a Literal
7609 *
7610 * [29] Literal ::= '"' [^"]* '"'
7611 * | "'" [^']* "'"
7612 *
7613 * Returns the value found or NULL in case of error
7614 */
7615static xmlChar *
7616xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7617 const xmlChar *q;
7618 xmlChar *ret = NULL;
7619
7620 if (CUR == '"') {
7621 NEXT;
7622 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007623 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007624 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007625 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007626 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7627 } else {
7628 ret = xmlStrndup(q, CUR_PTR - q);
7629 NEXT;
7630 }
7631 } else if (CUR == '\'') {
7632 NEXT;
7633 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007634 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007635 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007636 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007637 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7638 } else {
7639 ret = xmlStrndup(q, CUR_PTR - q);
7640 NEXT;
7641 }
7642 } else {
7643 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7644 }
7645 return(ret);
7646}
7647
7648/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007649 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007650 * @ctxt: the XPath Parser context
7651 *
7652 * Parse a Literal and push it on the stack.
7653 *
7654 * [29] Literal ::= '"' [^"]* '"'
7655 * | "'" [^']* "'"
7656 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007657 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007658 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007659static void
7660xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007661 const xmlChar *q;
7662 xmlChar *ret = NULL;
7663
7664 if (CUR == '"') {
7665 NEXT;
7666 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007667 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007668 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007669 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007670 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7671 } else {
7672 ret = xmlStrndup(q, CUR_PTR - q);
7673 NEXT;
7674 }
7675 } else if (CUR == '\'') {
7676 NEXT;
7677 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007678 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007679 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007680 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007681 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7682 } else {
7683 ret = xmlStrndup(q, CUR_PTR - q);
7684 NEXT;
7685 }
7686 } else {
7687 XP_ERROR(XPATH_START_LITERAL_ERROR);
7688 }
7689 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007690 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7691 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007692 xmlFree(ret);
7693}
7694
7695/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007696 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007697 * @ctxt: the XPath Parser context
7698 *
7699 * Parse a VariableReference, evaluate it and push it on the stack.
7700 *
7701 * The variable bindings consist of a mapping from variable names
7702 * to variable values. The value of a variable is an object, which
7703 * of any of the types that are possible for the value of an expression,
7704 * and may also be of additional types not specified here.
7705 *
7706 * Early evaluation is possible since:
7707 * The variable bindings [...] used to evaluate a subexpression are
7708 * always the same as those used to evaluate the containing expression.
7709 *
7710 * [36] VariableReference ::= '$' QName
7711 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007712static void
7713xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007714 xmlChar *name;
7715 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007716
7717 SKIP_BLANKS;
7718 if (CUR != '$') {
7719 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7720 }
7721 NEXT;
7722 name = xmlXPathParseQName(ctxt, &prefix);
7723 if (name == NULL) {
7724 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7725 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007726 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007727 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7728 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007729 SKIP_BLANKS;
7730}
7731
7732/**
7733 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007734 * @name: a name string
7735 *
7736 * Is the name given a NodeType one.
7737 *
7738 * [38] NodeType ::= 'comment'
7739 * | 'text'
7740 * | 'processing-instruction'
7741 * | 'node'
7742 *
7743 * Returns 1 if true 0 otherwise
7744 */
7745int
7746xmlXPathIsNodeType(const xmlChar *name) {
7747 if (name == NULL)
7748 return(0);
7749
Daniel Veillard1971ee22002-01-31 20:29:19 +00007750 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007751 return(1);
7752 if (xmlStrEqual(name, BAD_CAST "text"))
7753 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007754 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007755 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007756 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007757 return(1);
7758 return(0);
7759}
7760
7761/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007762 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007763 * @ctxt: the XPath Parser context
7764 *
7765 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7766 * [17] Argument ::= Expr
7767 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007768 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007769 * pushed on the stack
7770 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007771static void
7772xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007773 xmlChar *name;
7774 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007775 int nbargs = 0;
7776
7777 name = xmlXPathParseQName(ctxt, &prefix);
7778 if (name == NULL) {
7779 XP_ERROR(XPATH_EXPR_ERROR);
7780 }
7781 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007782#ifdef DEBUG_EXPR
7783 if (prefix == NULL)
7784 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7785 name);
7786 else
7787 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7788 prefix, name);
7789#endif
7790
Owen Taylor3473f882001-02-23 17:55:21 +00007791 if (CUR != '(') {
7792 XP_ERROR(XPATH_EXPR_ERROR);
7793 }
7794 NEXT;
7795 SKIP_BLANKS;
7796
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007797 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007798 if (CUR != ')') {
7799 while (CUR != 0) {
7800 int op1 = ctxt->comp->last;
7801 ctxt->comp->last = -1;
7802 xmlXPathCompileExpr(ctxt);
7803 CHECK_ERROR;
7804 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7805 nbargs++;
7806 if (CUR == ')') break;
7807 if (CUR != ',') {
7808 XP_ERROR(XPATH_EXPR_ERROR);
7809 }
7810 NEXT;
7811 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007812 }
Owen Taylor3473f882001-02-23 17:55:21 +00007813 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007814 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7815 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007816 NEXT;
7817 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007818}
7819
7820/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007821 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007822 * @ctxt: the XPath Parser context
7823 *
7824 * [15] PrimaryExpr ::= VariableReference
7825 * | '(' Expr ')'
7826 * | Literal
7827 * | Number
7828 * | FunctionCall
7829 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007830 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007831 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007832static void
7833xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007834 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007835 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007836 else if (CUR == '(') {
7837 NEXT;
7838 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007839 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007840 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007841 if (CUR != ')') {
7842 XP_ERROR(XPATH_EXPR_ERROR);
7843 }
7844 NEXT;
7845 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007846 } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007847 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007848 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007849 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007850 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007851 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007852 }
7853 SKIP_BLANKS;
7854}
7855
7856/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007857 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007858 * @ctxt: the XPath Parser context
7859 *
7860 * [20] FilterExpr ::= PrimaryExpr
7861 * | FilterExpr Predicate
7862 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007863 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007864 * Square brackets are used to filter expressions in the same way that
7865 * they are used in location paths. It is an error if the expression to
7866 * be filtered does not evaluate to a node-set. The context node list
7867 * used for evaluating the expression in square brackets is the node-set
7868 * to be filtered listed in document order.
7869 */
7870
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007871static void
7872xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7873 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007874 CHECK_ERROR;
7875 SKIP_BLANKS;
7876
7877 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007878 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007879 SKIP_BLANKS;
7880 }
7881
7882
7883}
7884
7885/**
7886 * xmlXPathScanName:
7887 * @ctxt: the XPath Parser context
7888 *
7889 * Trickery: parse an XML name but without consuming the input flow
7890 * Needed to avoid insanity in the parser state.
7891 *
7892 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7893 * CombiningChar | Extender
7894 *
7895 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7896 *
7897 * [6] Names ::= Name (S Name)*
7898 *
7899 * Returns the Name parsed or NULL
7900 */
7901
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007902static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007903xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7904 xmlChar buf[XML_MAX_NAMELEN];
7905 int len = 0;
7906
7907 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007908 if (!IS_LETTER_CH(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00007909 (CUR != ':')) {
7910 return(NULL);
7911 }
7912
William M. Brack76e95df2003-10-18 16:20:14 +00007913 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007914 (NXT(len) == '.') || (NXT(len) == '-') ||
7915 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007916 (IS_COMBINING_CH(NXT(len))) ||
7917 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007918 buf[len] = NXT(len);
7919 len++;
7920 if (len >= XML_MAX_NAMELEN) {
7921 xmlGenericError(xmlGenericErrorContext,
7922 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brack76e95df2003-10-18 16:20:14 +00007923 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007924 (NXT(len) == '.') || (NXT(len) == '-') ||
7925 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007926 (IS_COMBINING_CH(NXT(len))) ||
7927 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00007928 len++;
7929 break;
7930 }
7931 }
7932 return(xmlStrndup(buf, len));
7933}
7934
7935/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007936 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007937 * @ctxt: the XPath Parser context
7938 *
7939 * [19] PathExpr ::= LocationPath
7940 * | FilterExpr
7941 * | FilterExpr '/' RelativeLocationPath
7942 * | FilterExpr '//' RelativeLocationPath
7943 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007944 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007945 * The / operator and // operators combine an arbitrary expression
7946 * and a relative location path. It is an error if the expression
7947 * does not evaluate to a node-set.
7948 * The / operator does composition in the same way as when / is
7949 * used in a location path. As in location paths, // is short for
7950 * /descendant-or-self::node()/.
7951 */
7952
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007953static void
7954xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007955 int lc = 1; /* Should we branch to LocationPath ? */
7956 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7957
7958 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007959 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
7960 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007961 lc = 0;
7962 } else if (CUR == '*') {
7963 /* relative or absolute location path */
7964 lc = 1;
7965 } else if (CUR == '/') {
7966 /* relative or absolute location path */
7967 lc = 1;
7968 } else if (CUR == '@') {
7969 /* relative abbreviated attribute location path */
7970 lc = 1;
7971 } else if (CUR == '.') {
7972 /* relative abbreviated attribute location path */
7973 lc = 1;
7974 } else {
7975 /*
7976 * Problem is finding if we have a name here whether it's:
7977 * - a nodetype
7978 * - a function call in which case it's followed by '('
7979 * - an axis in which case it's followed by ':'
7980 * - a element name
7981 * We do an a priori analysis here rather than having to
7982 * maintain parsed token content through the recursive function
7983 * calls. This looks uglier but makes the code quite easier to
7984 * read/write/debug.
7985 */
7986 SKIP_BLANKS;
7987 name = xmlXPathScanName(ctxt);
7988 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7989#ifdef DEBUG_STEP
7990 xmlGenericError(xmlGenericErrorContext,
7991 "PathExpr: Axis\n");
7992#endif
7993 lc = 1;
7994 xmlFree(name);
7995 } else if (name != NULL) {
7996 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00007997
7998
7999 while (NXT(len) != 0) {
8000 if (NXT(len) == '/') {
8001 /* element name */
8002#ifdef DEBUG_STEP
8003 xmlGenericError(xmlGenericErrorContext,
8004 "PathExpr: AbbrRelLocation\n");
8005#endif
8006 lc = 1;
8007 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008008 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008009 /* ignore blanks */
8010 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008011 } else if (NXT(len) == ':') {
8012#ifdef DEBUG_STEP
8013 xmlGenericError(xmlGenericErrorContext,
8014 "PathExpr: AbbrRelLocation\n");
8015#endif
8016 lc = 1;
8017 break;
8018 } else if ((NXT(len) == '(')) {
8019 /* Note Type or Function */
8020 if (xmlXPathIsNodeType(name)) {
8021#ifdef DEBUG_STEP
8022 xmlGenericError(xmlGenericErrorContext,
8023 "PathExpr: Type search\n");
8024#endif
8025 lc = 1;
8026 } else {
8027#ifdef DEBUG_STEP
8028 xmlGenericError(xmlGenericErrorContext,
8029 "PathExpr: function call\n");
8030#endif
8031 lc = 0;
8032 }
8033 break;
8034 } else if ((NXT(len) == '[')) {
8035 /* element name */
8036#ifdef DEBUG_STEP
8037 xmlGenericError(xmlGenericErrorContext,
8038 "PathExpr: AbbrRelLocation\n");
8039#endif
8040 lc = 1;
8041 break;
8042 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8043 (NXT(len) == '=')) {
8044 lc = 1;
8045 break;
8046 } else {
8047 lc = 1;
8048 break;
8049 }
8050 len++;
8051 }
8052 if (NXT(len) == 0) {
8053#ifdef DEBUG_STEP
8054 xmlGenericError(xmlGenericErrorContext,
8055 "PathExpr: AbbrRelLocation\n");
8056#endif
8057 /* element name */
8058 lc = 1;
8059 }
8060 xmlFree(name);
8061 } else {
8062 /* make sure all cases are covered explicitely */
8063 XP_ERROR(XPATH_EXPR_ERROR);
8064 }
8065 }
8066
8067 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008068 if (CUR == '/') {
8069 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8070 } else {
8071 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008072 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008073 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008074 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008075 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008076 CHECK_ERROR;
8077 if ((CUR == '/') && (NXT(1) == '/')) {
8078 SKIP(2);
8079 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008080
8081 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8082 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8083 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8084
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008085 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008086 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008087 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008088 }
8089 }
8090 SKIP_BLANKS;
8091}
8092
8093/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008094 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008095 * @ctxt: the XPath Parser context
8096 *
8097 * [18] UnionExpr ::= PathExpr
8098 * | UnionExpr '|' PathExpr
8099 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008100 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008101 */
8102
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008103static void
8104xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8105 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008106 CHECK_ERROR;
8107 SKIP_BLANKS;
8108 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008109 int op1 = ctxt->comp->last;
8110 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008111
8112 NEXT;
8113 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008114 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008115
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008116 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8117
Owen Taylor3473f882001-02-23 17:55:21 +00008118 SKIP_BLANKS;
8119 }
Owen Taylor3473f882001-02-23 17:55:21 +00008120}
8121
8122/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008123 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008124 * @ctxt: the XPath Parser context
8125 *
8126 * [27] UnaryExpr ::= UnionExpr
8127 * | '-' UnaryExpr
8128 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008129 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008130 */
8131
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008132static void
8133xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008134 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008135 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008136
8137 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008138 while (CUR == '-') {
8139 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008140 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008141 NEXT;
8142 SKIP_BLANKS;
8143 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008144
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008145 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008146 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008147 if (found) {
8148 if (minus)
8149 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8150 else
8151 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008152 }
8153}
8154
8155/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008156 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008157 * @ctxt: the XPath Parser context
8158 *
8159 * [26] MultiplicativeExpr ::= UnaryExpr
8160 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8161 * | MultiplicativeExpr 'div' UnaryExpr
8162 * | MultiplicativeExpr 'mod' UnaryExpr
8163 * [34] MultiplyOperator ::= '*'
8164 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008165 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008166 */
8167
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008168static void
8169xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8170 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008171 CHECK_ERROR;
8172 SKIP_BLANKS;
8173 while ((CUR == '*') ||
8174 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8175 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8176 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008177 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008178
8179 if (CUR == '*') {
8180 op = 0;
8181 NEXT;
8182 } else if (CUR == 'd') {
8183 op = 1;
8184 SKIP(3);
8185 } else if (CUR == 'm') {
8186 op = 2;
8187 SKIP(3);
8188 }
8189 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008190 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008191 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008192 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008193 SKIP_BLANKS;
8194 }
8195}
8196
8197/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008198 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008199 * @ctxt: the XPath Parser context
8200 *
8201 * [25] AdditiveExpr ::= MultiplicativeExpr
8202 * | AdditiveExpr '+' MultiplicativeExpr
8203 * | AdditiveExpr '-' MultiplicativeExpr
8204 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008205 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008206 */
8207
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008208static void
8209xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008210
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008211 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008212 CHECK_ERROR;
8213 SKIP_BLANKS;
8214 while ((CUR == '+') || (CUR == '-')) {
8215 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008216 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008217
8218 if (CUR == '+') plus = 1;
8219 else plus = 0;
8220 NEXT;
8221 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008222 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008223 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008224 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008225 SKIP_BLANKS;
8226 }
8227}
8228
8229/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008230 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008231 * @ctxt: the XPath Parser context
8232 *
8233 * [24] RelationalExpr ::= AdditiveExpr
8234 * | RelationalExpr '<' AdditiveExpr
8235 * | RelationalExpr '>' AdditiveExpr
8236 * | RelationalExpr '<=' AdditiveExpr
8237 * | RelationalExpr '>=' AdditiveExpr
8238 *
8239 * A <= B > C is allowed ? Answer from James, yes with
8240 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8241 * which is basically what got implemented.
8242 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008243 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008244 * on the stack
8245 */
8246
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008247static void
8248xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8249 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008250 CHECK_ERROR;
8251 SKIP_BLANKS;
8252 while ((CUR == '<') ||
8253 (CUR == '>') ||
8254 ((CUR == '<') && (NXT(1) == '=')) ||
8255 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008256 int inf, strict;
8257 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008258
8259 if (CUR == '<') inf = 1;
8260 else inf = 0;
8261 if (NXT(1) == '=') strict = 0;
8262 else strict = 1;
8263 NEXT;
8264 if (!strict) NEXT;
8265 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008266 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008267 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008268 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008269 SKIP_BLANKS;
8270 }
8271}
8272
8273/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008274 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008275 * @ctxt: the XPath Parser context
8276 *
8277 * [23] EqualityExpr ::= RelationalExpr
8278 * | EqualityExpr '=' RelationalExpr
8279 * | EqualityExpr '!=' RelationalExpr
8280 *
8281 * A != B != C is allowed ? Answer from James, yes with
8282 * (RelationalExpr = RelationalExpr) = RelationalExpr
8283 * (RelationalExpr != RelationalExpr) != RelationalExpr
8284 * which is basically what got implemented.
8285 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008286 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008287 *
8288 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008289static void
8290xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8291 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008292 CHECK_ERROR;
8293 SKIP_BLANKS;
8294 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008295 int eq;
8296 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008297
8298 if (CUR == '=') eq = 1;
8299 else eq = 0;
8300 NEXT;
8301 if (!eq) NEXT;
8302 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008303 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008304 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008305 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008306 SKIP_BLANKS;
8307 }
8308}
8309
8310/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008311 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008312 * @ctxt: the XPath Parser context
8313 *
8314 * [22] AndExpr ::= EqualityExpr
8315 * | AndExpr 'and' EqualityExpr
8316 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008317 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008318 *
8319 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008320static void
8321xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8322 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008323 CHECK_ERROR;
8324 SKIP_BLANKS;
8325 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008326 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008327 SKIP(3);
8328 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008329 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008330 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008331 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008332 SKIP_BLANKS;
8333 }
8334}
8335
8336/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008337 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008338 * @ctxt: the XPath Parser context
8339 *
8340 * [14] Expr ::= OrExpr
8341 * [21] OrExpr ::= AndExpr
8342 * | OrExpr 'or' AndExpr
8343 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008344 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008345 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008346static void
8347xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8348 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008349 CHECK_ERROR;
8350 SKIP_BLANKS;
8351 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008352 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008353 SKIP(2);
8354 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008355 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008356 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008357 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8358 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008359 SKIP_BLANKS;
8360 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008361 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8362 /* more ops could be optimized too */
8363 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8364 }
Owen Taylor3473f882001-02-23 17:55:21 +00008365}
8366
8367/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008368 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008369 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008370 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008371 *
8372 * [8] Predicate ::= '[' PredicateExpr ']'
8373 * [9] PredicateExpr ::= Expr
8374 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008375 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008376 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008377static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008378xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008379 int op1 = ctxt->comp->last;
8380
8381 SKIP_BLANKS;
8382 if (CUR != '[') {
8383 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8384 }
8385 NEXT;
8386 SKIP_BLANKS;
8387
8388 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008389 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008390 CHECK_ERROR;
8391
8392 if (CUR != ']') {
8393 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8394 }
8395
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008396 if (filter)
8397 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8398 else
8399 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008400
8401 NEXT;
8402 SKIP_BLANKS;
8403}
8404
8405/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008406 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008407 * @ctxt: the XPath Parser context
8408 * @test: pointer to a xmlXPathTestVal
8409 * @type: pointer to a xmlXPathTypeVal
8410 * @prefix: placeholder for a possible name prefix
8411 *
8412 * [7] NodeTest ::= NameTest
8413 * | NodeType '(' ')'
8414 * | 'processing-instruction' '(' Literal ')'
8415 *
8416 * [37] NameTest ::= '*'
8417 * | NCName ':' '*'
8418 * | QName
8419 * [38] NodeType ::= 'comment'
8420 * | 'text'
8421 * | 'processing-instruction'
8422 * | 'node'
8423 *
8424 * Returns the name found and update @test, @type and @prefix appropriately
8425 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008426static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008427xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8428 xmlXPathTypeVal *type, const xmlChar **prefix,
8429 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008430 int blanks;
8431
8432 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8433 STRANGE;
8434 return(NULL);
8435 }
William M. Brack78637da2003-07-31 14:47:38 +00008436 *type = (xmlXPathTypeVal) 0;
8437 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008438 *prefix = NULL;
8439 SKIP_BLANKS;
8440
8441 if ((name == NULL) && (CUR == '*')) {
8442 /*
8443 * All elements
8444 */
8445 NEXT;
8446 *test = NODE_TEST_ALL;
8447 return(NULL);
8448 }
8449
8450 if (name == NULL)
8451 name = xmlXPathParseNCName(ctxt);
8452 if (name == NULL) {
8453 XP_ERROR0(XPATH_EXPR_ERROR);
8454 }
8455
William M. Brack76e95df2003-10-18 16:20:14 +00008456 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008457 SKIP_BLANKS;
8458 if (CUR == '(') {
8459 NEXT;
8460 /*
8461 * NodeType or PI search
8462 */
8463 if (xmlStrEqual(name, BAD_CAST "comment"))
8464 *type = NODE_TYPE_COMMENT;
8465 else if (xmlStrEqual(name, BAD_CAST "node"))
8466 *type = NODE_TYPE_NODE;
8467 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8468 *type = NODE_TYPE_PI;
8469 else if (xmlStrEqual(name, BAD_CAST "text"))
8470 *type = NODE_TYPE_TEXT;
8471 else {
8472 if (name != NULL)
8473 xmlFree(name);
8474 XP_ERROR0(XPATH_EXPR_ERROR);
8475 }
8476
8477 *test = NODE_TEST_TYPE;
8478
8479 SKIP_BLANKS;
8480 if (*type == NODE_TYPE_PI) {
8481 /*
8482 * Specific case: search a PI by name.
8483 */
Owen Taylor3473f882001-02-23 17:55:21 +00008484 if (name != NULL)
8485 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008486 name = NULL;
8487 if (CUR != ')') {
8488 name = xmlXPathParseLiteral(ctxt);
8489 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008490 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008491 SKIP_BLANKS;
8492 }
Owen Taylor3473f882001-02-23 17:55:21 +00008493 }
8494 if (CUR != ')') {
8495 if (name != NULL)
8496 xmlFree(name);
8497 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8498 }
8499 NEXT;
8500 return(name);
8501 }
8502 *test = NODE_TEST_NAME;
8503 if ((!blanks) && (CUR == ':')) {
8504 NEXT;
8505
8506 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008507 * Since currently the parser context don't have a
8508 * namespace list associated:
8509 * The namespace name for this prefix can be computed
8510 * only at evaluation time. The compilation is done
8511 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008512 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008513#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008514 *prefix = xmlXPathNsLookup(ctxt->context, name);
8515 if (name != NULL)
8516 xmlFree(name);
8517 if (*prefix == NULL) {
8518 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8519 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008520#else
8521 *prefix = name;
8522#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008523
8524 if (CUR == '*') {
8525 /*
8526 * All elements
8527 */
8528 NEXT;
8529 *test = NODE_TEST_ALL;
8530 return(NULL);
8531 }
8532
8533 name = xmlXPathParseNCName(ctxt);
8534 if (name == NULL) {
8535 XP_ERROR0(XPATH_EXPR_ERROR);
8536 }
8537 }
8538 return(name);
8539}
8540
8541/**
8542 * xmlXPathIsAxisName:
8543 * @name: a preparsed name token
8544 *
8545 * [6] AxisName ::= 'ancestor'
8546 * | 'ancestor-or-self'
8547 * | 'attribute'
8548 * | 'child'
8549 * | 'descendant'
8550 * | 'descendant-or-self'
8551 * | 'following'
8552 * | 'following-sibling'
8553 * | 'namespace'
8554 * | 'parent'
8555 * | 'preceding'
8556 * | 'preceding-sibling'
8557 * | 'self'
8558 *
8559 * Returns the axis or 0
8560 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008561static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008562xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008563 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008564 switch (name[0]) {
8565 case 'a':
8566 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8567 ret = AXIS_ANCESTOR;
8568 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8569 ret = AXIS_ANCESTOR_OR_SELF;
8570 if (xmlStrEqual(name, BAD_CAST "attribute"))
8571 ret = AXIS_ATTRIBUTE;
8572 break;
8573 case 'c':
8574 if (xmlStrEqual(name, BAD_CAST "child"))
8575 ret = AXIS_CHILD;
8576 break;
8577 case 'd':
8578 if (xmlStrEqual(name, BAD_CAST "descendant"))
8579 ret = AXIS_DESCENDANT;
8580 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8581 ret = AXIS_DESCENDANT_OR_SELF;
8582 break;
8583 case 'f':
8584 if (xmlStrEqual(name, BAD_CAST "following"))
8585 ret = AXIS_FOLLOWING;
8586 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8587 ret = AXIS_FOLLOWING_SIBLING;
8588 break;
8589 case 'n':
8590 if (xmlStrEqual(name, BAD_CAST "namespace"))
8591 ret = AXIS_NAMESPACE;
8592 break;
8593 case 'p':
8594 if (xmlStrEqual(name, BAD_CAST "parent"))
8595 ret = AXIS_PARENT;
8596 if (xmlStrEqual(name, BAD_CAST "preceding"))
8597 ret = AXIS_PRECEDING;
8598 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8599 ret = AXIS_PRECEDING_SIBLING;
8600 break;
8601 case 's':
8602 if (xmlStrEqual(name, BAD_CAST "self"))
8603 ret = AXIS_SELF;
8604 break;
8605 }
8606 return(ret);
8607}
8608
8609/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008610 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008611 * @ctxt: the XPath Parser context
8612 *
8613 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8614 * | AbbreviatedStep
8615 *
8616 * [12] AbbreviatedStep ::= '.' | '..'
8617 *
8618 * [5] AxisSpecifier ::= AxisName '::'
8619 * | AbbreviatedAxisSpecifier
8620 *
8621 * [13] AbbreviatedAxisSpecifier ::= '@'?
8622 *
8623 * Modified for XPtr range support as:
8624 *
8625 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8626 * | AbbreviatedStep
8627 * | 'range-to' '(' Expr ')' Predicate*
8628 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008629 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008630 * A location step of . is short for self::node(). This is
8631 * particularly useful in conjunction with //. For example, the
8632 * location path .//para is short for
8633 * self::node()/descendant-or-self::node()/child::para
8634 * and so will select all para descendant elements of the context
8635 * node.
8636 * Similarly, a location step of .. is short for parent::node().
8637 * For example, ../title is short for parent::node()/child::title
8638 * and so will select the title children of the parent of the context
8639 * node.
8640 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008641static void
8642xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008643#ifdef LIBXML_XPTR_ENABLED
8644 int rangeto = 0;
8645 int op2 = -1;
8646#endif
8647
Owen Taylor3473f882001-02-23 17:55:21 +00008648 SKIP_BLANKS;
8649 if ((CUR == '.') && (NXT(1) == '.')) {
8650 SKIP(2);
8651 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008652 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8653 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008654 } else if (CUR == '.') {
8655 NEXT;
8656 SKIP_BLANKS;
8657 } else {
8658 xmlChar *name = NULL;
8659 const xmlChar *prefix = NULL;
8660 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008661 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008662 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008663 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008664
8665 /*
8666 * The modification needed for XPointer change to the production
8667 */
8668#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008669 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008670 name = xmlXPathParseNCName(ctxt);
8671 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008672 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008673 xmlFree(name);
8674 SKIP_BLANKS;
8675 if (CUR != '(') {
8676 XP_ERROR(XPATH_EXPR_ERROR);
8677 }
8678 NEXT;
8679 SKIP_BLANKS;
8680
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008681 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008682 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008683 CHECK_ERROR;
8684
8685 SKIP_BLANKS;
8686 if (CUR != ')') {
8687 XP_ERROR(XPATH_EXPR_ERROR);
8688 }
8689 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008690 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008691 goto eval_predicates;
8692 }
8693 }
8694#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008695 if (CUR == '*') {
8696 axis = AXIS_CHILD;
8697 } else {
8698 if (name == NULL)
8699 name = xmlXPathParseNCName(ctxt);
8700 if (name != NULL) {
8701 axis = xmlXPathIsAxisName(name);
8702 if (axis != 0) {
8703 SKIP_BLANKS;
8704 if ((CUR == ':') && (NXT(1) == ':')) {
8705 SKIP(2);
8706 xmlFree(name);
8707 name = NULL;
8708 } else {
8709 /* an element name can conflict with an axis one :-\ */
8710 axis = AXIS_CHILD;
8711 }
Owen Taylor3473f882001-02-23 17:55:21 +00008712 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008713 axis = AXIS_CHILD;
8714 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008715 } else if (CUR == '@') {
8716 NEXT;
8717 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008718 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008719 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008720 }
Owen Taylor3473f882001-02-23 17:55:21 +00008721 }
8722
8723 CHECK_ERROR;
8724
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008725 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008726 if (test == 0)
8727 return;
8728
8729#ifdef DEBUG_STEP
8730 xmlGenericError(xmlGenericErrorContext,
8731 "Basis : computing new set\n");
8732#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008733
Owen Taylor3473f882001-02-23 17:55:21 +00008734#ifdef DEBUG_STEP
8735 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008736 if (ctxt->value == NULL)
8737 xmlGenericError(xmlGenericErrorContext, "no value\n");
8738 else if (ctxt->value->nodesetval == NULL)
8739 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8740 else
8741 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008742#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008743
8744eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008745 op1 = ctxt->comp->last;
8746 ctxt->comp->last = -1;
8747
Owen Taylor3473f882001-02-23 17:55:21 +00008748 SKIP_BLANKS;
8749 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008750 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008751 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008752
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008753#ifdef LIBXML_XPTR_ENABLED
8754 if (rangeto) {
8755 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8756 } else
8757#endif
8758 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8759 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008760
Owen Taylor3473f882001-02-23 17:55:21 +00008761 }
8762#ifdef DEBUG_STEP
8763 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008764 if (ctxt->value == NULL)
8765 xmlGenericError(xmlGenericErrorContext, "no value\n");
8766 else if (ctxt->value->nodesetval == NULL)
8767 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8768 else
8769 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8770 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008771#endif
8772}
8773
8774/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008775 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008776 * @ctxt: the XPath Parser context
8777 *
8778 * [3] RelativeLocationPath ::= Step
8779 * | RelativeLocationPath '/' Step
8780 * | AbbreviatedRelativeLocationPath
8781 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8782 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008783 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008784 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008785static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008786xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008787(xmlXPathParserContextPtr ctxt) {
8788 SKIP_BLANKS;
8789 if ((CUR == '/') && (NXT(1) == '/')) {
8790 SKIP(2);
8791 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008792 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8793 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008794 } else if (CUR == '/') {
8795 NEXT;
8796 SKIP_BLANKS;
8797 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008798 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008799 SKIP_BLANKS;
8800 while (CUR == '/') {
8801 if ((CUR == '/') && (NXT(1) == '/')) {
8802 SKIP(2);
8803 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008804 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008805 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008806 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008807 } else if (CUR == '/') {
8808 NEXT;
8809 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008810 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008811 }
8812 SKIP_BLANKS;
8813 }
8814}
8815
8816/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008817 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008818 * @ctxt: the XPath Parser context
8819 *
8820 * [1] LocationPath ::= RelativeLocationPath
8821 * | AbsoluteLocationPath
8822 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8823 * | AbbreviatedAbsoluteLocationPath
8824 * [10] AbbreviatedAbsoluteLocationPath ::=
8825 * '//' RelativeLocationPath
8826 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008827 * Compile a location path
8828 *
Owen Taylor3473f882001-02-23 17:55:21 +00008829 * // is short for /descendant-or-self::node()/. For example,
8830 * //para is short for /descendant-or-self::node()/child::para and
8831 * so will select any para element in the document (even a para element
8832 * that is a document element will be selected by //para since the
8833 * document element node is a child of the root node); div//para is
8834 * short for div/descendant-or-self::node()/child::para and so will
8835 * select all para descendants of div children.
8836 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008837static void
8838xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008839 SKIP_BLANKS;
8840 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008841 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008842 } else {
8843 while (CUR == '/') {
8844 if ((CUR == '/') && (NXT(1) == '/')) {
8845 SKIP(2);
8846 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008847 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8848 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008849 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008850 } else if (CUR == '/') {
8851 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008852 SKIP_BLANKS;
8853 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008854 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008855 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008856 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008857 }
8858 }
8859 }
8860}
8861
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008862/************************************************************************
8863 * *
8864 * XPath precompiled expression evaluation *
8865 * *
8866 ************************************************************************/
8867
Daniel Veillardf06307e2001-07-03 10:35:50 +00008868static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008869xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8870
8871/**
8872 * xmlXPathNodeCollectAndTest:
8873 * @ctxt: the XPath Parser context
8874 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 * @first: pointer to the first element in document order
8876 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008877 *
8878 * This is the function implementing a step: based on the current list
8879 * of nodes, it builds up a new list, looking at all nodes under that
8880 * axis and selecting them it also do the predicate filtering
8881 *
8882 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008883 *
8884 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008885 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008886static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008887xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008888 xmlXPathStepOpPtr op,
8889 xmlNodePtr * first, xmlNodePtr * last)
8890{
William M. Brack78637da2003-07-31 14:47:38 +00008891 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8892 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8893 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008894 const xmlChar *prefix = op->value4;
8895 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008896 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008897
8898#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008899 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008900#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008901 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008902 xmlNodeSetPtr ret, list;
8903 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008904 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008905 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008906 xmlNodePtr cur = NULL;
8907 xmlXPathObjectPtr obj;
8908 xmlNodeSetPtr nodelist;
8909 xmlNodePtr tmp;
8910
Daniel Veillardf06307e2001-07-03 10:35:50 +00008911 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008912 obj = valuePop(ctxt);
8913 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008914 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008915 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008916 URI = xmlXPathNsLookup(ctxt->context, prefix);
8917 if (URI == NULL)
8918 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008919 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008920#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008921 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008922#endif
8923 switch (axis) {
8924 case AXIS_ANCESTOR:
8925#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008926 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008927#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008928 first = NULL;
8929 next = xmlXPathNextAncestor;
8930 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008931 case AXIS_ANCESTOR_OR_SELF:
8932#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008933 xmlGenericError(xmlGenericErrorContext,
8934 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008935#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008936 first = NULL;
8937 next = xmlXPathNextAncestorOrSelf;
8938 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008939 case AXIS_ATTRIBUTE:
8940#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008941 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008942#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008943 first = NULL;
8944 last = NULL;
8945 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008946 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008947 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008948 case AXIS_CHILD:
8949#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008950 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008951#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008952 last = NULL;
8953 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008954 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008956 case AXIS_DESCENDANT:
8957#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008958 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008959#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008960 last = NULL;
8961 next = xmlXPathNextDescendant;
8962 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008963 case AXIS_DESCENDANT_OR_SELF:
8964#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008965 xmlGenericError(xmlGenericErrorContext,
8966 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008967#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008968 last = NULL;
8969 next = xmlXPathNextDescendantOrSelf;
8970 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008971 case AXIS_FOLLOWING:
8972#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008973 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008974#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975 last = NULL;
8976 next = xmlXPathNextFollowing;
8977 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008978 case AXIS_FOLLOWING_SIBLING:
8979#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 xmlGenericError(xmlGenericErrorContext,
8981 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008982#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008983 last = NULL;
8984 next = xmlXPathNextFollowingSibling;
8985 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008986 case AXIS_NAMESPACE:
8987#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008988 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008989#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 first = NULL;
8991 last = NULL;
8992 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008993 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008994 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008995 case AXIS_PARENT:
8996#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008997 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008998#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008999 first = NULL;
9000 next = xmlXPathNextParent;
9001 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009002 case AXIS_PRECEDING:
9003#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009004 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009005#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009006 first = NULL;
9007 next = xmlXPathNextPrecedingInternal;
9008 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009009 case AXIS_PRECEDING_SIBLING:
9010#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011 xmlGenericError(xmlGenericErrorContext,
9012 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009013#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009014 first = NULL;
9015 next = xmlXPathNextPrecedingSibling;
9016 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009017 case AXIS_SELF:
9018#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009019 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009020#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009021 first = NULL;
9022 last = NULL;
9023 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009024 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009025 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009026 }
9027 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009029
9030 nodelist = obj->nodesetval;
9031 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009032 xmlXPathFreeObject(obj);
9033 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9034 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009035 }
9036 addNode = xmlXPathNodeSetAddUnique;
9037 ret = NULL;
9038#ifdef DEBUG_STEP
9039 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009040 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009041 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009042 case NODE_TEST_NONE:
9043 xmlGenericError(xmlGenericErrorContext,
9044 " searching for none !!!\n");
9045 break;
9046 case NODE_TEST_TYPE:
9047 xmlGenericError(xmlGenericErrorContext,
9048 " searching for type %d\n", type);
9049 break;
9050 case NODE_TEST_PI:
9051 xmlGenericError(xmlGenericErrorContext,
9052 " searching for PI !!!\n");
9053 break;
9054 case NODE_TEST_ALL:
9055 xmlGenericError(xmlGenericErrorContext,
9056 " searching for *\n");
9057 break;
9058 case NODE_TEST_NS:
9059 xmlGenericError(xmlGenericErrorContext,
9060 " searching for namespace %s\n",
9061 prefix);
9062 break;
9063 case NODE_TEST_NAME:
9064 xmlGenericError(xmlGenericErrorContext,
9065 " searching for name %s\n", name);
9066 if (prefix != NULL)
9067 xmlGenericError(xmlGenericErrorContext,
9068 " with namespace %s\n", prefix);
9069 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009070 }
9071 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9072#endif
9073 /*
9074 * 2.3 Node Tests
9075 * - For the attribute axis, the principal node type is attribute.
9076 * - For the namespace axis, the principal node type is namespace.
9077 * - For other axes, the principal node type is element.
9078 *
9079 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009080 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009081 * select all element children of the context node
9082 */
9083 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009085 ctxt->context->node = nodelist->nodeTab[i];
9086
Daniel Veillardf06307e2001-07-03 10:35:50 +00009087 cur = NULL;
9088 list = xmlXPathNodeSetCreate(NULL);
9089 do {
9090 cur = next(ctxt, cur);
9091 if (cur == NULL)
9092 break;
9093 if ((first != NULL) && (*first == cur))
9094 break;
9095 if (((t % 256) == 0) &&
9096 (first != NULL) && (*first != NULL) &&
9097 (xmlXPathCmpNodes(*first, cur) >= 0))
9098 break;
9099 if ((last != NULL) && (*last == cur))
9100 break;
9101 if (((t % 256) == 0) &&
9102 (last != NULL) && (*last != NULL) &&
9103 (xmlXPathCmpNodes(cur, *last) >= 0))
9104 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009105 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009106#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009107 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9108#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009109 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009110 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111 ctxt->context->node = tmp;
9112 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009113 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 if ((cur->type == type) ||
9115 ((type == NODE_TYPE_NODE) &&
9116 ((cur->type == XML_DOCUMENT_NODE) ||
9117 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9118 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009119 (cur->type == XML_NAMESPACE_DECL) ||
9120 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 (cur->type == XML_PI_NODE) ||
9122 (cur->type == XML_COMMENT_NODE) ||
9123 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009124 (cur->type == XML_TEXT_NODE))) ||
9125 ((type == NODE_TYPE_TEXT) &&
9126 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009127#ifdef DEBUG_STEP
9128 n++;
9129#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009130 addNode(list, cur);
9131 }
9132 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009133 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 if (cur->type == XML_PI_NODE) {
9135 if ((name != NULL) &&
9136 (!xmlStrEqual(name, cur->name)))
9137 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009138#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009140#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 addNode(list, cur);
9142 }
9143 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009144 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009145 if (axis == AXIS_ATTRIBUTE) {
9146 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009147#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009149#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009150 addNode(list, cur);
9151 }
9152 } else if (axis == AXIS_NAMESPACE) {
9153 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009154#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009155 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009156#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009157 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9158 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009159 }
9160 } else {
9161 if (cur->type == XML_ELEMENT_NODE) {
9162 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009163#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009164 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009165#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009166 addNode(list, cur);
9167 } else if ((cur->ns != NULL) &&
9168 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009169#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009170 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009171#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009172 addNode(list, cur);
9173 }
9174 }
9175 }
9176 break;
9177 case NODE_TEST_NS:{
9178 TODO;
9179 break;
9180 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009181 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009182 switch (cur->type) {
9183 case XML_ELEMENT_NODE:
9184 if (xmlStrEqual(name, cur->name)) {
9185 if (prefix == NULL) {
9186 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009187#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009188 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009189#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009190 addNode(list, cur);
9191 }
9192 } else {
9193 if ((cur->ns != NULL) &&
9194 (xmlStrEqual(URI,
9195 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009196#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009197 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009198#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009199 addNode(list, cur);
9200 }
9201 }
9202 }
9203 break;
9204 case XML_ATTRIBUTE_NODE:{
9205 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009206
Daniel Veillardf06307e2001-07-03 10:35:50 +00009207 if (xmlStrEqual(name, attr->name)) {
9208 if (prefix == NULL) {
9209 if ((attr->ns == NULL) ||
9210 (attr->ns->prefix == NULL)) {
9211#ifdef DEBUG_STEP
9212 n++;
9213#endif
9214 addNode(list,
9215 (xmlNodePtr) attr);
9216 }
9217 } else {
9218 if ((attr->ns != NULL) &&
9219 (xmlStrEqual(URI,
9220 attr->ns->
9221 href))) {
9222#ifdef DEBUG_STEP
9223 n++;
9224#endif
9225 addNode(list,
9226 (xmlNodePtr) attr);
9227 }
9228 }
9229 }
9230 break;
9231 }
9232 case XML_NAMESPACE_DECL:
9233 if (cur->type == XML_NAMESPACE_DECL) {
9234 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009235
Daniel Veillardf06307e2001-07-03 10:35:50 +00009236 if ((ns->prefix != NULL) && (name != NULL)
9237 && (xmlStrEqual(ns->prefix, name))) {
9238#ifdef DEBUG_STEP
9239 n++;
9240#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009241 xmlXPathNodeSetAddNs(list,
9242 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009243 }
9244 }
9245 break;
9246 default:
9247 break;
9248 }
9249 break;
9250 break;
9251 }
9252 } while (cur != NULL);
9253
9254 /*
9255 * If there is some predicate filtering do it now
9256 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009257 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009258 xmlXPathObjectPtr obj2;
9259
9260 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9261 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9262 CHECK_TYPE0(XPATH_NODESET);
9263 obj2 = valuePop(ctxt);
9264 list = obj2->nodesetval;
9265 obj2->nodesetval = NULL;
9266 xmlXPathFreeObject(obj2);
9267 }
9268 if (ret == NULL) {
9269 ret = list;
9270 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009271 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009272 xmlXPathFreeNodeSet(list);
9273 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009274 }
9275 ctxt->context->node = tmp;
9276#ifdef DEBUG_STEP
9277 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009278 "\nExamined %d nodes, found %d nodes at that step\n",
9279 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009280#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009281 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009282 if ((obj->boolval) && (obj->user != NULL)) {
9283 ctxt->value->boolval = 1;
9284 ctxt->value->user = obj->user;
9285 obj->user = NULL;
9286 obj->boolval = 0;
9287 }
9288 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009289 return(t);
9290}
9291
9292/**
9293 * xmlXPathNodeCollectAndTestNth:
9294 * @ctxt: the XPath Parser context
9295 * @op: the XPath precompiled step operation
9296 * @indx: the index to collect
9297 * @first: pointer to the first element in document order
9298 * @last: pointer to the last element in document order
9299 *
9300 * This is the function implementing a step: based on the current list
9301 * of nodes, it builds up a new list, looking at all nodes under that
9302 * axis and selecting them it also do the predicate filtering
9303 *
9304 * Pushes the new NodeSet resulting from the search.
9305 * Returns the number of node traversed
9306 */
9307static int
9308xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9309 xmlXPathStepOpPtr op, int indx,
9310 xmlNodePtr * first, xmlNodePtr * last)
9311{
William M. Brack78637da2003-07-31 14:47:38 +00009312 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9313 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9314 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009315 const xmlChar *prefix = op->value4;
9316 const xmlChar *name = op->value5;
9317 const xmlChar *URI = NULL;
9318 int n = 0, t = 0;
9319
9320 int i;
9321 xmlNodeSetPtr list;
9322 xmlXPathTraversalFunction next = NULL;
9323 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9324 xmlNodePtr cur = NULL;
9325 xmlXPathObjectPtr obj;
9326 xmlNodeSetPtr nodelist;
9327 xmlNodePtr tmp;
9328
9329 CHECK_TYPE0(XPATH_NODESET);
9330 obj = valuePop(ctxt);
9331 addNode = xmlXPathNodeSetAdd;
9332 if (prefix != NULL) {
9333 URI = xmlXPathNsLookup(ctxt->context, prefix);
9334 if (URI == NULL)
9335 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9336 }
9337#ifdef DEBUG_STEP_NTH
9338 xmlGenericError(xmlGenericErrorContext, "new step : ");
9339 if (first != NULL) {
9340 if (*first != NULL)
9341 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9342 (*first)->name);
9343 else
9344 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9345 }
9346 if (last != NULL) {
9347 if (*last != NULL)
9348 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9349 (*last)->name);
9350 else
9351 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9352 }
9353#endif
9354 switch (axis) {
9355 case AXIS_ANCESTOR:
9356#ifdef DEBUG_STEP_NTH
9357 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9358#endif
9359 first = NULL;
9360 next = xmlXPathNextAncestor;
9361 break;
9362 case AXIS_ANCESTOR_OR_SELF:
9363#ifdef DEBUG_STEP_NTH
9364 xmlGenericError(xmlGenericErrorContext,
9365 "axis 'ancestors-or-self' ");
9366#endif
9367 first = NULL;
9368 next = xmlXPathNextAncestorOrSelf;
9369 break;
9370 case AXIS_ATTRIBUTE:
9371#ifdef DEBUG_STEP_NTH
9372 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9373#endif
9374 first = NULL;
9375 last = NULL;
9376 next = xmlXPathNextAttribute;
9377 break;
9378 case AXIS_CHILD:
9379#ifdef DEBUG_STEP_NTH
9380 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9381#endif
9382 last = NULL;
9383 next = xmlXPathNextChild;
9384 break;
9385 case AXIS_DESCENDANT:
9386#ifdef DEBUG_STEP_NTH
9387 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9388#endif
9389 last = NULL;
9390 next = xmlXPathNextDescendant;
9391 break;
9392 case AXIS_DESCENDANT_OR_SELF:
9393#ifdef DEBUG_STEP_NTH
9394 xmlGenericError(xmlGenericErrorContext,
9395 "axis 'descendant-or-self' ");
9396#endif
9397 last = NULL;
9398 next = xmlXPathNextDescendantOrSelf;
9399 break;
9400 case AXIS_FOLLOWING:
9401#ifdef DEBUG_STEP_NTH
9402 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9403#endif
9404 last = NULL;
9405 next = xmlXPathNextFollowing;
9406 break;
9407 case AXIS_FOLLOWING_SIBLING:
9408#ifdef DEBUG_STEP_NTH
9409 xmlGenericError(xmlGenericErrorContext,
9410 "axis 'following-siblings' ");
9411#endif
9412 last = NULL;
9413 next = xmlXPathNextFollowingSibling;
9414 break;
9415 case AXIS_NAMESPACE:
9416#ifdef DEBUG_STEP_NTH
9417 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9418#endif
9419 last = NULL;
9420 first = NULL;
9421 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9422 break;
9423 case AXIS_PARENT:
9424#ifdef DEBUG_STEP_NTH
9425 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9426#endif
9427 first = NULL;
9428 next = xmlXPathNextParent;
9429 break;
9430 case AXIS_PRECEDING:
9431#ifdef DEBUG_STEP_NTH
9432 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9433#endif
9434 first = NULL;
9435 next = xmlXPathNextPrecedingInternal;
9436 break;
9437 case AXIS_PRECEDING_SIBLING:
9438#ifdef DEBUG_STEP_NTH
9439 xmlGenericError(xmlGenericErrorContext,
9440 "axis 'preceding-sibling' ");
9441#endif
9442 first = NULL;
9443 next = xmlXPathNextPrecedingSibling;
9444 break;
9445 case AXIS_SELF:
9446#ifdef DEBUG_STEP_NTH
9447 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9448#endif
9449 first = NULL;
9450 last = NULL;
9451 next = xmlXPathNextSelf;
9452 break;
9453 }
9454 if (next == NULL)
9455 return(0);
9456
9457 nodelist = obj->nodesetval;
9458 if (nodelist == NULL) {
9459 xmlXPathFreeObject(obj);
9460 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9461 return(0);
9462 }
9463 addNode = xmlXPathNodeSetAddUnique;
9464#ifdef DEBUG_STEP_NTH
9465 xmlGenericError(xmlGenericErrorContext,
9466 " context contains %d nodes\n", nodelist->nodeNr);
9467 switch (test) {
9468 case NODE_TEST_NONE:
9469 xmlGenericError(xmlGenericErrorContext,
9470 " searching for none !!!\n");
9471 break;
9472 case NODE_TEST_TYPE:
9473 xmlGenericError(xmlGenericErrorContext,
9474 " searching for type %d\n", type);
9475 break;
9476 case NODE_TEST_PI:
9477 xmlGenericError(xmlGenericErrorContext,
9478 " searching for PI !!!\n");
9479 break;
9480 case NODE_TEST_ALL:
9481 xmlGenericError(xmlGenericErrorContext,
9482 " searching for *\n");
9483 break;
9484 case NODE_TEST_NS:
9485 xmlGenericError(xmlGenericErrorContext,
9486 " searching for namespace %s\n",
9487 prefix);
9488 break;
9489 case NODE_TEST_NAME:
9490 xmlGenericError(xmlGenericErrorContext,
9491 " searching for name %s\n", name);
9492 if (prefix != NULL)
9493 xmlGenericError(xmlGenericErrorContext,
9494 " with namespace %s\n", prefix);
9495 break;
9496 }
9497 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9498#endif
9499 /*
9500 * 2.3 Node Tests
9501 * - For the attribute axis, the principal node type is attribute.
9502 * - For the namespace axis, the principal node type is namespace.
9503 * - For other axes, the principal node type is element.
9504 *
9505 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009506 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009507 * select all element children of the context node
9508 */
9509 tmp = ctxt->context->node;
9510 list = xmlXPathNodeSetCreate(NULL);
9511 for (i = 0; i < nodelist->nodeNr; i++) {
9512 ctxt->context->node = nodelist->nodeTab[i];
9513
9514 cur = NULL;
9515 n = 0;
9516 do {
9517 cur = next(ctxt, cur);
9518 if (cur == NULL)
9519 break;
9520 if ((first != NULL) && (*first == cur))
9521 break;
9522 if (((t % 256) == 0) &&
9523 (first != NULL) && (*first != NULL) &&
9524 (xmlXPathCmpNodes(*first, cur) >= 0))
9525 break;
9526 if ((last != NULL) && (*last == cur))
9527 break;
9528 if (((t % 256) == 0) &&
9529 (last != NULL) && (*last != NULL) &&
9530 (xmlXPathCmpNodes(cur, *last) >= 0))
9531 break;
9532 t++;
9533 switch (test) {
9534 case NODE_TEST_NONE:
9535 ctxt->context->node = tmp;
9536 STRANGE return(0);
9537 case NODE_TEST_TYPE:
9538 if ((cur->type == type) ||
9539 ((type == NODE_TYPE_NODE) &&
9540 ((cur->type == XML_DOCUMENT_NODE) ||
9541 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9542 (cur->type == XML_ELEMENT_NODE) ||
9543 (cur->type == XML_PI_NODE) ||
9544 (cur->type == XML_COMMENT_NODE) ||
9545 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009546 (cur->type == XML_TEXT_NODE))) ||
9547 ((type == NODE_TYPE_TEXT) &&
9548 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009549 n++;
9550 if (n == indx)
9551 addNode(list, cur);
9552 }
9553 break;
9554 case NODE_TEST_PI:
9555 if (cur->type == XML_PI_NODE) {
9556 if ((name != NULL) &&
9557 (!xmlStrEqual(name, cur->name)))
9558 break;
9559 n++;
9560 if (n == indx)
9561 addNode(list, cur);
9562 }
9563 break;
9564 case NODE_TEST_ALL:
9565 if (axis == AXIS_ATTRIBUTE) {
9566 if (cur->type == XML_ATTRIBUTE_NODE) {
9567 n++;
9568 if (n == indx)
9569 addNode(list, cur);
9570 }
9571 } else if (axis == AXIS_NAMESPACE) {
9572 if (cur->type == XML_NAMESPACE_DECL) {
9573 n++;
9574 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009575 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9576 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009577 }
9578 } else {
9579 if (cur->type == XML_ELEMENT_NODE) {
9580 if (prefix == NULL) {
9581 n++;
9582 if (n == indx)
9583 addNode(list, cur);
9584 } else if ((cur->ns != NULL) &&
9585 (xmlStrEqual(URI, cur->ns->href))) {
9586 n++;
9587 if (n == indx)
9588 addNode(list, cur);
9589 }
9590 }
9591 }
9592 break;
9593 case NODE_TEST_NS:{
9594 TODO;
9595 break;
9596 }
9597 case NODE_TEST_NAME:
9598 switch (cur->type) {
9599 case XML_ELEMENT_NODE:
9600 if (xmlStrEqual(name, cur->name)) {
9601 if (prefix == NULL) {
9602 if (cur->ns == NULL) {
9603 n++;
9604 if (n == indx)
9605 addNode(list, cur);
9606 }
9607 } else {
9608 if ((cur->ns != NULL) &&
9609 (xmlStrEqual(URI,
9610 cur->ns->href))) {
9611 n++;
9612 if (n == indx)
9613 addNode(list, cur);
9614 }
9615 }
9616 }
9617 break;
9618 case XML_ATTRIBUTE_NODE:{
9619 xmlAttrPtr attr = (xmlAttrPtr) cur;
9620
9621 if (xmlStrEqual(name, attr->name)) {
9622 if (prefix == NULL) {
9623 if ((attr->ns == NULL) ||
9624 (attr->ns->prefix == NULL)) {
9625 n++;
9626 if (n == indx)
9627 addNode(list, cur);
9628 }
9629 } else {
9630 if ((attr->ns != NULL) &&
9631 (xmlStrEqual(URI,
9632 attr->ns->
9633 href))) {
9634 n++;
9635 if (n == indx)
9636 addNode(list, cur);
9637 }
9638 }
9639 }
9640 break;
9641 }
9642 case XML_NAMESPACE_DECL:
9643 if (cur->type == XML_NAMESPACE_DECL) {
9644 xmlNsPtr ns = (xmlNsPtr) cur;
9645
9646 if ((ns->prefix != NULL) && (name != NULL)
9647 && (xmlStrEqual(ns->prefix, name))) {
9648 n++;
9649 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009650 xmlXPathNodeSetAddNs(list,
9651 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009652 }
9653 }
9654 break;
9655 default:
9656 break;
9657 }
9658 break;
9659 break;
9660 }
9661 } while (n < indx);
9662 }
9663 ctxt->context->node = tmp;
9664#ifdef DEBUG_STEP_NTH
9665 xmlGenericError(xmlGenericErrorContext,
9666 "\nExamined %d nodes, found %d nodes at that step\n",
9667 t, list->nodeNr);
9668#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009669 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009670 if ((obj->boolval) && (obj->user != NULL)) {
9671 ctxt->value->boolval = 1;
9672 ctxt->value->user = obj->user;
9673 obj->user = NULL;
9674 obj->boolval = 0;
9675 }
9676 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009677 return(t);
9678}
9679
9680/**
9681 * xmlXPathCompOpEvalFirst:
9682 * @ctxt: the XPath parser context with the compiled expression
9683 * @op: an XPath compiled operation
9684 * @first: the first elem found so far
9685 *
9686 * Evaluate the Precompiled XPath operation searching only the first
9687 * element in document order
9688 *
9689 * Returns the number of examined objects.
9690 */
9691static int
9692xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9693 xmlXPathStepOpPtr op, xmlNodePtr * first)
9694{
9695 int total = 0, cur;
9696 xmlXPathCompExprPtr comp;
9697 xmlXPathObjectPtr arg1, arg2;
9698
Daniel Veillard556c6682001-10-06 09:59:51 +00009699 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009700 comp = ctxt->comp;
9701 switch (op->op) {
9702 case XPATH_OP_END:
9703 return (0);
9704 case XPATH_OP_UNION:
9705 total =
9706 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9707 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009708 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009709 if ((ctxt->value != NULL)
9710 && (ctxt->value->type == XPATH_NODESET)
9711 && (ctxt->value->nodesetval != NULL)
9712 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9713 /*
9714 * limit tree traversing to first node in the result
9715 */
9716 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9717 *first = ctxt->value->nodesetval->nodeTab[0];
9718 }
9719 cur =
9720 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9721 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009722 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009723 CHECK_TYPE0(XPATH_NODESET);
9724 arg2 = valuePop(ctxt);
9725
9726 CHECK_TYPE0(XPATH_NODESET);
9727 arg1 = valuePop(ctxt);
9728
9729 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9730 arg2->nodesetval);
9731 valuePush(ctxt, arg1);
9732 xmlXPathFreeObject(arg2);
9733 /* optimizer */
9734 if (total > cur)
9735 xmlXPathCompSwap(op);
9736 return (total + cur);
9737 case XPATH_OP_ROOT:
9738 xmlXPathRoot(ctxt);
9739 return (0);
9740 case XPATH_OP_NODE:
9741 if (op->ch1 != -1)
9742 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009743 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009744 if (op->ch2 != -1)
9745 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009746 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009747 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9748 return (total);
9749 case XPATH_OP_RESET:
9750 if (op->ch1 != -1)
9751 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009752 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009753 if (op->ch2 != -1)
9754 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009755 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009756 ctxt->context->node = NULL;
9757 return (total);
9758 case XPATH_OP_COLLECT:{
9759 if (op->ch1 == -1)
9760 return (total);
9761
9762 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009763 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009764
9765 /*
9766 * Optimization for [n] selection where n is a number
9767 */
9768 if ((op->ch2 != -1) &&
9769 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9770 (comp->steps[op->ch2].ch1 == -1) &&
9771 (comp->steps[op->ch2].ch2 != -1) &&
9772 (comp->steps[comp->steps[op->ch2].ch2].op ==
9773 XPATH_OP_VALUE)) {
9774 xmlXPathObjectPtr val;
9775
9776 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9777 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9778 int indx = (int) val->floatval;
9779
9780 if (val->floatval == (float) indx) {
9781 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9782 first, NULL);
9783 return (total);
9784 }
9785 }
9786 }
9787 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9788 return (total);
9789 }
9790 case XPATH_OP_VALUE:
9791 valuePush(ctxt,
9792 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9793 return (0);
9794 case XPATH_OP_SORT:
9795 if (op->ch1 != -1)
9796 total +=
9797 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9798 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009799 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009800 if ((ctxt->value != NULL)
9801 && (ctxt->value->type == XPATH_NODESET)
9802 && (ctxt->value->nodesetval != NULL))
9803 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9804 return (total);
9805 default:
9806 return (xmlXPathCompOpEval(ctxt, op));
9807 }
9808}
9809
9810/**
9811 * xmlXPathCompOpEvalLast:
9812 * @ctxt: the XPath parser context with the compiled expression
9813 * @op: an XPath compiled operation
9814 * @last: the last elem found so far
9815 *
9816 * Evaluate the Precompiled XPath operation searching only the last
9817 * element in document order
9818 *
9819 * Returns the number of node traversed
9820 */
9821static int
9822xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9823 xmlNodePtr * last)
9824{
9825 int total = 0, cur;
9826 xmlXPathCompExprPtr comp;
9827 xmlXPathObjectPtr arg1, arg2;
9828
Daniel Veillard556c6682001-10-06 09:59:51 +00009829 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009830 comp = ctxt->comp;
9831 switch (op->op) {
9832 case XPATH_OP_END:
9833 return (0);
9834 case XPATH_OP_UNION:
9835 total =
9836 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009837 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009838 if ((ctxt->value != NULL)
9839 && (ctxt->value->type == XPATH_NODESET)
9840 && (ctxt->value->nodesetval != NULL)
9841 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9842 /*
9843 * limit tree traversing to first node in the result
9844 */
9845 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9846 *last =
9847 ctxt->value->nodesetval->nodeTab[ctxt->value->
9848 nodesetval->nodeNr -
9849 1];
9850 }
9851 cur =
9852 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009853 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009854 if ((ctxt->value != NULL)
9855 && (ctxt->value->type == XPATH_NODESET)
9856 && (ctxt->value->nodesetval != NULL)
9857 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9858 }
9859 CHECK_TYPE0(XPATH_NODESET);
9860 arg2 = valuePop(ctxt);
9861
9862 CHECK_TYPE0(XPATH_NODESET);
9863 arg1 = valuePop(ctxt);
9864
9865 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9866 arg2->nodesetval);
9867 valuePush(ctxt, arg1);
9868 xmlXPathFreeObject(arg2);
9869 /* optimizer */
9870 if (total > cur)
9871 xmlXPathCompSwap(op);
9872 return (total + cur);
9873 case XPATH_OP_ROOT:
9874 xmlXPathRoot(ctxt);
9875 return (0);
9876 case XPATH_OP_NODE:
9877 if (op->ch1 != -1)
9878 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009879 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009880 if (op->ch2 != -1)
9881 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009882 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009883 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9884 return (total);
9885 case XPATH_OP_RESET:
9886 if (op->ch1 != -1)
9887 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009888 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009889 if (op->ch2 != -1)
9890 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009891 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009892 ctxt->context->node = NULL;
9893 return (total);
9894 case XPATH_OP_COLLECT:{
9895 if (op->ch1 == -1)
9896 return (0);
9897
9898 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009899 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009900
9901 /*
9902 * Optimization for [n] selection where n is a number
9903 */
9904 if ((op->ch2 != -1) &&
9905 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9906 (comp->steps[op->ch2].ch1 == -1) &&
9907 (comp->steps[op->ch2].ch2 != -1) &&
9908 (comp->steps[comp->steps[op->ch2].ch2].op ==
9909 XPATH_OP_VALUE)) {
9910 xmlXPathObjectPtr val;
9911
9912 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9913 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9914 int indx = (int) val->floatval;
9915
9916 if (val->floatval == (float) indx) {
9917 total +=
9918 xmlXPathNodeCollectAndTestNth(ctxt, op,
9919 indx, NULL,
9920 last);
9921 return (total);
9922 }
9923 }
9924 }
9925 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9926 return (total);
9927 }
9928 case XPATH_OP_VALUE:
9929 valuePush(ctxt,
9930 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9931 return (0);
9932 case XPATH_OP_SORT:
9933 if (op->ch1 != -1)
9934 total +=
9935 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9936 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009937 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009938 if ((ctxt->value != NULL)
9939 && (ctxt->value->type == XPATH_NODESET)
9940 && (ctxt->value->nodesetval != NULL))
9941 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9942 return (total);
9943 default:
9944 return (xmlXPathCompOpEval(ctxt, op));
9945 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009946}
9947
Owen Taylor3473f882001-02-23 17:55:21 +00009948/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009949 * xmlXPathCompOpEval:
9950 * @ctxt: the XPath parser context with the compiled expression
9951 * @op: an XPath compiled operation
9952 *
9953 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009954 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009955 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009956static int
9957xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9958{
9959 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009960 int equal, ret;
9961 xmlXPathCompExprPtr comp;
9962 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009963 xmlNodePtr bak;
9964 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009965 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009966 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009967
Daniel Veillard556c6682001-10-06 09:59:51 +00009968 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009969 comp = ctxt->comp;
9970 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009971 case XPATH_OP_END:
9972 return (0);
9973 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009974 bakd = ctxt->context->doc;
9975 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009976 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009977 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009978 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009979 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980 xmlXPathBooleanFunction(ctxt, 1);
9981 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9982 return (total);
9983 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009984 ctxt->context->doc = bakd;
9985 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009986 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009987 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009988 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009989 if (ctxt->error) {
9990 xmlXPathFreeObject(arg2);
9991 return(0);
9992 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009993 xmlXPathBooleanFunction(ctxt, 1);
9994 arg1 = valuePop(ctxt);
9995 arg1->boolval &= arg2->boolval;
9996 valuePush(ctxt, arg1);
9997 xmlXPathFreeObject(arg2);
9998 return (total);
9999 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010000 bakd = ctxt->context->doc;
10001 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010002 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010003 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010004 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010005 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010006 xmlXPathBooleanFunction(ctxt, 1);
10007 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10008 return (total);
10009 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010010 ctxt->context->doc = bakd;
10011 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010012 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010013 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010014 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010015 if (ctxt->error) {
10016 xmlXPathFreeObject(arg2);
10017 return(0);
10018 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010019 xmlXPathBooleanFunction(ctxt, 1);
10020 arg1 = valuePop(ctxt);
10021 arg1->boolval |= arg2->boolval;
10022 valuePush(ctxt, arg1);
10023 xmlXPathFreeObject(arg2);
10024 return (total);
10025 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010026 bakd = ctxt->context->doc;
10027 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010028 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010029 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010030 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010031 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010032 ctxt->context->doc = bakd;
10033 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010034 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010035 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010036 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010037 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010038 if (op->value)
10039 equal = xmlXPathEqualValues(ctxt);
10040 else
10041 equal = xmlXPathNotEqualValues(ctxt);
10042 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 return (total);
10044 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010045 bakd = ctxt->context->doc;
10046 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010047 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010048 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010049 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010050 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010051 ctxt->context->doc = bakd;
10052 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010053 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010054 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010055 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010056 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010057 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10058 valuePush(ctxt, xmlXPathNewBoolean(ret));
10059 return (total);
10060 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010061 bakd = ctxt->context->doc;
10062 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010063 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010064 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010065 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010066 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010067 if (op->ch2 != -1) {
10068 ctxt->context->doc = bakd;
10069 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010070 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010071 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010072 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010073 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010074 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010075 if (op->value == 0)
10076 xmlXPathSubValues(ctxt);
10077 else if (op->value == 1)
10078 xmlXPathAddValues(ctxt);
10079 else if (op->value == 2)
10080 xmlXPathValueFlipSign(ctxt);
10081 else if (op->value == 3) {
10082 CAST_TO_NUMBER;
10083 CHECK_TYPE0(XPATH_NUMBER);
10084 }
10085 return (total);
10086 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010087 bakd = ctxt->context->doc;
10088 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010089 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010090 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010091 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010092 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010093 ctxt->context->doc = bakd;
10094 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010095 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010096 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010097 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010098 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099 if (op->value == 0)
10100 xmlXPathMultValues(ctxt);
10101 else if (op->value == 1)
10102 xmlXPathDivValues(ctxt);
10103 else if (op->value == 2)
10104 xmlXPathModValues(ctxt);
10105 return (total);
10106 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010107 bakd = ctxt->context->doc;
10108 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010109 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010110 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010111 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010112 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010113 ctxt->context->doc = bakd;
10114 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010115 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010116 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010118 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010119 CHECK_TYPE0(XPATH_NODESET);
10120 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010121
Daniel Veillardf06307e2001-07-03 10:35:50 +000010122 CHECK_TYPE0(XPATH_NODESET);
10123 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010124
Daniel Veillardf06307e2001-07-03 10:35:50 +000010125 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10126 arg2->nodesetval);
10127 valuePush(ctxt, arg1);
10128 xmlXPathFreeObject(arg2);
10129 return (total);
10130 case XPATH_OP_ROOT:
10131 xmlXPathRoot(ctxt);
10132 return (total);
10133 case XPATH_OP_NODE:
10134 if (op->ch1 != -1)
10135 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010136 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010137 if (op->ch2 != -1)
10138 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010139 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010140 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10141 return (total);
10142 case XPATH_OP_RESET:
10143 if (op->ch1 != -1)
10144 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010145 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010146 if (op->ch2 != -1)
10147 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010148 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010149 ctxt->context->node = NULL;
10150 return (total);
10151 case XPATH_OP_COLLECT:{
10152 if (op->ch1 == -1)
10153 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010154
Daniel Veillardf06307e2001-07-03 10:35:50 +000010155 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010156 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010157
Daniel Veillardf06307e2001-07-03 10:35:50 +000010158 /*
10159 * Optimization for [n] selection where n is a number
10160 */
10161 if ((op->ch2 != -1) &&
10162 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10163 (comp->steps[op->ch2].ch1 == -1) &&
10164 (comp->steps[op->ch2].ch2 != -1) &&
10165 (comp->steps[comp->steps[op->ch2].ch2].op ==
10166 XPATH_OP_VALUE)) {
10167 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010168
Daniel Veillardf06307e2001-07-03 10:35:50 +000010169 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10170 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10171 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010172
Daniel Veillardf06307e2001-07-03 10:35:50 +000010173 if (val->floatval == (float) indx) {
10174 total +=
10175 xmlXPathNodeCollectAndTestNth(ctxt, op,
10176 indx, NULL,
10177 NULL);
10178 return (total);
10179 }
10180 }
10181 }
10182 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10183 return (total);
10184 }
10185 case XPATH_OP_VALUE:
10186 valuePush(ctxt,
10187 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10188 return (total);
10189 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010190 xmlXPathObjectPtr val;
10191
Daniel Veillardf06307e2001-07-03 10:35:50 +000010192 if (op->ch1 != -1)
10193 total +=
10194 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010195 if (op->value5 == NULL) {
10196 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10197 if (val == NULL) {
10198 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10199 return(0);
10200 }
10201 valuePush(ctxt, val);
10202 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010203 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010204
Daniel Veillardf06307e2001-07-03 10:35:50 +000010205 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10206 if (URI == NULL) {
10207 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010208 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010209 op->value4, op->value5);
10210 return (total);
10211 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010212 val = xmlXPathVariableLookupNS(ctxt->context,
10213 op->value4, URI);
10214 if (val == NULL) {
10215 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10216 return(0);
10217 }
10218 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010219 }
10220 return (total);
10221 }
10222 case XPATH_OP_FUNCTION:{
10223 xmlXPathFunction func;
10224 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010225 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010226
10227 if (op->ch1 != -1)
10228 total +=
10229 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010230 if (ctxt->valueNr < op->value) {
10231 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010232 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010233 ctxt->error = XPATH_INVALID_OPERAND;
10234 return (total);
10235 }
10236 for (i = 0; i < op->value; i++)
10237 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10238 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010239 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010240 ctxt->error = XPATH_INVALID_OPERAND;
10241 return (total);
10242 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010243 if (op->cache != NULL)
10244 func = (xmlXPathFunction) op->cache;
10245 else {
10246 const xmlChar *URI = NULL;
10247
10248 if (op->value5 == NULL)
10249 func =
10250 xmlXPathFunctionLookup(ctxt->context,
10251 op->value4);
10252 else {
10253 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10254 if (URI == NULL) {
10255 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010256 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010257 op->value4, op->value5);
10258 return (total);
10259 }
10260 func = xmlXPathFunctionLookupNS(ctxt->context,
10261 op->value4, URI);
10262 }
10263 if (func == NULL) {
10264 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010265 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010266 op->value4);
10267 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010268 }
10269 op->cache = (void *) func;
10270 op->cacheURI = (void *) URI;
10271 }
10272 oldFunc = ctxt->context->function;
10273 oldFuncURI = ctxt->context->functionURI;
10274 ctxt->context->function = op->value4;
10275 ctxt->context->functionURI = op->cacheURI;
10276 func(ctxt, op->value);
10277 ctxt->context->function = oldFunc;
10278 ctxt->context->functionURI = oldFuncURI;
10279 return (total);
10280 }
10281 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010282 bakd = ctxt->context->doc;
10283 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010284 if (op->ch1 != -1)
10285 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010286 ctxt->context->doc = bakd;
10287 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010288 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010289 if (op->ch2 != -1)
10290 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010291 ctxt->context->doc = bakd;
10292 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010293 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010294 return (total);
10295 case XPATH_OP_PREDICATE:
10296 case XPATH_OP_FILTER:{
10297 xmlXPathObjectPtr res;
10298 xmlXPathObjectPtr obj, tmp;
10299 xmlNodeSetPtr newset = NULL;
10300 xmlNodeSetPtr oldset;
10301 xmlNodePtr oldnode;
10302 int i;
10303
10304 /*
10305 * Optimization for ()[1] selection i.e. the first elem
10306 */
10307 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10308 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10309 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10310 xmlXPathObjectPtr val;
10311
10312 val = comp->steps[op->ch2].value4;
10313 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10314 (val->floatval == 1.0)) {
10315 xmlNodePtr first = NULL;
10316
10317 total +=
10318 xmlXPathCompOpEvalFirst(ctxt,
10319 &comp->steps[op->ch1],
10320 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010321 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010322 /*
10323 * The nodeset should be in document order,
10324 * Keep only the first value
10325 */
10326 if ((ctxt->value != NULL) &&
10327 (ctxt->value->type == XPATH_NODESET) &&
10328 (ctxt->value->nodesetval != NULL) &&
10329 (ctxt->value->nodesetval->nodeNr > 1))
10330 ctxt->value->nodesetval->nodeNr = 1;
10331 return (total);
10332 }
10333 }
10334 /*
10335 * Optimization for ()[last()] selection i.e. the last elem
10336 */
10337 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10338 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10339 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10340 int f = comp->steps[op->ch2].ch1;
10341
10342 if ((f != -1) &&
10343 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10344 (comp->steps[f].value5 == NULL) &&
10345 (comp->steps[f].value == 0) &&
10346 (comp->steps[f].value4 != NULL) &&
10347 (xmlStrEqual
10348 (comp->steps[f].value4, BAD_CAST "last"))) {
10349 xmlNodePtr last = NULL;
10350
10351 total +=
10352 xmlXPathCompOpEvalLast(ctxt,
10353 &comp->steps[op->ch1],
10354 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010355 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010356 /*
10357 * The nodeset should be in document order,
10358 * Keep only the last value
10359 */
10360 if ((ctxt->value != NULL) &&
10361 (ctxt->value->type == XPATH_NODESET) &&
10362 (ctxt->value->nodesetval != NULL) &&
10363 (ctxt->value->nodesetval->nodeTab != NULL) &&
10364 (ctxt->value->nodesetval->nodeNr > 1)) {
10365 ctxt->value->nodesetval->nodeTab[0] =
10366 ctxt->value->nodesetval->nodeTab[ctxt->
10367 value->
10368 nodesetval->
10369 nodeNr -
10370 1];
10371 ctxt->value->nodesetval->nodeNr = 1;
10372 }
10373 return (total);
10374 }
10375 }
10376
10377 if (op->ch1 != -1)
10378 total +=
10379 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010380 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010381 if (op->ch2 == -1)
10382 return (total);
10383 if (ctxt->value == NULL)
10384 return (total);
10385
10386 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010387
10388#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010389 /*
10390 * Hum are we filtering the result of an XPointer expression
10391 */
10392 if (ctxt->value->type == XPATH_LOCATIONSET) {
10393 xmlLocationSetPtr newlocset = NULL;
10394 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010395
Daniel Veillardf06307e2001-07-03 10:35:50 +000010396 /*
10397 * Extract the old locset, and then evaluate the result of the
10398 * expression for all the element in the locset. use it to grow
10399 * up a new locset.
10400 */
10401 CHECK_TYPE0(XPATH_LOCATIONSET);
10402 obj = valuePop(ctxt);
10403 oldlocset = obj->user;
10404 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010405
Daniel Veillardf06307e2001-07-03 10:35:50 +000010406 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10407 ctxt->context->contextSize = 0;
10408 ctxt->context->proximityPosition = 0;
10409 if (op->ch2 != -1)
10410 total +=
10411 xmlXPathCompOpEval(ctxt,
10412 &comp->steps[op->ch2]);
10413 res = valuePop(ctxt);
10414 if (res != NULL)
10415 xmlXPathFreeObject(res);
10416 valuePush(ctxt, obj);
10417 CHECK_ERROR0;
10418 return (total);
10419 }
10420 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010421
Daniel Veillardf06307e2001-07-03 10:35:50 +000010422 for (i = 0; i < oldlocset->locNr; i++) {
10423 /*
10424 * Run the evaluation with a node list made of a
10425 * single item in the nodelocset.
10426 */
10427 ctxt->context->node = oldlocset->locTab[i]->user;
10428 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10429 valuePush(ctxt, tmp);
10430 ctxt->context->contextSize = oldlocset->locNr;
10431 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010432
Daniel Veillardf06307e2001-07-03 10:35:50 +000010433 if (op->ch2 != -1)
10434 total +=
10435 xmlXPathCompOpEval(ctxt,
10436 &comp->steps[op->ch2]);
10437 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010438
Daniel Veillardf06307e2001-07-03 10:35:50 +000010439 /*
10440 * The result of the evaluation need to be tested to
10441 * decided whether the filter succeeded or not
10442 */
10443 res = valuePop(ctxt);
10444 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10445 xmlXPtrLocationSetAdd(newlocset,
10446 xmlXPathObjectCopy
10447 (oldlocset->locTab[i]));
10448 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010449
Daniel Veillardf06307e2001-07-03 10:35:50 +000010450 /*
10451 * Cleanup
10452 */
10453 if (res != NULL)
10454 xmlXPathFreeObject(res);
10455 if (ctxt->value == tmp) {
10456 res = valuePop(ctxt);
10457 xmlXPathFreeObject(res);
10458 }
10459
10460 ctxt->context->node = NULL;
10461 }
10462
10463 /*
10464 * The result is used as the new evaluation locset.
10465 */
10466 xmlXPathFreeObject(obj);
10467 ctxt->context->node = NULL;
10468 ctxt->context->contextSize = -1;
10469 ctxt->context->proximityPosition = -1;
10470 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10471 ctxt->context->node = oldnode;
10472 return (total);
10473 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010474#endif /* LIBXML_XPTR_ENABLED */
10475
Daniel Veillardf06307e2001-07-03 10:35:50 +000010476 /*
10477 * Extract the old set, and then evaluate the result of the
10478 * expression for all the element in the set. use it to grow
10479 * up a new set.
10480 */
10481 CHECK_TYPE0(XPATH_NODESET);
10482 obj = valuePop(ctxt);
10483 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010484
Daniel Veillardf06307e2001-07-03 10:35:50 +000010485 oldnode = ctxt->context->node;
10486 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010487
Daniel Veillardf06307e2001-07-03 10:35:50 +000010488 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10489 ctxt->context->contextSize = 0;
10490 ctxt->context->proximityPosition = 0;
10491 if (op->ch2 != -1)
10492 total +=
10493 xmlXPathCompOpEval(ctxt,
10494 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010495 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010496 res = valuePop(ctxt);
10497 if (res != NULL)
10498 xmlXPathFreeObject(res);
10499 valuePush(ctxt, obj);
10500 ctxt->context->node = oldnode;
10501 CHECK_ERROR0;
10502 } else {
10503 /*
10504 * Initialize the new set.
10505 */
10506 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010507
Daniel Veillardf06307e2001-07-03 10:35:50 +000010508 for (i = 0; i < oldset->nodeNr; i++) {
10509 /*
10510 * Run the evaluation with a node list made of
10511 * a single item in the nodeset.
10512 */
10513 ctxt->context->node = oldset->nodeTab[i];
10514 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10515 valuePush(ctxt, tmp);
10516 ctxt->context->contextSize = oldset->nodeNr;
10517 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010518
Daniel Veillardf06307e2001-07-03 10:35:50 +000010519 if (op->ch2 != -1)
10520 total +=
10521 xmlXPathCompOpEval(ctxt,
10522 &comp->steps[op->ch2]);
10523 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010524
Daniel Veillardf06307e2001-07-03 10:35:50 +000010525 /*
10526 * The result of the evaluation need to be tested to
10527 * decided whether the filter succeeded or not
10528 */
10529 res = valuePop(ctxt);
10530 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10531 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10532 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010533
Daniel Veillardf06307e2001-07-03 10:35:50 +000010534 /*
10535 * Cleanup
10536 */
10537 if (res != NULL)
10538 xmlXPathFreeObject(res);
10539 if (ctxt->value == tmp) {
10540 res = valuePop(ctxt);
10541 xmlXPathFreeObject(res);
10542 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010543
Daniel Veillardf06307e2001-07-03 10:35:50 +000010544 ctxt->context->node = NULL;
10545 }
10546
10547 /*
10548 * The result is used as the new evaluation set.
10549 */
10550 xmlXPathFreeObject(obj);
10551 ctxt->context->node = NULL;
10552 ctxt->context->contextSize = -1;
10553 ctxt->context->proximityPosition = -1;
10554 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10555 }
10556 ctxt->context->node = oldnode;
10557 return (total);
10558 }
10559 case XPATH_OP_SORT:
10560 if (op->ch1 != -1)
10561 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010562 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010563 if ((ctxt->value != NULL) &&
10564 (ctxt->value->type == XPATH_NODESET) &&
10565 (ctxt->value->nodesetval != NULL))
10566 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10567 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010568#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010569 case XPATH_OP_RANGETO:{
10570 xmlXPathObjectPtr range;
10571 xmlXPathObjectPtr res, obj;
10572 xmlXPathObjectPtr tmp;
10573 xmlLocationSetPtr newset = NULL;
10574 xmlNodeSetPtr oldset;
10575 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010576
Daniel Veillardf06307e2001-07-03 10:35:50 +000010577 if (op->ch1 != -1)
10578 total +=
10579 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10580 if (op->ch2 == -1)
10581 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010582
Daniel Veillardf06307e2001-07-03 10:35:50 +000010583 CHECK_TYPE0(XPATH_NODESET);
10584 obj = valuePop(ctxt);
10585 oldset = obj->nodesetval;
10586 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010587
Daniel Veillardf06307e2001-07-03 10:35:50 +000010588 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010589
Daniel Veillardf06307e2001-07-03 10:35:50 +000010590 if (oldset != NULL) {
10591 for (i = 0; i < oldset->nodeNr; i++) {
10592 /*
10593 * Run the evaluation with a node list made of a single item
10594 * in the nodeset.
10595 */
10596 ctxt->context->node = oldset->nodeTab[i];
10597 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10598 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010599
Daniel Veillardf06307e2001-07-03 10:35:50 +000010600 if (op->ch2 != -1)
10601 total +=
10602 xmlXPathCompOpEval(ctxt,
10603 &comp->steps[op->ch2]);
10604 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010605
Daniel Veillardf06307e2001-07-03 10:35:50 +000010606 /*
10607 * The result of the evaluation need to be tested to
10608 * decided whether the filter succeeded or not
10609 */
10610 res = valuePop(ctxt);
10611 range =
10612 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10613 res);
10614 if (range != NULL) {
10615 xmlXPtrLocationSetAdd(newset, range);
10616 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010617
Daniel Veillardf06307e2001-07-03 10:35:50 +000010618 /*
10619 * Cleanup
10620 */
10621 if (res != NULL)
10622 xmlXPathFreeObject(res);
10623 if (ctxt->value == tmp) {
10624 res = valuePop(ctxt);
10625 xmlXPathFreeObject(res);
10626 }
10627
10628 ctxt->context->node = NULL;
10629 }
10630 }
10631
10632 /*
10633 * The result is used as the new evaluation set.
10634 */
10635 xmlXPathFreeObject(obj);
10636 ctxt->context->node = NULL;
10637 ctxt->context->contextSize = -1;
10638 ctxt->context->proximityPosition = -1;
10639 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10640 return (total);
10641 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010642#endif /* LIBXML_XPTR_ENABLED */
10643 }
10644 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010645 "XPath: unknown precompiled operation %d\n", op->op);
10646 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010647}
10648
10649/**
10650 * xmlXPathRunEval:
10651 * @ctxt: the XPath parser context with the compiled expression
10652 *
10653 * Evaluate the Precompiled XPath expression in the given context.
10654 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010655static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010656xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10657 xmlXPathCompExprPtr comp;
10658
10659 if ((ctxt == NULL) || (ctxt->comp == NULL))
10660 return;
10661
10662 if (ctxt->valueTab == NULL) {
10663 /* Allocate the value stack */
10664 ctxt->valueTab = (xmlXPathObjectPtr *)
10665 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10666 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010667 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010668 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010669 }
10670 ctxt->valueNr = 0;
10671 ctxt->valueMax = 10;
10672 ctxt->value = NULL;
10673 }
10674 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010675 if(comp->last < 0) {
10676 xmlGenericError(xmlGenericErrorContext,
10677 "xmlXPathRunEval: last is less than zero\n");
10678 return;
10679 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010680 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10681}
10682
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010683/************************************************************************
10684 * *
10685 * Public interfaces *
10686 * *
10687 ************************************************************************/
10688
10689/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010690 * xmlXPathEvalPredicate:
10691 * @ctxt: the XPath context
10692 * @res: the Predicate Expression evaluation result
10693 *
10694 * Evaluate a predicate result for the current node.
10695 * A PredicateExpr is evaluated by evaluating the Expr and converting
10696 * the result to a boolean. If the result is a number, the result will
10697 * be converted to true if the number is equal to the position of the
10698 * context node in the context node list (as returned by the position
10699 * function) and will be converted to false otherwise; if the result
10700 * is not a number, then the result will be converted as if by a call
10701 * to the boolean function.
10702 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010703 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010704 */
10705int
10706xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10707 if (res == NULL) return(0);
10708 switch (res->type) {
10709 case XPATH_BOOLEAN:
10710 return(res->boolval);
10711 case XPATH_NUMBER:
10712 return(res->floatval == ctxt->proximityPosition);
10713 case XPATH_NODESET:
10714 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010715 if (res->nodesetval == NULL)
10716 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010717 return(res->nodesetval->nodeNr != 0);
10718 case XPATH_STRING:
10719 return((res->stringval != NULL) &&
10720 (xmlStrlen(res->stringval) != 0));
10721 default:
10722 STRANGE
10723 }
10724 return(0);
10725}
10726
10727/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010728 * xmlXPathEvaluatePredicateResult:
10729 * @ctxt: the XPath Parser context
10730 * @res: the Predicate Expression evaluation result
10731 *
10732 * Evaluate a predicate result for the current node.
10733 * A PredicateExpr is evaluated by evaluating the Expr and converting
10734 * the result to a boolean. If the result is a number, the result will
10735 * be converted to true if the number is equal to the position of the
10736 * context node in the context node list (as returned by the position
10737 * function) and will be converted to false otherwise; if the result
10738 * is not a number, then the result will be converted as if by a call
10739 * to the boolean function.
10740 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010741 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010742 */
10743int
10744xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10745 xmlXPathObjectPtr res) {
10746 if (res == NULL) return(0);
10747 switch (res->type) {
10748 case XPATH_BOOLEAN:
10749 return(res->boolval);
10750 case XPATH_NUMBER:
10751 return(res->floatval == ctxt->context->proximityPosition);
10752 case XPATH_NODESET:
10753 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010754 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010755 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010756 return(res->nodesetval->nodeNr != 0);
10757 case XPATH_STRING:
10758 return((res->stringval != NULL) &&
10759 (xmlStrlen(res->stringval) != 0));
10760 default:
10761 STRANGE
10762 }
10763 return(0);
10764}
10765
10766/**
10767 * xmlXPathCompile:
10768 * @str: the XPath expression
10769 *
10770 * Compile an XPath expression
10771 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010772 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010773 * the caller has to free the object.
10774 */
10775xmlXPathCompExprPtr
10776xmlXPathCompile(const xmlChar *str) {
10777 xmlXPathParserContextPtr ctxt;
10778 xmlXPathCompExprPtr comp;
10779
10780 xmlXPathInit();
10781
10782 ctxt = xmlXPathNewParserContext(str, NULL);
10783 xmlXPathCompileExpr(ctxt);
Daniel Veillardae9733a2003-10-28 19:02:21 +000010784
10785 if( ctxt->error != XPATH_EXPRESSION_OK )
10786 {
10787 xmlXPathFreeParserContext(ctxt);
10788 return (0);
10789 }
10790
Daniel Veillard40af6492001-04-22 08:50:55 +000010791 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010792 /*
10793 * aleksey: in some cases this line prints *second* error message
10794 * (see bug #78858) and probably this should be fixed.
10795 * However, we are not sure that all error messages are printed
10796 * out in other places. It's not critical so we leave it as-is for now
10797 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010798 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10799 comp = NULL;
10800 } else {
10801 comp = ctxt->comp;
10802 ctxt->comp = NULL;
10803 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010804 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010805 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010806 comp->expr = xmlStrdup(str);
10807#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010808 comp->string = xmlStrdup(str);
10809 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010810#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010811 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010812 return(comp);
10813}
10814
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010815/**
10816 * xmlXPathCompiledEval:
10817 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010818 * @ctx: the XPath context
10819 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010820 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010821 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010822 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010823 * the caller has to free the object.
10824 */
10825xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010826xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010827 xmlXPathParserContextPtr ctxt;
10828 xmlXPathObjectPtr res, tmp, init = NULL;
10829 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010830#ifndef LIBXML_THREAD_ENABLED
10831 static int reentance = 0;
10832#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010833
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010834 if ((comp == NULL) || (ctx == NULL))
10835 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010836 xmlXPathInit();
10837
10838 CHECK_CONTEXT(ctx)
10839
Daniel Veillard81463942001-10-16 12:34:39 +000010840#ifndef LIBXML_THREAD_ENABLED
10841 reentance++;
10842 if (reentance > 1)
10843 xmlXPathDisableOptimizer = 1;
10844#endif
10845
Daniel Veillardf06307e2001-07-03 10:35:50 +000010846#ifdef DEBUG_EVAL_COUNTS
10847 comp->nb++;
10848 if ((comp->string != NULL) && (comp->nb > 100)) {
10849 fprintf(stderr, "100 x %s\n", comp->string);
10850 comp->nb = 0;
10851 }
10852#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010853 ctxt = xmlXPathCompParserContext(comp, ctx);
10854 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010855
10856 if (ctxt->value == NULL) {
10857 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010858 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010859 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010860 } else {
10861 res = valuePop(ctxt);
10862 }
10863
Daniel Veillardf06307e2001-07-03 10:35:50 +000010864
Owen Taylor3473f882001-02-23 17:55:21 +000010865 do {
10866 tmp = valuePop(ctxt);
10867 if (tmp != NULL) {
10868 if (tmp != init)
10869 stack++;
10870 xmlXPathFreeObject(tmp);
10871 }
10872 } while (tmp != NULL);
10873 if ((stack != 0) && (res != NULL)) {
10874 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010875 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010876 stack);
10877 }
10878 if (ctxt->error != XPATH_EXPRESSION_OK) {
10879 xmlXPathFreeObject(res);
10880 res = NULL;
10881 }
10882
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010883
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010884 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010885 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010886#ifndef LIBXML_THREAD_ENABLED
10887 reentance--;
10888#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010889 return(res);
10890}
10891
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010892/**
10893 * xmlXPathEvalExpr:
10894 * @ctxt: the XPath Parser context
10895 *
10896 * Parse and evaluate an XPath expression in the given context,
10897 * then push the result on the context stack
10898 */
10899void
10900xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10901 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010902 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010903 xmlXPathRunEval(ctxt);
10904}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010905
10906/**
10907 * xmlXPathEval:
10908 * @str: the XPath expression
10909 * @ctx: the XPath context
10910 *
10911 * Evaluate the XPath Location Path in the given context.
10912 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010913 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010914 * the caller has to free the object.
10915 */
10916xmlXPathObjectPtr
10917xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10918 xmlXPathParserContextPtr ctxt;
10919 xmlXPathObjectPtr res, tmp, init = NULL;
10920 int stack = 0;
10921
10922 xmlXPathInit();
10923
10924 CHECK_CONTEXT(ctx)
10925
10926 ctxt = xmlXPathNewParserContext(str, ctx);
10927 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010928
10929 if (ctxt->value == NULL) {
10930 xmlGenericError(xmlGenericErrorContext,
10931 "xmlXPathEval: evaluation failed\n");
10932 res = NULL;
10933 } else if (*ctxt->cur != 0) {
10934 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10935 res = NULL;
10936 } else {
10937 res = valuePop(ctxt);
10938 }
10939
10940 do {
10941 tmp = valuePop(ctxt);
10942 if (tmp != NULL) {
10943 if (tmp != init)
10944 stack++;
10945 xmlXPathFreeObject(tmp);
10946 }
10947 } while (tmp != NULL);
10948 if ((stack != 0) && (res != NULL)) {
10949 xmlGenericError(xmlGenericErrorContext,
10950 "xmlXPathEval: %d object left on the stack\n",
10951 stack);
10952 }
10953 if (ctxt->error != XPATH_EXPRESSION_OK) {
10954 xmlXPathFreeObject(res);
10955 res = NULL;
10956 }
10957
Owen Taylor3473f882001-02-23 17:55:21 +000010958 xmlXPathFreeParserContext(ctxt);
10959 return(res);
10960}
10961
10962/**
10963 * xmlXPathEvalExpression:
10964 * @str: the XPath expression
10965 * @ctxt: the XPath context
10966 *
10967 * Evaluate the XPath expression in the given context.
10968 *
10969 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10970 * the caller has to free the object.
10971 */
10972xmlXPathObjectPtr
10973xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10974 xmlXPathParserContextPtr pctxt;
10975 xmlXPathObjectPtr res, tmp;
10976 int stack = 0;
10977
10978 xmlXPathInit();
10979
10980 CHECK_CONTEXT(ctxt)
10981
10982 pctxt = xmlXPathNewParserContext(str, ctxt);
10983 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010984
10985 if (*pctxt->cur != 0) {
10986 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10987 res = NULL;
10988 } else {
10989 res = valuePop(pctxt);
10990 }
10991 do {
10992 tmp = valuePop(pctxt);
10993 if (tmp != NULL) {
10994 xmlXPathFreeObject(tmp);
10995 stack++;
10996 }
10997 } while (tmp != NULL);
10998 if ((stack != 0) && (res != NULL)) {
10999 xmlGenericError(xmlGenericErrorContext,
11000 "xmlXPathEvalExpression: %d object left on the stack\n",
11001 stack);
11002 }
11003 xmlXPathFreeParserContext(pctxt);
11004 return(res);
11005}
11006
Daniel Veillard42766c02002-08-22 20:52:17 +000011007/************************************************************************
11008 * *
11009 * Extra functions not pertaining to the XPath spec *
11010 * *
11011 ************************************************************************/
11012/**
11013 * xmlXPathEscapeUriFunction:
11014 * @ctxt: the XPath Parser context
11015 * @nargs: the number of arguments
11016 *
11017 * Implement the escape-uri() XPath function
11018 * string escape-uri(string $str, bool $escape-reserved)
11019 *
11020 * This function applies the URI escaping rules defined in section 2 of [RFC
11021 * 2396] to the string supplied as $uri-part, which typically represents all
11022 * or part of a URI. The effect of the function is to replace any special
11023 * character in the string by an escape sequence of the form %xx%yy...,
11024 * where xxyy... is the hexadecimal representation of the octets used to
11025 * represent the character in UTF-8.
11026 *
11027 * The set of characters that are escaped depends on the setting of the
11028 * boolean argument $escape-reserved.
11029 *
11030 * If $escape-reserved is true, all characters are escaped other than lower
11031 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11032 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11033 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11034 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11035 * A-F).
11036 *
11037 * If $escape-reserved is false, the behavior differs in that characters
11038 * referred to in [RFC 2396] as reserved characters are not escaped. These
11039 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11040 *
11041 * [RFC 2396] does not define whether escaped URIs should use lower case or
11042 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11043 * compared using string comparison functions, this function must always use
11044 * the upper-case letters A-F.
11045 *
11046 * Generally, $escape-reserved should be set to true when escaping a string
11047 * that is to form a single part of a URI, and to false when escaping an
11048 * entire URI or URI reference.
11049 *
11050 * In the case of non-ascii characters, the string is encoded according to
11051 * utf-8 and then converted according to RFC 2396.
11052 *
11053 * Examples
11054 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11055 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11056 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11057 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11058 *
11059 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011060static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011061xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11062 xmlXPathObjectPtr str;
11063 int escape_reserved;
11064 xmlBufferPtr target;
11065 xmlChar *cptr;
11066 xmlChar escape[4];
11067
11068 CHECK_ARITY(2);
11069
11070 escape_reserved = xmlXPathPopBoolean(ctxt);
11071
11072 CAST_TO_STRING;
11073 str = valuePop(ctxt);
11074
11075 target = xmlBufferCreate();
11076
11077 escape[0] = '%';
11078 escape[3] = 0;
11079
11080 if (target) {
11081 for (cptr = str->stringval; *cptr; cptr++) {
11082 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11083 (*cptr >= 'a' && *cptr <= 'z') ||
11084 (*cptr >= '0' && *cptr <= '9') ||
11085 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11086 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11087 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11088 (*cptr == '%' &&
11089 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11090 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11091 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11092 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11093 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11094 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11095 (!escape_reserved &&
11096 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11097 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11098 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11099 *cptr == ','))) {
11100 xmlBufferAdd(target, cptr, 1);
11101 } else {
11102 if ((*cptr >> 4) < 10)
11103 escape[1] = '0' + (*cptr >> 4);
11104 else
11105 escape[1] = 'A' - 10 + (*cptr >> 4);
11106 if ((*cptr & 0xF) < 10)
11107 escape[2] = '0' + (*cptr & 0xF);
11108 else
11109 escape[2] = 'A' - 10 + (*cptr & 0xF);
11110
11111 xmlBufferAdd(target, &escape[0], 3);
11112 }
11113 }
11114 }
11115 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11116 xmlBufferFree(target);
11117 xmlXPathFreeObject(str);
11118}
11119
Owen Taylor3473f882001-02-23 17:55:21 +000011120/**
11121 * xmlXPathRegisterAllFunctions:
11122 * @ctxt: the XPath context
11123 *
11124 * Registers all default XPath functions in this context
11125 */
11126void
11127xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11128{
11129 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11130 xmlXPathBooleanFunction);
11131 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11132 xmlXPathCeilingFunction);
11133 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11134 xmlXPathCountFunction);
11135 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11136 xmlXPathConcatFunction);
11137 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11138 xmlXPathContainsFunction);
11139 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11140 xmlXPathIdFunction);
11141 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11142 xmlXPathFalseFunction);
11143 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11144 xmlXPathFloorFunction);
11145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11146 xmlXPathLastFunction);
11147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11148 xmlXPathLangFunction);
11149 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11150 xmlXPathLocalNameFunction);
11151 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11152 xmlXPathNotFunction);
11153 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11154 xmlXPathNameFunction);
11155 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11156 xmlXPathNamespaceURIFunction);
11157 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11158 xmlXPathNormalizeFunction);
11159 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11160 xmlXPathNumberFunction);
11161 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11162 xmlXPathPositionFunction);
11163 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11164 xmlXPathRoundFunction);
11165 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11166 xmlXPathStringFunction);
11167 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11168 xmlXPathStringLengthFunction);
11169 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11170 xmlXPathStartsWithFunction);
11171 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11172 xmlXPathSubstringFunction);
11173 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11174 xmlXPathSubstringBeforeFunction);
11175 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11176 xmlXPathSubstringAfterFunction);
11177 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11178 xmlXPathSumFunction);
11179 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11180 xmlXPathTrueFunction);
11181 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11182 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011183
11184 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11185 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11186 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011187}
11188
11189#endif /* LIBXML_XPATH_ENABLED */