blob: d62054384e0622c7fffe51cee180f47167453c43 [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;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001478 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001479 xmlNodePtr cur, root;
1480
1481 if ((node1 == NULL) || (node2 == NULL))
1482 return(-2);
1483 /*
1484 * a couple of optimizations which will avoid computations in most cases
1485 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001486 if (node1->type == XML_ATTRIBUTE_NODE) {
1487 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001488 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001489 node1 = node1->parent;
1490 }
1491 if (node2->type == XML_ATTRIBUTE_NODE) {
1492 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001493 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001494 node2 = node2->parent;
1495 }
1496 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001497 if (attr1 == attr2) {
1498 /* not required, but we keep attributes in order */
1499 if (attr1 != 0) {
1500 cur = attrNode2->prev;
1501 while (cur != NULL) {
1502 if (cur == attrNode1)
1503 return (1);
1504 cur = cur->prev;
1505 }
1506 return (-1);
1507 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001508 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001509 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001510 if (attr2 == 1)
1511 return(1);
1512 return(-1);
1513 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001514 if ((node1->type == XML_NAMESPACE_DECL) ||
1515 (node2->type == XML_NAMESPACE_DECL))
1516 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001517 if (node1 == node2->prev)
1518 return(1);
1519 if (node1 == node2->next)
1520 return(-1);
1521
1522 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001523 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001524 */
1525 if ((node1->type == XML_ELEMENT_NODE) &&
1526 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001527 (0 > (long) node1->content) &&
1528 (0 > (long) node2->content) &&
1529 (node1->doc == node2->doc)) {
1530 long l1, l2;
1531
1532 l1 = -((long) node1->content);
1533 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001534 if (l1 < l2)
1535 return(1);
1536 if (l1 > l2)
1537 return(-1);
1538 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001539
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001540 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001541 * compute depth to root
1542 */
1543 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1544 if (cur == node1)
1545 return(1);
1546 depth2++;
1547 }
1548 root = cur;
1549 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1550 if (cur == node2)
1551 return(-1);
1552 depth1++;
1553 }
1554 /*
1555 * Distinct document (or distinct entities :-( ) case.
1556 */
1557 if (root != cur) {
1558 return(-2);
1559 }
1560 /*
1561 * get the nearest common ancestor.
1562 */
1563 while (depth1 > depth2) {
1564 depth1--;
1565 node1 = node1->parent;
1566 }
1567 while (depth2 > depth1) {
1568 depth2--;
1569 node2 = node2->parent;
1570 }
1571 while (node1->parent != node2->parent) {
1572 node1 = node1->parent;
1573 node2 = node2->parent;
1574 /* should not happen but just in case ... */
1575 if ((node1 == NULL) || (node2 == NULL))
1576 return(-2);
1577 }
1578 /*
1579 * Find who's first.
1580 */
1581 if (node1 == node2->next)
1582 return(-1);
1583 for (cur = node1->next;cur != NULL;cur = cur->next)
1584 if (cur == node2)
1585 return(1);
1586 return(-1); /* assume there is no sibling list corruption */
1587}
1588
1589/**
1590 * xmlXPathNodeSetSort:
1591 * @set: the node set
1592 *
1593 * Sort the node set in document order
1594 */
1595void
1596xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001597 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001598 xmlNodePtr tmp;
1599
1600 if (set == NULL)
1601 return;
1602
1603 /* Use Shell's sort to sort the node-set */
1604 len = set->nodeNr;
1605 for (incr = len / 2; incr > 0; incr /= 2) {
1606 for (i = incr; i < len; i++) {
1607 j = i - incr;
1608 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001609 if (xmlXPathCmpNodes(set->nodeTab[j],
1610 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001611 tmp = set->nodeTab[j];
1612 set->nodeTab[j] = set->nodeTab[j + incr];
1613 set->nodeTab[j + incr] = tmp;
1614 j -= incr;
1615 } else
1616 break;
1617 }
1618 }
1619 }
1620}
1621
1622#define XML_NODESET_DEFAULT 10
1623/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001624 * xmlXPathNodeSetDupNs:
1625 * @node: the parent node of the namespace XPath node
1626 * @ns: the libxml namespace declaration node.
1627 *
1628 * Namespace node in libxml don't match the XPath semantic. In a node set
1629 * the namespace nodes are duplicated and the next pointer is set to the
1630 * parent node in the XPath semantic.
1631 *
1632 * Returns the newly created object.
1633 */
1634static xmlNodePtr
1635xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1636 xmlNsPtr cur;
1637
1638 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1639 return(NULL);
1640 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1641 return((xmlNodePtr) ns);
1642
1643 /*
1644 * Allocate a new Namespace and fill the fields.
1645 */
1646 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1647 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001648 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001649 return(NULL);
1650 }
1651 memset(cur, 0, sizeof(xmlNs));
1652 cur->type = XML_NAMESPACE_DECL;
1653 if (ns->href != NULL)
1654 cur->href = xmlStrdup(ns->href);
1655 if (ns->prefix != NULL)
1656 cur->prefix = xmlStrdup(ns->prefix);
1657 cur->next = (xmlNsPtr) node;
1658 return((xmlNodePtr) cur);
1659}
1660
1661/**
1662 * xmlXPathNodeSetFreeNs:
1663 * @ns: the XPath namespace node found in a nodeset.
1664 *
1665 * Namespace node in libxml don't match the XPath semantic. In a node set
1666 * the namespace nodes are duplicated and the next pointer is set to the
1667 * parent node in the XPath semantic. Check if such a node need to be freed
1668 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001669void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001670xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1671 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1672 return;
1673
1674 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1675 if (ns->href != NULL)
1676 xmlFree((xmlChar *)ns->href);
1677 if (ns->prefix != NULL)
1678 xmlFree((xmlChar *)ns->prefix);
1679 xmlFree(ns);
1680 }
1681}
1682
1683/**
Owen Taylor3473f882001-02-23 17:55:21 +00001684 * xmlXPathNodeSetCreate:
1685 * @val: an initial xmlNodePtr, or NULL
1686 *
1687 * Create a new xmlNodeSetPtr of type double and of value @val
1688 *
1689 * Returns the newly created object.
1690 */
1691xmlNodeSetPtr
1692xmlXPathNodeSetCreate(xmlNodePtr val) {
1693 xmlNodeSetPtr ret;
1694
1695 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1696 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001697 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001698 return(NULL);
1699 }
1700 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1701 if (val != NULL) {
1702 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1703 sizeof(xmlNodePtr));
1704 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001705 xmlXPathErrMemory(NULL, "creating nodeset\n");
1706 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001707 return(NULL);
1708 }
1709 memset(ret->nodeTab, 0 ,
1710 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1711 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001712 if (val->type == XML_NAMESPACE_DECL) {
1713 xmlNsPtr ns = (xmlNsPtr) val;
1714
1715 ret->nodeTab[ret->nodeNr++] =
1716 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1717 } else
1718 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001719 }
1720 return(ret);
1721}
1722
1723/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001724 * xmlXPathNodeSetContains:
1725 * @cur: the node-set
1726 * @val: the node
1727 *
1728 * checks whether @cur contains @val
1729 *
1730 * Returns true (1) if @cur contains @val, false (0) otherwise
1731 */
1732int
1733xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1734 int i;
1735
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001736 if (val->type == XML_NAMESPACE_DECL) {
1737 for (i = 0; i < cur->nodeNr; i++) {
1738 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1739 xmlNsPtr ns1, ns2;
1740
1741 ns1 = (xmlNsPtr) val;
1742 ns2 = (xmlNsPtr) cur->nodeTab[i];
1743 if (ns1 == ns2)
1744 return(1);
1745 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1746 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1747 return(1);
1748 }
1749 }
1750 } else {
1751 for (i = 0; i < cur->nodeNr; i++) {
1752 if (cur->nodeTab[i] == val)
1753 return(1);
1754 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001755 }
1756 return(0);
1757}
1758
1759/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001760 * xmlXPathNodeSetAddNs:
1761 * @cur: the initial node set
1762 * @node: the hosting node
1763 * @ns: a the namespace node
1764 *
1765 * add a new namespace node to an existing NodeSet
1766 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001767void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001768xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1769 int i;
1770
1771 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1772 (node->type != XML_ELEMENT_NODE))
1773 return;
1774
1775 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1776 /*
1777 * check against doublons
1778 */
1779 for (i = 0;i < cur->nodeNr;i++) {
1780 if ((cur->nodeTab[i] != NULL) &&
1781 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001782 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001783 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1784 return;
1785 }
1786
1787 /*
1788 * grow the nodeTab if needed
1789 */
1790 if (cur->nodeMax == 0) {
1791 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1792 sizeof(xmlNodePtr));
1793 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001794 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001795 return;
1796 }
1797 memset(cur->nodeTab, 0 ,
1798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1799 cur->nodeMax = XML_NODESET_DEFAULT;
1800 } else if (cur->nodeNr == cur->nodeMax) {
1801 xmlNodePtr *temp;
1802
1803 cur->nodeMax *= 2;
1804 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1805 sizeof(xmlNodePtr));
1806 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001807 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001808 return;
1809 }
1810 cur->nodeTab = temp;
1811 }
1812 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1813}
1814
1815/**
Owen Taylor3473f882001-02-23 17:55:21 +00001816 * xmlXPathNodeSetAdd:
1817 * @cur: the initial node set
1818 * @val: a new xmlNodePtr
1819 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001820 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001821 */
1822void
1823xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1824 int i;
1825
1826 if (val == NULL) return;
1827
Daniel Veillardef0b4502003-03-24 13:57:34 +00001828#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001829 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1830 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001831#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001832
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001833 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001834 /*
1835 * check against doublons
1836 */
1837 for (i = 0;i < cur->nodeNr;i++)
1838 if (cur->nodeTab[i] == val) return;
1839
1840 /*
1841 * grow the nodeTab if needed
1842 */
1843 if (cur->nodeMax == 0) {
1844 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1845 sizeof(xmlNodePtr));
1846 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001847 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001848 return;
1849 }
1850 memset(cur->nodeTab, 0 ,
1851 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1852 cur->nodeMax = XML_NODESET_DEFAULT;
1853 } else if (cur->nodeNr == cur->nodeMax) {
1854 xmlNodePtr *temp;
1855
1856 cur->nodeMax *= 2;
1857 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1858 sizeof(xmlNodePtr));
1859 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001860 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001861 return;
1862 }
1863 cur->nodeTab = temp;
1864 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001865 if (val->type == XML_NAMESPACE_DECL) {
1866 xmlNsPtr ns = (xmlNsPtr) val;
1867
1868 cur->nodeTab[cur->nodeNr++] =
1869 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1870 } else
1871 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001872}
1873
1874/**
1875 * xmlXPathNodeSetAddUnique:
1876 * @cur: the initial node set
1877 * @val: a new xmlNodePtr
1878 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001879 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001880 * when we are sure the node is not already in the set.
1881 */
1882void
1883xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1884 if (val == NULL) return;
1885
Daniel Veillardef0b4502003-03-24 13:57:34 +00001886#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001887 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1888 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001889#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001890
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001891 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001892 /*
1893 * grow the nodeTab if needed
1894 */
1895 if (cur->nodeMax == 0) {
1896 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1897 sizeof(xmlNodePtr));
1898 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001899 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001900 return;
1901 }
1902 memset(cur->nodeTab, 0 ,
1903 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1904 cur->nodeMax = XML_NODESET_DEFAULT;
1905 } else if (cur->nodeNr == cur->nodeMax) {
1906 xmlNodePtr *temp;
1907
1908 cur->nodeMax *= 2;
1909 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1910 sizeof(xmlNodePtr));
1911 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001912 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001913 return;
1914 }
1915 cur->nodeTab = temp;
1916 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001917 if (val->type == XML_NAMESPACE_DECL) {
1918 xmlNsPtr ns = (xmlNsPtr) val;
1919
1920 cur->nodeTab[cur->nodeNr++] =
1921 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1922 } else
1923 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001924}
1925
1926/**
1927 * xmlXPathNodeSetMerge:
1928 * @val1: the first NodeSet or NULL
1929 * @val2: the second NodeSet
1930 *
1931 * Merges two nodesets, all nodes from @val2 are added to @val1
1932 * if @val1 is NULL, a new set is created and copied from @val2
1933 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001934 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001935 */
1936xmlNodeSetPtr
1937xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001938 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001939
1940 if (val2 == NULL) return(val1);
1941 if (val1 == NULL) {
1942 val1 = xmlXPathNodeSetCreate(NULL);
1943 }
1944
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001945 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001946 initNr = val1->nodeNr;
1947
1948 for (i = 0;i < val2->nodeNr;i++) {
1949 /*
1950 * check against doublons
1951 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001952 skip = 0;
1953 for (j = 0; j < initNr; j++) {
1954 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1955 skip = 1;
1956 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001957 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1958 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1959 xmlNsPtr ns1, ns2;
1960 ns1 = (xmlNsPtr) val1->nodeTab[j];
1961 ns2 = (xmlNsPtr) val2->nodeTab[i];
1962 if ((ns1->next == ns2->next) &&
1963 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1964 skip = 1;
1965 break;
1966 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001967 }
1968 }
1969 if (skip)
1970 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001971
1972 /*
1973 * grow the nodeTab if needed
1974 */
1975 if (val1->nodeMax == 0) {
1976 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1977 sizeof(xmlNodePtr));
1978 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001979 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001980 return(NULL);
1981 }
1982 memset(val1->nodeTab, 0 ,
1983 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1984 val1->nodeMax = XML_NODESET_DEFAULT;
1985 } else if (val1->nodeNr == val1->nodeMax) {
1986 xmlNodePtr *temp;
1987
1988 val1->nodeMax *= 2;
1989 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1990 sizeof(xmlNodePtr));
1991 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001992 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001993 return(NULL);
1994 }
1995 val1->nodeTab = temp;
1996 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001997 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1998 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1999
2000 val1->nodeTab[val1->nodeNr++] =
2001 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2002 } else
2003 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002004 }
2005
2006 return(val1);
2007}
2008
2009/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002010 * xmlXPathNodeSetMergeUnique:
2011 * @val1: the first NodeSet or NULL
2012 * @val2: the second NodeSet
2013 *
2014 * Merges two nodesets, all nodes from @val2 are added to @val1
2015 * if @val1 is NULL, a new set is created and copied from @val2
2016 *
2017 * Returns @val1 once extended or NULL in case of error.
2018 */
2019static xmlNodeSetPtr
2020xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002021 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002022
2023 if (val2 == NULL) return(val1);
2024 if (val1 == NULL) {
2025 val1 = xmlXPathNodeSetCreate(NULL);
2026 }
2027
2028 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002029
2030 for (i = 0;i < val2->nodeNr;i++) {
2031 /*
2032 * grow the nodeTab if needed
2033 */
2034 if (val1->nodeMax == 0) {
2035 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2036 sizeof(xmlNodePtr));
2037 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002038 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002039 return(NULL);
2040 }
2041 memset(val1->nodeTab, 0 ,
2042 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2043 val1->nodeMax = XML_NODESET_DEFAULT;
2044 } else if (val1->nodeNr == val1->nodeMax) {
2045 xmlNodePtr *temp;
2046
2047 val1->nodeMax *= 2;
2048 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2049 sizeof(xmlNodePtr));
2050 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002051 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002052 return(NULL);
2053 }
2054 val1->nodeTab = temp;
2055 }
2056 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2057 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2058
2059 val1->nodeTab[val1->nodeNr++] =
2060 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2061 } else
2062 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2063 }
2064
2065 return(val1);
2066}
2067
2068/**
Owen Taylor3473f882001-02-23 17:55:21 +00002069 * xmlXPathNodeSetDel:
2070 * @cur: the initial node set
2071 * @val: an xmlNodePtr
2072 *
2073 * Removes an xmlNodePtr from an existing NodeSet
2074 */
2075void
2076xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2077 int i;
2078
2079 if (cur == NULL) return;
2080 if (val == NULL) return;
2081
2082 /*
2083 * check against doublons
2084 */
2085 for (i = 0;i < cur->nodeNr;i++)
2086 if (cur->nodeTab[i] == val) break;
2087
2088 if (i >= cur->nodeNr) {
2089#ifdef DEBUG
2090 xmlGenericError(xmlGenericErrorContext,
2091 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2092 val->name);
2093#endif
2094 return;
2095 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002096 if ((cur->nodeTab[i] != NULL) &&
2097 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2098 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002099 cur->nodeNr--;
2100 for (;i < cur->nodeNr;i++)
2101 cur->nodeTab[i] = cur->nodeTab[i + 1];
2102 cur->nodeTab[cur->nodeNr] = NULL;
2103}
2104
2105/**
2106 * xmlXPathNodeSetRemove:
2107 * @cur: the initial node set
2108 * @val: the index to remove
2109 *
2110 * Removes an entry from an existing NodeSet list.
2111 */
2112void
2113xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2114 if (cur == NULL) return;
2115 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002116 if ((cur->nodeTab[val] != NULL) &&
2117 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2118 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002119 cur->nodeNr--;
2120 for (;val < cur->nodeNr;val++)
2121 cur->nodeTab[val] = cur->nodeTab[val + 1];
2122 cur->nodeTab[cur->nodeNr] = NULL;
2123}
2124
2125/**
2126 * xmlXPathFreeNodeSet:
2127 * @obj: the xmlNodeSetPtr to free
2128 *
2129 * Free the NodeSet compound (not the actual nodes !).
2130 */
2131void
2132xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2133 if (obj == NULL) return;
2134 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002135 int i;
2136
2137 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2138 for (i = 0;i < obj->nodeNr;i++)
2139 if ((obj->nodeTab[i] != NULL) &&
2140 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2141 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002142 xmlFree(obj->nodeTab);
2143 }
Owen Taylor3473f882001-02-23 17:55:21 +00002144 xmlFree(obj);
2145}
2146
2147/**
2148 * xmlXPathFreeValueTree:
2149 * @obj: the xmlNodeSetPtr to free
2150 *
2151 * Free the NodeSet compound and the actual tree, this is different
2152 * from xmlXPathFreeNodeSet()
2153 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002154static void
Owen Taylor3473f882001-02-23 17:55:21 +00002155xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2156 int i;
2157
2158 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002159
2160 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002161 for (i = 0;i < obj->nodeNr;i++) {
2162 if (obj->nodeTab[i] != NULL) {
2163 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2164 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2165 } else {
2166 xmlFreeNodeList(obj->nodeTab[i]);
2167 }
2168 }
2169 }
Owen Taylor3473f882001-02-23 17:55:21 +00002170 xmlFree(obj->nodeTab);
2171 }
Owen Taylor3473f882001-02-23 17:55:21 +00002172 xmlFree(obj);
2173}
2174
2175#if defined(DEBUG) || defined(DEBUG_STEP)
2176/**
2177 * xmlGenericErrorContextNodeSet:
2178 * @output: a FILE * for the output
2179 * @obj: the xmlNodeSetPtr to free
2180 *
2181 * Quick display of a NodeSet
2182 */
2183void
2184xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2185 int i;
2186
2187 if (output == NULL) output = xmlGenericErrorContext;
2188 if (obj == NULL) {
2189 fprintf(output, "NodeSet == NULL !\n");
2190 return;
2191 }
2192 if (obj->nodeNr == 0) {
2193 fprintf(output, "NodeSet is empty\n");
2194 return;
2195 }
2196 if (obj->nodeTab == NULL) {
2197 fprintf(output, " nodeTab == NULL !\n");
2198 return;
2199 }
2200 for (i = 0; i < obj->nodeNr; i++) {
2201 if (obj->nodeTab[i] == NULL) {
2202 fprintf(output, " NULL !\n");
2203 return;
2204 }
2205 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2206 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2207 fprintf(output, " /");
2208 else if (obj->nodeTab[i]->name == NULL)
2209 fprintf(output, " noname!");
2210 else fprintf(output, " %s", obj->nodeTab[i]->name);
2211 }
2212 fprintf(output, "\n");
2213}
2214#endif
2215
2216/**
2217 * xmlXPathNewNodeSet:
2218 * @val: the NodePtr value
2219 *
2220 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2221 * it with the single Node @val
2222 *
2223 * Returns the newly created object.
2224 */
2225xmlXPathObjectPtr
2226xmlXPathNewNodeSet(xmlNodePtr val) {
2227 xmlXPathObjectPtr ret;
2228
2229 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2230 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002231 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002232 return(NULL);
2233 }
2234 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2235 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002236 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002237 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002238 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002239 return(ret);
2240}
2241
2242/**
2243 * xmlXPathNewValueTree:
2244 * @val: the NodePtr value
2245 *
2246 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2247 * it with the tree root @val
2248 *
2249 * Returns the newly created object.
2250 */
2251xmlXPathObjectPtr
2252xmlXPathNewValueTree(xmlNodePtr val) {
2253 xmlXPathObjectPtr ret;
2254
2255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2256 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002257 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002258 return(NULL);
2259 }
2260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2261 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002262 ret->boolval = 1;
2263 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002264 ret->nodesetval = xmlXPathNodeSetCreate(val);
2265 return(ret);
2266}
2267
2268/**
2269 * xmlXPathNewNodeSetList:
2270 * @val: an existing NodeSet
2271 *
2272 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2273 * it with the Nodeset @val
2274 *
2275 * Returns the newly created object.
2276 */
2277xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002278xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2279{
Owen Taylor3473f882001-02-23 17:55:21 +00002280 xmlXPathObjectPtr ret;
2281 int i;
2282
2283 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002284 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002285 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002286 ret = xmlXPathNewNodeSet(NULL);
2287 else {
2288 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2289 for (i = 1; i < val->nodeNr; ++i)
2290 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2291 }
Owen Taylor3473f882001-02-23 17:55:21 +00002292
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002293 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002294}
2295
2296/**
2297 * xmlXPathWrapNodeSet:
2298 * @val: the NodePtr value
2299 *
2300 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2301 *
2302 * Returns the newly created object.
2303 */
2304xmlXPathObjectPtr
2305xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2306 xmlXPathObjectPtr ret;
2307
2308 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2309 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002310 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002311 return(NULL);
2312 }
2313 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2314 ret->type = XPATH_NODESET;
2315 ret->nodesetval = val;
2316 return(ret);
2317}
2318
2319/**
2320 * xmlXPathFreeNodeSetList:
2321 * @obj: an existing NodeSetList object
2322 *
2323 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2324 * the list contrary to xmlXPathFreeObject().
2325 */
2326void
2327xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2328 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002329 xmlFree(obj);
2330}
2331
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002332/**
2333 * xmlXPathDifference:
2334 * @nodes1: a node-set
2335 * @nodes2: a node-set
2336 *
2337 * Implements the EXSLT - Sets difference() function:
2338 * node-set set:difference (node-set, node-set)
2339 *
2340 * Returns the difference between the two node sets, or nodes1 if
2341 * nodes2 is empty
2342 */
2343xmlNodeSetPtr
2344xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2345 xmlNodeSetPtr ret;
2346 int i, l1;
2347 xmlNodePtr cur;
2348
2349 if (xmlXPathNodeSetIsEmpty(nodes2))
2350 return(nodes1);
2351
2352 ret = xmlXPathNodeSetCreate(NULL);
2353 if (xmlXPathNodeSetIsEmpty(nodes1))
2354 return(ret);
2355
2356 l1 = xmlXPathNodeSetGetLength(nodes1);
2357
2358 for (i = 0; i < l1; i++) {
2359 cur = xmlXPathNodeSetItem(nodes1, i);
2360 if (!xmlXPathNodeSetContains(nodes2, cur))
2361 xmlXPathNodeSetAddUnique(ret, cur);
2362 }
2363 return(ret);
2364}
2365
2366/**
2367 * xmlXPathIntersection:
2368 * @nodes1: a node-set
2369 * @nodes2: a node-set
2370 *
2371 * Implements the EXSLT - Sets intersection() function:
2372 * node-set set:intersection (node-set, node-set)
2373 *
2374 * Returns a node set comprising the nodes that are within both the
2375 * node sets passed as arguments
2376 */
2377xmlNodeSetPtr
2378xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2379 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2380 int i, l1;
2381 xmlNodePtr cur;
2382
2383 if (xmlXPathNodeSetIsEmpty(nodes1))
2384 return(ret);
2385 if (xmlXPathNodeSetIsEmpty(nodes2))
2386 return(ret);
2387
2388 l1 = xmlXPathNodeSetGetLength(nodes1);
2389
2390 for (i = 0; i < l1; i++) {
2391 cur = xmlXPathNodeSetItem(nodes1, i);
2392 if (xmlXPathNodeSetContains(nodes2, cur))
2393 xmlXPathNodeSetAddUnique(ret, cur);
2394 }
2395 return(ret);
2396}
2397
2398/**
2399 * xmlXPathDistinctSorted:
2400 * @nodes: a node-set, sorted by document order
2401 *
2402 * Implements the EXSLT - Sets distinct() function:
2403 * node-set set:distinct (node-set)
2404 *
2405 * Returns a subset of the nodes contained in @nodes, or @nodes if
2406 * it is empty
2407 */
2408xmlNodeSetPtr
2409xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2410 xmlNodeSetPtr ret;
2411 xmlHashTablePtr hash;
2412 int i, l;
2413 xmlChar * strval;
2414 xmlNodePtr cur;
2415
2416 if (xmlXPathNodeSetIsEmpty(nodes))
2417 return(nodes);
2418
2419 ret = xmlXPathNodeSetCreate(NULL);
2420 l = xmlXPathNodeSetGetLength(nodes);
2421 hash = xmlHashCreate (l);
2422 for (i = 0; i < l; i++) {
2423 cur = xmlXPathNodeSetItem(nodes, i);
2424 strval = xmlXPathCastNodeToString(cur);
2425 if (xmlHashLookup(hash, strval) == NULL) {
2426 xmlHashAddEntry(hash, strval, strval);
2427 xmlXPathNodeSetAddUnique(ret, cur);
2428 } else {
2429 xmlFree(strval);
2430 }
2431 }
2432 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2433 return(ret);
2434}
2435
2436/**
2437 * xmlXPathDistinct:
2438 * @nodes: a node-set
2439 *
2440 * Implements the EXSLT - Sets distinct() function:
2441 * node-set set:distinct (node-set)
2442 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2443 * is called with the sorted node-set
2444 *
2445 * Returns a subset of the nodes contained in @nodes, or @nodes if
2446 * it is empty
2447 */
2448xmlNodeSetPtr
2449xmlXPathDistinct (xmlNodeSetPtr nodes) {
2450 if (xmlXPathNodeSetIsEmpty(nodes))
2451 return(nodes);
2452
2453 xmlXPathNodeSetSort(nodes);
2454 return(xmlXPathDistinctSorted(nodes));
2455}
2456
2457/**
2458 * xmlXPathHasSameNodes:
2459 * @nodes1: a node-set
2460 * @nodes2: a node-set
2461 *
2462 * Implements the EXSLT - Sets has-same-nodes function:
2463 * boolean set:has-same-node(node-set, node-set)
2464 *
2465 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2466 * otherwise
2467 */
2468int
2469xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2470 int i, l;
2471 xmlNodePtr cur;
2472
2473 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2474 xmlXPathNodeSetIsEmpty(nodes2))
2475 return(0);
2476
2477 l = xmlXPathNodeSetGetLength(nodes1);
2478 for (i = 0; i < l; i++) {
2479 cur = xmlXPathNodeSetItem(nodes1, i);
2480 if (xmlXPathNodeSetContains(nodes2, cur))
2481 return(1);
2482 }
2483 return(0);
2484}
2485
2486/**
2487 * xmlXPathNodeLeadingSorted:
2488 * @nodes: a node-set, sorted by document order
2489 * @node: a node
2490 *
2491 * Implements the EXSLT - Sets leading() function:
2492 * node-set set:leading (node-set, node-set)
2493 *
2494 * Returns the nodes in @nodes that precede @node in document order,
2495 * @nodes if @node is NULL or an empty node-set if @nodes
2496 * doesn't contain @node
2497 */
2498xmlNodeSetPtr
2499xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2500 int i, l;
2501 xmlNodePtr cur;
2502 xmlNodeSetPtr ret;
2503
2504 if (node == NULL)
2505 return(nodes);
2506
2507 ret = xmlXPathNodeSetCreate(NULL);
2508 if (xmlXPathNodeSetIsEmpty(nodes) ||
2509 (!xmlXPathNodeSetContains(nodes, node)))
2510 return(ret);
2511
2512 l = xmlXPathNodeSetGetLength(nodes);
2513 for (i = 0; i < l; i++) {
2514 cur = xmlXPathNodeSetItem(nodes, i);
2515 if (cur == node)
2516 break;
2517 xmlXPathNodeSetAddUnique(ret, cur);
2518 }
2519 return(ret);
2520}
2521
2522/**
2523 * xmlXPathNodeLeading:
2524 * @nodes: a node-set
2525 * @node: a node
2526 *
2527 * Implements the EXSLT - Sets leading() function:
2528 * node-set set:leading (node-set, node-set)
2529 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2530 * is called.
2531 *
2532 * Returns the nodes in @nodes that precede @node in document order,
2533 * @nodes if @node is NULL or an empty node-set if @nodes
2534 * doesn't contain @node
2535 */
2536xmlNodeSetPtr
2537xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2538 xmlXPathNodeSetSort(nodes);
2539 return(xmlXPathNodeLeadingSorted(nodes, node));
2540}
2541
2542/**
2543 * xmlXPathLeadingSorted:
2544 * @nodes1: a node-set, sorted by document order
2545 * @nodes2: a node-set, sorted by document order
2546 *
2547 * Implements the EXSLT - Sets leading() function:
2548 * node-set set:leading (node-set, node-set)
2549 *
2550 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2551 * in document order, @nodes1 if @nodes2 is NULL or empty or
2552 * an empty node-set if @nodes1 doesn't contain @nodes2
2553 */
2554xmlNodeSetPtr
2555xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2556 if (xmlXPathNodeSetIsEmpty(nodes2))
2557 return(nodes1);
2558 return(xmlXPathNodeLeadingSorted(nodes1,
2559 xmlXPathNodeSetItem(nodes2, 1)));
2560}
2561
2562/**
2563 * xmlXPathLeading:
2564 * @nodes1: a node-set
2565 * @nodes2: a node-set
2566 *
2567 * Implements the EXSLT - Sets leading() function:
2568 * node-set set:leading (node-set, node-set)
2569 * @nodes1 and @nodes2 are sorted by document order, then
2570 * #exslSetsLeadingSorted is called.
2571 *
2572 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2573 * in document order, @nodes1 if @nodes2 is NULL or empty or
2574 * an empty node-set if @nodes1 doesn't contain @nodes2
2575 */
2576xmlNodeSetPtr
2577xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2578 if (xmlXPathNodeSetIsEmpty(nodes2))
2579 return(nodes1);
2580 if (xmlXPathNodeSetIsEmpty(nodes1))
2581 return(xmlXPathNodeSetCreate(NULL));
2582 xmlXPathNodeSetSort(nodes1);
2583 xmlXPathNodeSetSort(nodes2);
2584 return(xmlXPathNodeLeadingSorted(nodes1,
2585 xmlXPathNodeSetItem(nodes2, 1)));
2586}
2587
2588/**
2589 * xmlXPathNodeTrailingSorted:
2590 * @nodes: a node-set, sorted by document order
2591 * @node: a node
2592 *
2593 * Implements the EXSLT - Sets trailing() function:
2594 * node-set set:trailing (node-set, node-set)
2595 *
2596 * Returns the nodes in @nodes that follow @node in document order,
2597 * @nodes if @node is NULL or an empty node-set if @nodes
2598 * doesn't contain @node
2599 */
2600xmlNodeSetPtr
2601xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2602 int i, l;
2603 xmlNodePtr cur;
2604 xmlNodeSetPtr ret;
2605
2606 if (node == NULL)
2607 return(nodes);
2608
2609 ret = xmlXPathNodeSetCreate(NULL);
2610 if (xmlXPathNodeSetIsEmpty(nodes) ||
2611 (!xmlXPathNodeSetContains(nodes, node)))
2612 return(ret);
2613
2614 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002615 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002616 cur = xmlXPathNodeSetItem(nodes, i);
2617 if (cur == node)
2618 break;
2619 xmlXPathNodeSetAddUnique(ret, cur);
2620 }
2621 return(ret);
2622}
2623
2624/**
2625 * xmlXPathNodeTrailing:
2626 * @nodes: a node-set
2627 * @node: a node
2628 *
2629 * Implements the EXSLT - Sets trailing() function:
2630 * node-set set:trailing (node-set, node-set)
2631 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2632 * is called.
2633 *
2634 * Returns the nodes in @nodes that follow @node in document order,
2635 * @nodes if @node is NULL or an empty node-set if @nodes
2636 * doesn't contain @node
2637 */
2638xmlNodeSetPtr
2639xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2640 xmlXPathNodeSetSort(nodes);
2641 return(xmlXPathNodeTrailingSorted(nodes, node));
2642}
2643
2644/**
2645 * xmlXPathTrailingSorted:
2646 * @nodes1: a node-set, sorted by document order
2647 * @nodes2: a node-set, sorted by document order
2648 *
2649 * Implements the EXSLT - Sets trailing() function:
2650 * node-set set:trailing (node-set, node-set)
2651 *
2652 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2653 * in document order, @nodes1 if @nodes2 is NULL or empty or
2654 * an empty node-set if @nodes1 doesn't contain @nodes2
2655 */
2656xmlNodeSetPtr
2657xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2658 if (xmlXPathNodeSetIsEmpty(nodes2))
2659 return(nodes1);
2660 return(xmlXPathNodeTrailingSorted(nodes1,
2661 xmlXPathNodeSetItem(nodes2, 0)));
2662}
2663
2664/**
2665 * xmlXPathTrailing:
2666 * @nodes1: a node-set
2667 * @nodes2: a node-set
2668 *
2669 * Implements the EXSLT - Sets trailing() function:
2670 * node-set set:trailing (node-set, node-set)
2671 * @nodes1 and @nodes2 are sorted by document order, then
2672 * #xmlXPathTrailingSorted is called.
2673 *
2674 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2675 * in document order, @nodes1 if @nodes2 is NULL or empty or
2676 * an empty node-set if @nodes1 doesn't contain @nodes2
2677 */
2678xmlNodeSetPtr
2679xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2680 if (xmlXPathNodeSetIsEmpty(nodes2))
2681 return(nodes1);
2682 if (xmlXPathNodeSetIsEmpty(nodes1))
2683 return(xmlXPathNodeSetCreate(NULL));
2684 xmlXPathNodeSetSort(nodes1);
2685 xmlXPathNodeSetSort(nodes2);
2686 return(xmlXPathNodeTrailingSorted(nodes1,
2687 xmlXPathNodeSetItem(nodes2, 0)));
2688}
2689
Owen Taylor3473f882001-02-23 17:55:21 +00002690/************************************************************************
2691 * *
2692 * Routines to handle extra functions *
2693 * *
2694 ************************************************************************/
2695
2696/**
2697 * xmlXPathRegisterFunc:
2698 * @ctxt: the XPath context
2699 * @name: the function name
2700 * @f: the function implementation or NULL
2701 *
2702 * Register a new function. If @f is NULL it unregisters the function
2703 *
2704 * Returns 0 in case of success, -1 in case of error
2705 */
2706int
2707xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2708 xmlXPathFunction f) {
2709 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2710}
2711
2712/**
2713 * xmlXPathRegisterFuncNS:
2714 * @ctxt: the XPath context
2715 * @name: the function name
2716 * @ns_uri: the function namespace URI
2717 * @f: the function implementation or NULL
2718 *
2719 * Register a new function. If @f is NULL it unregisters the function
2720 *
2721 * Returns 0 in case of success, -1 in case of error
2722 */
2723int
2724xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2725 const xmlChar *ns_uri, xmlXPathFunction f) {
2726 if (ctxt == NULL)
2727 return(-1);
2728 if (name == NULL)
2729 return(-1);
2730
2731 if (ctxt->funcHash == NULL)
2732 ctxt->funcHash = xmlHashCreate(0);
2733 if (ctxt->funcHash == NULL)
2734 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002735 if (f == NULL)
2736 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002737 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2738}
2739
2740/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002741 * xmlXPathRegisterFuncLookup:
2742 * @ctxt: the XPath context
2743 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002744 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002745 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002746 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002747 */
2748void
2749xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2750 xmlXPathFuncLookupFunc f,
2751 void *funcCtxt) {
2752 if (ctxt == NULL)
2753 return;
2754 ctxt->funcLookupFunc = (void *) f;
2755 ctxt->funcLookupData = funcCtxt;
2756}
2757
2758/**
Owen Taylor3473f882001-02-23 17:55:21 +00002759 * xmlXPathFunctionLookup:
2760 * @ctxt: the XPath context
2761 * @name: the function name
2762 *
2763 * Search in the Function array of the context for the given
2764 * function.
2765 *
2766 * Returns the xmlXPathFunction or NULL if not found
2767 */
2768xmlXPathFunction
2769xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002770 if (ctxt == NULL)
2771 return (NULL);
2772
2773 if (ctxt->funcLookupFunc != NULL) {
2774 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002775 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002776
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002777 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002778 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002779 if (ret != NULL)
2780 return(ret);
2781 }
Owen Taylor3473f882001-02-23 17:55:21 +00002782 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2783}
2784
2785/**
2786 * xmlXPathFunctionLookupNS:
2787 * @ctxt: the XPath context
2788 * @name: the function name
2789 * @ns_uri: the function namespace URI
2790 *
2791 * Search in the Function array of the context for the given
2792 * function.
2793 *
2794 * Returns the xmlXPathFunction or NULL if not found
2795 */
2796xmlXPathFunction
2797xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2798 const xmlChar *ns_uri) {
2799 if (ctxt == NULL)
2800 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002801 if (name == NULL)
2802 return(NULL);
2803
Thomas Broyerba4ad322001-07-26 16:55:21 +00002804 if (ctxt->funcLookupFunc != NULL) {
2805 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002806 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002807
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002808 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002809 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002810 if (ret != NULL)
2811 return(ret);
2812 }
2813
2814 if (ctxt->funcHash == NULL)
2815 return(NULL);
2816
Owen Taylor3473f882001-02-23 17:55:21 +00002817 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2818}
2819
2820/**
2821 * xmlXPathRegisteredFuncsCleanup:
2822 * @ctxt: the XPath context
2823 *
2824 * Cleanup the XPath context data associated to registered functions
2825 */
2826void
2827xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2828 if (ctxt == NULL)
2829 return;
2830
2831 xmlHashFree(ctxt->funcHash, NULL);
2832 ctxt->funcHash = NULL;
2833}
2834
2835/************************************************************************
2836 * *
2837 * Routines to handle Variable *
2838 * *
2839 ************************************************************************/
2840
2841/**
2842 * xmlXPathRegisterVariable:
2843 * @ctxt: the XPath context
2844 * @name: the variable name
2845 * @value: the variable value or NULL
2846 *
2847 * Register a new variable value. If @value is NULL it unregisters
2848 * the variable
2849 *
2850 * Returns 0 in case of success, -1 in case of error
2851 */
2852int
2853xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2854 xmlXPathObjectPtr value) {
2855 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2856}
2857
2858/**
2859 * xmlXPathRegisterVariableNS:
2860 * @ctxt: the XPath context
2861 * @name: the variable name
2862 * @ns_uri: the variable namespace URI
2863 * @value: the variable value or NULL
2864 *
2865 * Register a new variable value. If @value is NULL it unregisters
2866 * the variable
2867 *
2868 * Returns 0 in case of success, -1 in case of error
2869 */
2870int
2871xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2872 const xmlChar *ns_uri,
2873 xmlXPathObjectPtr value) {
2874 if (ctxt == NULL)
2875 return(-1);
2876 if (name == NULL)
2877 return(-1);
2878
2879 if (ctxt->varHash == NULL)
2880 ctxt->varHash = xmlHashCreate(0);
2881 if (ctxt->varHash == NULL)
2882 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002883 if (value == NULL)
2884 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2885 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002886 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2887 (void *) value,
2888 (xmlHashDeallocator)xmlXPathFreeObject));
2889}
2890
2891/**
2892 * xmlXPathRegisterVariableLookup:
2893 * @ctxt: the XPath context
2894 * @f: the lookup function
2895 * @data: the lookup data
2896 *
2897 * register an external mechanism to do variable lookup
2898 */
2899void
2900xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2901 xmlXPathVariableLookupFunc f, void *data) {
2902 if (ctxt == NULL)
2903 return;
2904 ctxt->varLookupFunc = (void *) f;
2905 ctxt->varLookupData = data;
2906}
2907
2908/**
2909 * xmlXPathVariableLookup:
2910 * @ctxt: the XPath context
2911 * @name: the variable name
2912 *
2913 * Search in the Variable array of the context for the given
2914 * variable value.
2915 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002916 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002917 */
2918xmlXPathObjectPtr
2919xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2920 if (ctxt == NULL)
2921 return(NULL);
2922
2923 if (ctxt->varLookupFunc != NULL) {
2924 xmlXPathObjectPtr ret;
2925
2926 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2927 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002928 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002929 }
2930 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2931}
2932
2933/**
2934 * xmlXPathVariableLookupNS:
2935 * @ctxt: the XPath context
2936 * @name: the variable name
2937 * @ns_uri: the variable namespace URI
2938 *
2939 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002940 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002941 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002942 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002943 */
2944xmlXPathObjectPtr
2945xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2946 const xmlChar *ns_uri) {
2947 if (ctxt == NULL)
2948 return(NULL);
2949
2950 if (ctxt->varLookupFunc != NULL) {
2951 xmlXPathObjectPtr ret;
2952
2953 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2954 (ctxt->varLookupData, name, ns_uri);
2955 if (ret != NULL) return(ret);
2956 }
2957
2958 if (ctxt->varHash == NULL)
2959 return(NULL);
2960 if (name == NULL)
2961 return(NULL);
2962
Daniel Veillard8c357d52001-07-03 23:43:33 +00002963 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2964 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002965}
2966
2967/**
2968 * xmlXPathRegisteredVariablesCleanup:
2969 * @ctxt: the XPath context
2970 *
2971 * Cleanup the XPath context data associated to registered variables
2972 */
2973void
2974xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2975 if (ctxt == NULL)
2976 return;
2977
Daniel Veillard76d66f42001-05-16 21:05:17 +00002978 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002979 ctxt->varHash = NULL;
2980}
2981
2982/**
2983 * xmlXPathRegisterNs:
2984 * @ctxt: the XPath context
2985 * @prefix: the namespace prefix
2986 * @ns_uri: the namespace name
2987 *
2988 * Register a new namespace. If @ns_uri is NULL it unregisters
2989 * the namespace
2990 *
2991 * Returns 0 in case of success, -1 in case of error
2992 */
2993int
2994xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2995 const xmlChar *ns_uri) {
2996 if (ctxt == NULL)
2997 return(-1);
2998 if (prefix == NULL)
2999 return(-1);
3000
3001 if (ctxt->nsHash == NULL)
3002 ctxt->nsHash = xmlHashCreate(10);
3003 if (ctxt->nsHash == NULL)
3004 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003005 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003006 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003007 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003008 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003009 (xmlHashDeallocator)xmlFree));
3010}
3011
3012/**
3013 * xmlXPathNsLookup:
3014 * @ctxt: the XPath context
3015 * @prefix: the namespace prefix value
3016 *
3017 * Search in the namespace declaration array of the context for the given
3018 * namespace name associated to the given prefix
3019 *
3020 * Returns the value or NULL if not found
3021 */
3022const xmlChar *
3023xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3024 if (ctxt == NULL)
3025 return(NULL);
3026 if (prefix == NULL)
3027 return(NULL);
3028
3029#ifdef XML_XML_NAMESPACE
3030 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3031 return(XML_XML_NAMESPACE);
3032#endif
3033
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003034 if (ctxt->namespaces != NULL) {
3035 int i;
3036
3037 for (i = 0;i < ctxt->nsNr;i++) {
3038 if ((ctxt->namespaces[i] != NULL) &&
3039 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3040 return(ctxt->namespaces[i]->href);
3041 }
3042 }
Owen Taylor3473f882001-02-23 17:55:21 +00003043
3044 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3045}
3046
3047/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003048 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003049 * @ctxt: the XPath context
3050 *
3051 * Cleanup the XPath context data associated to registered variables
3052 */
3053void
3054xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3055 if (ctxt == NULL)
3056 return;
3057
Daniel Veillard42766c02002-08-22 20:52:17 +00003058 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003059 ctxt->nsHash = NULL;
3060}
3061
3062/************************************************************************
3063 * *
3064 * Routines to handle Values *
3065 * *
3066 ************************************************************************/
3067
3068/* Allocations are terrible, one need to optimize all this !!! */
3069
3070/**
3071 * xmlXPathNewFloat:
3072 * @val: the double value
3073 *
3074 * Create a new xmlXPathObjectPtr of type double and of value @val
3075 *
3076 * Returns the newly created object.
3077 */
3078xmlXPathObjectPtr
3079xmlXPathNewFloat(double val) {
3080 xmlXPathObjectPtr ret;
3081
3082 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3083 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003084 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003085 return(NULL);
3086 }
3087 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3088 ret->type = XPATH_NUMBER;
3089 ret->floatval = val;
3090 return(ret);
3091}
3092
3093/**
3094 * xmlXPathNewBoolean:
3095 * @val: the boolean value
3096 *
3097 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3098 *
3099 * Returns the newly created object.
3100 */
3101xmlXPathObjectPtr
3102xmlXPathNewBoolean(int val) {
3103 xmlXPathObjectPtr ret;
3104
3105 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3106 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003107 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003108 return(NULL);
3109 }
3110 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3111 ret->type = XPATH_BOOLEAN;
3112 ret->boolval = (val != 0);
3113 return(ret);
3114}
3115
3116/**
3117 * xmlXPathNewString:
3118 * @val: the xmlChar * value
3119 *
3120 * Create a new xmlXPathObjectPtr of type string and of value @val
3121 *
3122 * Returns the newly created object.
3123 */
3124xmlXPathObjectPtr
3125xmlXPathNewString(const xmlChar *val) {
3126 xmlXPathObjectPtr ret;
3127
3128 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3129 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003130 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003131 return(NULL);
3132 }
3133 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3134 ret->type = XPATH_STRING;
3135 if (val != NULL)
3136 ret->stringval = xmlStrdup(val);
3137 else
3138 ret->stringval = xmlStrdup((const xmlChar *)"");
3139 return(ret);
3140}
3141
3142/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003143 * xmlXPathWrapString:
3144 * @val: the xmlChar * value
3145 *
3146 * Wraps the @val string into an XPath object.
3147 *
3148 * Returns the newly created object.
3149 */
3150xmlXPathObjectPtr
3151xmlXPathWrapString (xmlChar *val) {
3152 xmlXPathObjectPtr ret;
3153
3154 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3155 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003156 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003157 return(NULL);
3158 }
3159 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3160 ret->type = XPATH_STRING;
3161 ret->stringval = val;
3162 return(ret);
3163}
3164
3165/**
Owen Taylor3473f882001-02-23 17:55:21 +00003166 * xmlXPathNewCString:
3167 * @val: the char * value
3168 *
3169 * Create a new xmlXPathObjectPtr of type string and of value @val
3170 *
3171 * Returns the newly created object.
3172 */
3173xmlXPathObjectPtr
3174xmlXPathNewCString(const char *val) {
3175 xmlXPathObjectPtr ret;
3176
3177 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3178 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003179 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003180 return(NULL);
3181 }
3182 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3183 ret->type = XPATH_STRING;
3184 ret->stringval = xmlStrdup(BAD_CAST val);
3185 return(ret);
3186}
3187
3188/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003189 * xmlXPathWrapCString:
3190 * @val: the char * value
3191 *
3192 * Wraps a string into an XPath object.
3193 *
3194 * Returns the newly created object.
3195 */
3196xmlXPathObjectPtr
3197xmlXPathWrapCString (char * val) {
3198 return(xmlXPathWrapString((xmlChar *)(val)));
3199}
3200
3201/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003202 * xmlXPathWrapExternal:
3203 * @val: the user data
3204 *
3205 * Wraps the @val data into an XPath object.
3206 *
3207 * Returns the newly created object.
3208 */
3209xmlXPathObjectPtr
3210xmlXPathWrapExternal (void *val) {
3211 xmlXPathObjectPtr ret;
3212
3213 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3214 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003215 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003216 return(NULL);
3217 }
3218 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3219 ret->type = XPATH_USERS;
3220 ret->user = val;
3221 return(ret);
3222}
3223
3224/**
Owen Taylor3473f882001-02-23 17:55:21 +00003225 * xmlXPathObjectCopy:
3226 * @val: the original object
3227 *
3228 * allocate a new copy of a given object
3229 *
3230 * Returns the newly created object.
3231 */
3232xmlXPathObjectPtr
3233xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3234 xmlXPathObjectPtr ret;
3235
3236 if (val == NULL)
3237 return(NULL);
3238
3239 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3240 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003241 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003242 return(NULL);
3243 }
3244 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3245 switch (val->type) {
3246 case XPATH_BOOLEAN:
3247 case XPATH_NUMBER:
3248 case XPATH_POINT:
3249 case XPATH_RANGE:
3250 break;
3251 case XPATH_STRING:
3252 ret->stringval = xmlStrdup(val->stringval);
3253 break;
3254 case XPATH_XSLT_TREE:
3255 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003256 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003257 xmlNodePtr cur, tmp;
3258 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003259
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003260 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003261 top = xmlNewDoc(NULL);
3262 top->name = (char *)
3263 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003264 ret->user = top;
3265 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003266 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003267 cur = val->nodesetval->nodeTab[0]->children;
3268 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003269 tmp = xmlDocCopyNode(cur, top, 1);
3270 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003271 cur = cur->next;
3272 }
3273 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003274 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003275 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003276 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003277 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003278 break;
3279 case XPATH_NODESET:
3280 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003281 /* Do not deallocate the copied tree value */
3282 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003283 break;
3284 case XPATH_LOCATIONSET:
3285#ifdef LIBXML_XPTR_ENABLED
3286 {
3287 xmlLocationSetPtr loc = val->user;
3288 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3289 break;
3290 }
3291#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003292 case XPATH_USERS:
3293 ret->user = val->user;
3294 break;
3295 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003296 xmlGenericError(xmlGenericErrorContext,
3297 "xmlXPathObjectCopy: unsupported type %d\n",
3298 val->type);
3299 break;
3300 }
3301 return(ret);
3302}
3303
3304/**
3305 * xmlXPathFreeObject:
3306 * @obj: the object to free
3307 *
3308 * Free up an xmlXPathObjectPtr object.
3309 */
3310void
3311xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3312 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003313 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003314 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003315 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003316 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003317 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003318 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003319 xmlXPathFreeValueTree(obj->nodesetval);
3320 } else {
3321 if (obj->nodesetval != NULL)
3322 xmlXPathFreeNodeSet(obj->nodesetval);
3323 }
Owen Taylor3473f882001-02-23 17:55:21 +00003324#ifdef LIBXML_XPTR_ENABLED
3325 } else if (obj->type == XPATH_LOCATIONSET) {
3326 if (obj->user != NULL)
3327 xmlXPtrFreeLocationSet(obj->user);
3328#endif
3329 } else if (obj->type == XPATH_STRING) {
3330 if (obj->stringval != NULL)
3331 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003332 }
3333
Owen Taylor3473f882001-02-23 17:55:21 +00003334 xmlFree(obj);
3335}
3336
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003337
3338/************************************************************************
3339 * *
3340 * Type Casting Routines *
3341 * *
3342 ************************************************************************/
3343
3344/**
3345 * xmlXPathCastBooleanToString:
3346 * @val: a boolean
3347 *
3348 * Converts a boolean to its string value.
3349 *
3350 * Returns a newly allocated string.
3351 */
3352xmlChar *
3353xmlXPathCastBooleanToString (int val) {
3354 xmlChar *ret;
3355 if (val)
3356 ret = xmlStrdup((const xmlChar *) "true");
3357 else
3358 ret = xmlStrdup((const xmlChar *) "false");
3359 return(ret);
3360}
3361
3362/**
3363 * xmlXPathCastNumberToString:
3364 * @val: a number
3365 *
3366 * Converts a number to its string value.
3367 *
3368 * Returns a newly allocated string.
3369 */
3370xmlChar *
3371xmlXPathCastNumberToString (double val) {
3372 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003373 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003374 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003375 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003376 break;
3377 case -1:
3378 ret = xmlStrdup((const xmlChar *) "-Infinity");
3379 break;
3380 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003381 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003382 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003383 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3384 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003385 } else {
3386 /* could be improved */
3387 char buf[100];
3388 xmlXPathFormatNumber(val, buf, 100);
3389 ret = xmlStrdup((const xmlChar *) buf);
3390 }
3391 }
3392 return(ret);
3393}
3394
3395/**
3396 * xmlXPathCastNodeToString:
3397 * @node: a node
3398 *
3399 * Converts a node to its string value.
3400 *
3401 * Returns a newly allocated string.
3402 */
3403xmlChar *
3404xmlXPathCastNodeToString (xmlNodePtr node) {
3405 return(xmlNodeGetContent(node));
3406}
3407
3408/**
3409 * xmlXPathCastNodeSetToString:
3410 * @ns: a node-set
3411 *
3412 * Converts a node-set to its string value.
3413 *
3414 * Returns a newly allocated string.
3415 */
3416xmlChar *
3417xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3418 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3419 return(xmlStrdup((const xmlChar *) ""));
3420
3421 xmlXPathNodeSetSort(ns);
3422 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3423}
3424
3425/**
3426 * xmlXPathCastToString:
3427 * @val: an XPath object
3428 *
3429 * Converts an existing object to its string() equivalent
3430 *
3431 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003432 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003433 * string object).
3434 */
3435xmlChar *
3436xmlXPathCastToString(xmlXPathObjectPtr val) {
3437 xmlChar *ret = NULL;
3438
3439 if (val == NULL)
3440 return(xmlStrdup((const xmlChar *) ""));
3441 switch (val->type) {
3442 case XPATH_UNDEFINED:
3443#ifdef DEBUG_EXPR
3444 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3445#endif
3446 ret = xmlStrdup((const xmlChar *) "");
3447 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003448 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003449 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003450 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3451 break;
3452 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003453 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003454 case XPATH_BOOLEAN:
3455 ret = xmlXPathCastBooleanToString(val->boolval);
3456 break;
3457 case XPATH_NUMBER: {
3458 ret = xmlXPathCastNumberToString(val->floatval);
3459 break;
3460 }
3461 case XPATH_USERS:
3462 case XPATH_POINT:
3463 case XPATH_RANGE:
3464 case XPATH_LOCATIONSET:
3465 TODO
3466 ret = xmlStrdup((const xmlChar *) "");
3467 break;
3468 }
3469 return(ret);
3470}
3471
3472/**
3473 * xmlXPathConvertString:
3474 * @val: an XPath object
3475 *
3476 * Converts an existing object to its string() equivalent
3477 *
3478 * Returns the new object, the old one is freed (or the operation
3479 * is done directly on @val)
3480 */
3481xmlXPathObjectPtr
3482xmlXPathConvertString(xmlXPathObjectPtr val) {
3483 xmlChar *res = NULL;
3484
3485 if (val == NULL)
3486 return(xmlXPathNewCString(""));
3487
3488 switch (val->type) {
3489 case XPATH_UNDEFINED:
3490#ifdef DEBUG_EXPR
3491 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3492#endif
3493 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003494 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003495 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003496 res = xmlXPathCastNodeSetToString(val->nodesetval);
3497 break;
3498 case XPATH_STRING:
3499 return(val);
3500 case XPATH_BOOLEAN:
3501 res = xmlXPathCastBooleanToString(val->boolval);
3502 break;
3503 case XPATH_NUMBER:
3504 res = xmlXPathCastNumberToString(val->floatval);
3505 break;
3506 case XPATH_USERS:
3507 case XPATH_POINT:
3508 case XPATH_RANGE:
3509 case XPATH_LOCATIONSET:
3510 TODO;
3511 break;
3512 }
3513 xmlXPathFreeObject(val);
3514 if (res == NULL)
3515 return(xmlXPathNewCString(""));
3516 return(xmlXPathWrapString(res));
3517}
3518
3519/**
3520 * xmlXPathCastBooleanToNumber:
3521 * @val: a boolean
3522 *
3523 * Converts a boolean to its number value
3524 *
3525 * Returns the number value
3526 */
3527double
3528xmlXPathCastBooleanToNumber(int val) {
3529 if (val)
3530 return(1.0);
3531 return(0.0);
3532}
3533
3534/**
3535 * xmlXPathCastStringToNumber:
3536 * @val: a string
3537 *
3538 * Converts a string to its number value
3539 *
3540 * Returns the number value
3541 */
3542double
3543xmlXPathCastStringToNumber(const xmlChar * val) {
3544 return(xmlXPathStringEvalNumber(val));
3545}
3546
3547/**
3548 * xmlXPathCastNodeToNumber:
3549 * @node: a node
3550 *
3551 * Converts a node to its number value
3552 *
3553 * Returns the number value
3554 */
3555double
3556xmlXPathCastNodeToNumber (xmlNodePtr node) {
3557 xmlChar *strval;
3558 double ret;
3559
3560 if (node == NULL)
3561 return(xmlXPathNAN);
3562 strval = xmlXPathCastNodeToString(node);
3563 if (strval == NULL)
3564 return(xmlXPathNAN);
3565 ret = xmlXPathCastStringToNumber(strval);
3566 xmlFree(strval);
3567
3568 return(ret);
3569}
3570
3571/**
3572 * xmlXPathCastNodeSetToNumber:
3573 * @ns: a node-set
3574 *
3575 * Converts a node-set to its number value
3576 *
3577 * Returns the number value
3578 */
3579double
3580xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3581 xmlChar *str;
3582 double ret;
3583
3584 if (ns == NULL)
3585 return(xmlXPathNAN);
3586 str = xmlXPathCastNodeSetToString(ns);
3587 ret = xmlXPathCastStringToNumber(str);
3588 xmlFree(str);
3589 return(ret);
3590}
3591
3592/**
3593 * xmlXPathCastToNumber:
3594 * @val: an XPath object
3595 *
3596 * Converts an XPath object to its number value
3597 *
3598 * Returns the number value
3599 */
3600double
3601xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3602 double ret = 0.0;
3603
3604 if (val == NULL)
3605 return(xmlXPathNAN);
3606 switch (val->type) {
3607 case XPATH_UNDEFINED:
3608#ifdef DEGUB_EXPR
3609 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3610#endif
3611 ret = xmlXPathNAN;
3612 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003613 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003614 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003615 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3616 break;
3617 case XPATH_STRING:
3618 ret = xmlXPathCastStringToNumber(val->stringval);
3619 break;
3620 case XPATH_NUMBER:
3621 ret = val->floatval;
3622 break;
3623 case XPATH_BOOLEAN:
3624 ret = xmlXPathCastBooleanToNumber(val->boolval);
3625 break;
3626 case XPATH_USERS:
3627 case XPATH_POINT:
3628 case XPATH_RANGE:
3629 case XPATH_LOCATIONSET:
3630 TODO;
3631 ret = xmlXPathNAN;
3632 break;
3633 }
3634 return(ret);
3635}
3636
3637/**
3638 * xmlXPathConvertNumber:
3639 * @val: an XPath object
3640 *
3641 * Converts an existing object to its number() equivalent
3642 *
3643 * Returns the new object, the old one is freed (or the operation
3644 * is done directly on @val)
3645 */
3646xmlXPathObjectPtr
3647xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3648 xmlXPathObjectPtr ret;
3649
3650 if (val == NULL)
3651 return(xmlXPathNewFloat(0.0));
3652 if (val->type == XPATH_NUMBER)
3653 return(val);
3654 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3655 xmlXPathFreeObject(val);
3656 return(ret);
3657}
3658
3659/**
3660 * xmlXPathCastNumberToBoolean:
3661 * @val: a number
3662 *
3663 * Converts a number to its boolean value
3664 *
3665 * Returns the boolean value
3666 */
3667int
3668xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003669 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003670 return(0);
3671 return(1);
3672}
3673
3674/**
3675 * xmlXPathCastStringToBoolean:
3676 * @val: a string
3677 *
3678 * Converts a string to its boolean value
3679 *
3680 * Returns the boolean value
3681 */
3682int
3683xmlXPathCastStringToBoolean (const xmlChar *val) {
3684 if ((val == NULL) || (xmlStrlen(val) == 0))
3685 return(0);
3686 return(1);
3687}
3688
3689/**
3690 * xmlXPathCastNodeSetToBoolean:
3691 * @ns: a node-set
3692 *
3693 * Converts a node-set to its boolean value
3694 *
3695 * Returns the boolean value
3696 */
3697int
3698xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3699 if ((ns == NULL) || (ns->nodeNr == 0))
3700 return(0);
3701 return(1);
3702}
3703
3704/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003705 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003706 * @val: an XPath object
3707 *
3708 * Converts an XPath object to its boolean value
3709 *
3710 * Returns the boolean value
3711 */
3712int
3713xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3714 int ret = 0;
3715
3716 if (val == NULL)
3717 return(0);
3718 switch (val->type) {
3719 case XPATH_UNDEFINED:
3720#ifdef DEBUG_EXPR
3721 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3722#endif
3723 ret = 0;
3724 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003725 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003726 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003727 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3728 break;
3729 case XPATH_STRING:
3730 ret = xmlXPathCastStringToBoolean(val->stringval);
3731 break;
3732 case XPATH_NUMBER:
3733 ret = xmlXPathCastNumberToBoolean(val->floatval);
3734 break;
3735 case XPATH_BOOLEAN:
3736 ret = val->boolval;
3737 break;
3738 case XPATH_USERS:
3739 case XPATH_POINT:
3740 case XPATH_RANGE:
3741 case XPATH_LOCATIONSET:
3742 TODO;
3743 ret = 0;
3744 break;
3745 }
3746 return(ret);
3747}
3748
3749
3750/**
3751 * xmlXPathConvertBoolean:
3752 * @val: an XPath object
3753 *
3754 * Converts an existing object to its boolean() equivalent
3755 *
3756 * Returns the new object, the old one is freed (or the operation
3757 * is done directly on @val)
3758 */
3759xmlXPathObjectPtr
3760xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3761 xmlXPathObjectPtr ret;
3762
3763 if (val == NULL)
3764 return(xmlXPathNewBoolean(0));
3765 if (val->type == XPATH_BOOLEAN)
3766 return(val);
3767 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3768 xmlXPathFreeObject(val);
3769 return(ret);
3770}
3771
Owen Taylor3473f882001-02-23 17:55:21 +00003772/************************************************************************
3773 * *
3774 * Routines to handle XPath contexts *
3775 * *
3776 ************************************************************************/
3777
3778/**
3779 * xmlXPathNewContext:
3780 * @doc: the XML document
3781 *
3782 * Create a new xmlXPathContext
3783 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003784 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003785 */
3786xmlXPathContextPtr
3787xmlXPathNewContext(xmlDocPtr doc) {
3788 xmlXPathContextPtr ret;
3789
3790 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3791 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003792 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003793 return(NULL);
3794 }
3795 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3796 ret->doc = doc;
3797 ret->node = NULL;
3798
3799 ret->varHash = NULL;
3800
3801 ret->nb_types = 0;
3802 ret->max_types = 0;
3803 ret->types = NULL;
3804
3805 ret->funcHash = xmlHashCreate(0);
3806
3807 ret->nb_axis = 0;
3808 ret->max_axis = 0;
3809 ret->axis = NULL;
3810
3811 ret->nsHash = NULL;
3812 ret->user = NULL;
3813
3814 ret->contextSize = -1;
3815 ret->proximityPosition = -1;
3816
3817 xmlXPathRegisterAllFunctions(ret);
3818
3819 return(ret);
3820}
3821
3822/**
3823 * xmlXPathFreeContext:
3824 * @ctxt: the context to free
3825 *
3826 * Free up an xmlXPathContext
3827 */
3828void
3829xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3830 xmlXPathRegisteredNsCleanup(ctxt);
3831 xmlXPathRegisteredFuncsCleanup(ctxt);
3832 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003833 xmlFree(ctxt);
3834}
3835
3836/************************************************************************
3837 * *
3838 * Routines to handle XPath parser contexts *
3839 * *
3840 ************************************************************************/
3841
3842#define CHECK_CTXT(ctxt) \
3843 if (ctxt == NULL) { \
3844 xmlGenericError(xmlGenericErrorContext, \
3845 "%s:%d Internal error: ctxt == NULL\n", \
3846 __FILE__, __LINE__); \
3847 } \
3848
3849
3850#define CHECK_CONTEXT(ctxt) \
3851 if (ctxt == NULL) { \
3852 xmlGenericError(xmlGenericErrorContext, \
3853 "%s:%d Internal error: no context\n", \
3854 __FILE__, __LINE__); \
3855 } \
3856 else if (ctxt->doc == NULL) { \
3857 xmlGenericError(xmlGenericErrorContext, \
3858 "%s:%d Internal error: no document\n", \
3859 __FILE__, __LINE__); \
3860 } \
3861 else if (ctxt->doc->children == NULL) { \
3862 xmlGenericError(xmlGenericErrorContext, \
3863 "%s:%d Internal error: document without root\n", \
3864 __FILE__, __LINE__); \
3865 } \
3866
3867
3868/**
3869 * xmlXPathNewParserContext:
3870 * @str: the XPath expression
3871 * @ctxt: the XPath context
3872 *
3873 * Create a new xmlXPathParserContext
3874 *
3875 * Returns the xmlXPathParserContext just allocated.
3876 */
3877xmlXPathParserContextPtr
3878xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3879 xmlXPathParserContextPtr ret;
3880
3881 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3882 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003883 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003884 return(NULL);
3885 }
3886 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3887 ret->cur = ret->base = str;
3888 ret->context = ctxt;
3889
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003890 ret->comp = xmlXPathNewCompExpr();
3891 if (ret->comp == NULL) {
3892 xmlFree(ret->valueTab);
3893 xmlFree(ret);
3894 return(NULL);
3895 }
3896
3897 return(ret);
3898}
3899
3900/**
3901 * xmlXPathCompParserContext:
3902 * @comp: the XPath compiled expression
3903 * @ctxt: the XPath context
3904 *
3905 * Create a new xmlXPathParserContext when processing a compiled expression
3906 *
3907 * Returns the xmlXPathParserContext just allocated.
3908 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003909static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003910xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3911 xmlXPathParserContextPtr ret;
3912
3913 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3914 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003915 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003916 return(NULL);
3917 }
3918 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3919
Owen Taylor3473f882001-02-23 17:55:21 +00003920 /* Allocate the value stack */
3921 ret->valueTab = (xmlXPathObjectPtr *)
3922 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003923 if (ret->valueTab == NULL) {
3924 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003925 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003926 return(NULL);
3927 }
Owen Taylor3473f882001-02-23 17:55:21 +00003928 ret->valueNr = 0;
3929 ret->valueMax = 10;
3930 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003931
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003932 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003933 ret->comp = comp;
3934
Owen Taylor3473f882001-02-23 17:55:21 +00003935 return(ret);
3936}
3937
3938/**
3939 * xmlXPathFreeParserContext:
3940 * @ctxt: the context to free
3941 *
3942 * Free up an xmlXPathParserContext
3943 */
3944void
3945xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3946 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003947 xmlFree(ctxt->valueTab);
3948 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003949 if (ctxt->comp)
3950 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003951 xmlFree(ctxt);
3952}
3953
3954/************************************************************************
3955 * *
3956 * The implicit core function library *
3957 * *
3958 ************************************************************************/
3959
Owen Taylor3473f882001-02-23 17:55:21 +00003960/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003961 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003962 * @node: a node pointer
3963 *
3964 * Function computing the beginning of the string value of the node,
3965 * used to speed up comparisons
3966 *
3967 * Returns an int usable as a hash
3968 */
3969static unsigned int
3970xmlXPathNodeValHash(xmlNodePtr node) {
3971 int len = 2;
3972 const xmlChar * string = NULL;
3973 xmlNodePtr tmp = NULL;
3974 unsigned int ret = 0;
3975
3976 if (node == NULL)
3977 return(0);
3978
Daniel Veillard9adc0462003-03-24 18:39:54 +00003979 if (node->type == XML_DOCUMENT_NODE) {
3980 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3981 if (tmp == NULL)
3982 node = node->children;
3983 else
3984 node = tmp;
3985
3986 if (node == NULL)
3987 return(0);
3988 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003989
3990 switch (node->type) {
3991 case XML_COMMENT_NODE:
3992 case XML_PI_NODE:
3993 case XML_CDATA_SECTION_NODE:
3994 case XML_TEXT_NODE:
3995 string = node->content;
3996 if (string == NULL)
3997 return(0);
3998 if (string[0] == 0)
3999 return(0);
4000 return(((unsigned int) string[0]) +
4001 (((unsigned int) string[1]) << 8));
4002 case XML_NAMESPACE_DECL:
4003 string = ((xmlNsPtr)node)->href;
4004 if (string == NULL)
4005 return(0);
4006 if (string[0] == 0)
4007 return(0);
4008 return(((unsigned int) string[0]) +
4009 (((unsigned int) string[1]) << 8));
4010 case XML_ATTRIBUTE_NODE:
4011 tmp = ((xmlAttrPtr) node)->children;
4012 break;
4013 case XML_ELEMENT_NODE:
4014 tmp = node->children;
4015 break;
4016 default:
4017 return(0);
4018 }
4019 while (tmp != NULL) {
4020 switch (tmp->type) {
4021 case XML_COMMENT_NODE:
4022 case XML_PI_NODE:
4023 case XML_CDATA_SECTION_NODE:
4024 case XML_TEXT_NODE:
4025 string = tmp->content;
4026 break;
4027 case XML_NAMESPACE_DECL:
4028 string = ((xmlNsPtr)tmp)->href;
4029 break;
4030 default:
4031 break;
4032 }
4033 if ((string != NULL) && (string[0] != 0)) {
4034 if (string[0] == 0)
4035 return(0);
4036 if (len == 1) {
4037 return(ret + (((unsigned int) string[0]) << 8));
4038 }
4039 if (string[1] == 0) {
4040 len = 1;
4041 ret = (unsigned int) string[0];
4042 } else {
4043 return(((unsigned int) string[0]) +
4044 (((unsigned int) string[1]) << 8));
4045 }
4046 }
4047 /*
4048 * Skip to next node
4049 */
4050 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4051 if (tmp->children->type != XML_ENTITY_DECL) {
4052 tmp = tmp->children;
4053 continue;
4054 }
4055 }
4056 if (tmp == node)
4057 break;
4058
4059 if (tmp->next != NULL) {
4060 tmp = tmp->next;
4061 continue;
4062 }
4063
4064 do {
4065 tmp = tmp->parent;
4066 if (tmp == NULL)
4067 break;
4068 if (tmp == node) {
4069 tmp = NULL;
4070 break;
4071 }
4072 if (tmp->next != NULL) {
4073 tmp = tmp->next;
4074 break;
4075 }
4076 } while (tmp != NULL);
4077 }
4078 return(ret);
4079}
4080
4081/**
4082 * xmlXPathStringHash:
4083 * @string: a string
4084 *
4085 * Function computing the beginning of the string value of the node,
4086 * used to speed up comparisons
4087 *
4088 * Returns an int usable as a hash
4089 */
4090static unsigned int
4091xmlXPathStringHash(const xmlChar * string) {
4092 if (string == NULL)
4093 return((unsigned int) 0);
4094 if (string[0] == 0)
4095 return(0);
4096 return(((unsigned int) string[0]) +
4097 (((unsigned int) string[1]) << 8));
4098}
4099
4100/**
Owen Taylor3473f882001-02-23 17:55:21 +00004101 * xmlXPathCompareNodeSetFloat:
4102 * @ctxt: the XPath Parser context
4103 * @inf: less than (1) or greater than (0)
4104 * @strict: is the comparison strict
4105 * @arg: the node set
4106 * @f: the value
4107 *
4108 * Implement the compare operation between a nodeset and a number
4109 * @ns < @val (1, 1, ...
4110 * @ns <= @val (1, 0, ...
4111 * @ns > @val (0, 1, ...
4112 * @ns >= @val (0, 0, ...
4113 *
4114 * If one object to be compared is a node-set and the other is a number,
4115 * then the comparison will be true if and only if there is a node in the
4116 * node-set such that the result of performing the comparison on the number
4117 * to be compared and on the result of converting the string-value of that
4118 * node to a number using the number function is true.
4119 *
4120 * Returns 0 or 1 depending on the results of the test.
4121 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004122static int
Owen Taylor3473f882001-02-23 17:55:21 +00004123xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4124 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4125 int i, ret = 0;
4126 xmlNodeSetPtr ns;
4127 xmlChar *str2;
4128
4129 if ((f == NULL) || (arg == NULL) ||
4130 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4131 xmlXPathFreeObject(arg);
4132 xmlXPathFreeObject(f);
4133 return(0);
4134 }
4135 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004136 if (ns != NULL) {
4137 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004138 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004139 if (str2 != NULL) {
4140 valuePush(ctxt,
4141 xmlXPathNewString(str2));
4142 xmlFree(str2);
4143 xmlXPathNumberFunction(ctxt, 1);
4144 valuePush(ctxt, xmlXPathObjectCopy(f));
4145 ret = xmlXPathCompareValues(ctxt, inf, strict);
4146 if (ret)
4147 break;
4148 }
4149 }
Owen Taylor3473f882001-02-23 17:55:21 +00004150 }
4151 xmlXPathFreeObject(arg);
4152 xmlXPathFreeObject(f);
4153 return(ret);
4154}
4155
4156/**
4157 * xmlXPathCompareNodeSetString:
4158 * @ctxt: the XPath Parser context
4159 * @inf: less than (1) or greater than (0)
4160 * @strict: is the comparison strict
4161 * @arg: the node set
4162 * @s: the value
4163 *
4164 * Implement the compare operation between a nodeset and a string
4165 * @ns < @val (1, 1, ...
4166 * @ns <= @val (1, 0, ...
4167 * @ns > @val (0, 1, ...
4168 * @ns >= @val (0, 0, ...
4169 *
4170 * If one object to be compared is a node-set and the other is a string,
4171 * then the comparison will be true if and only if there is a node in
4172 * the node-set such that the result of performing the comparison on the
4173 * string-value of the node and the other string is true.
4174 *
4175 * Returns 0 or 1 depending on the results of the test.
4176 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004177static int
Owen Taylor3473f882001-02-23 17:55:21 +00004178xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4179 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4180 int i, ret = 0;
4181 xmlNodeSetPtr ns;
4182 xmlChar *str2;
4183
4184 if ((s == NULL) || (arg == NULL) ||
4185 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4186 xmlXPathFreeObject(arg);
4187 xmlXPathFreeObject(s);
4188 return(0);
4189 }
4190 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004191 if (ns != NULL) {
4192 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004193 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004194 if (str2 != NULL) {
4195 valuePush(ctxt,
4196 xmlXPathNewString(str2));
4197 xmlFree(str2);
4198 valuePush(ctxt, xmlXPathObjectCopy(s));
4199 ret = xmlXPathCompareValues(ctxt, inf, strict);
4200 if (ret)
4201 break;
4202 }
4203 }
Owen Taylor3473f882001-02-23 17:55:21 +00004204 }
4205 xmlXPathFreeObject(arg);
4206 xmlXPathFreeObject(s);
4207 return(ret);
4208}
4209
4210/**
4211 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004212 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004213 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004214 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004215 * @arg2: the second node set object
4216 *
4217 * Implement the compare operation on nodesets:
4218 *
4219 * If both objects to be compared are node-sets, then the comparison
4220 * will be true if and only if there is a node in the first node-set
4221 * and a node in the second node-set such that the result of performing
4222 * the comparison on the string-values of the two nodes is true.
4223 * ....
4224 * When neither object to be compared is a node-set and the operator
4225 * is <=, <, >= or >, then the objects are compared by converting both
4226 * objects to numbers and comparing the numbers according to IEEE 754.
4227 * ....
4228 * The number function converts its argument to a number as follows:
4229 * - a string that consists of optional whitespace followed by an
4230 * optional minus sign followed by a Number followed by whitespace
4231 * is converted to the IEEE 754 number that is nearest (according
4232 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4233 * represented by the string; any other string is converted to NaN
4234 *
4235 * Conclusion all nodes need to be converted first to their string value
4236 * and then the comparison must be done when possible
4237 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004238static int
4239xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004240 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4241 int i, j, init = 0;
4242 double val1;
4243 double *values2;
4244 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004245 xmlNodeSetPtr ns1;
4246 xmlNodeSetPtr ns2;
4247
4248 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004249 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4250 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004251 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004252 }
Owen Taylor3473f882001-02-23 17:55:21 +00004253 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004254 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4255 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 ns1 = arg1->nodesetval;
4261 ns2 = arg2->nodesetval;
4262
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004263 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004264 xmlXPathFreeObject(arg1);
4265 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004266 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004267 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004268 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004269 xmlXPathFreeObject(arg1);
4270 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004271 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004272 }
Owen Taylor3473f882001-02-23 17:55:21 +00004273
4274 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4275 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004276 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004277 xmlXPathFreeObject(arg1);
4278 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004279 return(0);
4280 }
4281 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004282 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004283 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004284 continue;
4285 for (j = 0;j < ns2->nodeNr;j++) {
4286 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004287 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004288 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004289 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004290 continue;
4291 if (inf && strict)
4292 ret = (val1 < values2[j]);
4293 else if (inf && !strict)
4294 ret = (val1 <= values2[j]);
4295 else if (!inf && strict)
4296 ret = (val1 > values2[j]);
4297 else if (!inf && !strict)
4298 ret = (val1 >= values2[j]);
4299 if (ret)
4300 break;
4301 }
4302 if (ret)
4303 break;
4304 init = 1;
4305 }
4306 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004307 xmlXPathFreeObject(arg1);
4308 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004309 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004310}
4311
4312/**
4313 * xmlXPathCompareNodeSetValue:
4314 * @ctxt: the XPath Parser context
4315 * @inf: less than (1) or greater than (0)
4316 * @strict: is the comparison strict
4317 * @arg: the node set
4318 * @val: the value
4319 *
4320 * Implement the compare operation between a nodeset and a value
4321 * @ns < @val (1, 1, ...
4322 * @ns <= @val (1, 0, ...
4323 * @ns > @val (0, 1, ...
4324 * @ns >= @val (0, 0, ...
4325 *
4326 * If one object to be compared is a node-set and the other is a boolean,
4327 * then the comparison will be true if and only if the result of performing
4328 * the comparison on the boolean and on the result of converting
4329 * the node-set to a boolean using the boolean function is true.
4330 *
4331 * Returns 0 or 1 depending on the results of the test.
4332 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004333static int
Owen Taylor3473f882001-02-23 17:55:21 +00004334xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4335 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4336 if ((val == NULL) || (arg == NULL) ||
4337 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4338 return(0);
4339
4340 switch(val->type) {
4341 case XPATH_NUMBER:
4342 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4343 case XPATH_NODESET:
4344 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004345 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004346 case XPATH_STRING:
4347 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4348 case XPATH_BOOLEAN:
4349 valuePush(ctxt, arg);
4350 xmlXPathBooleanFunction(ctxt, 1);
4351 valuePush(ctxt, val);
4352 return(xmlXPathCompareValues(ctxt, inf, strict));
4353 default:
4354 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004355 }
4356 return(0);
4357}
4358
4359/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004360 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004361 * @arg: the nodeset object argument
4362 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004363 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004364 *
4365 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4366 * If one object to be compared is a node-set and the other is a string,
4367 * then the comparison will be true if and only if there is a node in
4368 * the node-set such that the result of performing the comparison on the
4369 * string-value of the node and the other string is true.
4370 *
4371 * Returns 0 or 1 depending on the results of the test.
4372 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004373static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004374xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004375{
Owen Taylor3473f882001-02-23 17:55:21 +00004376 int i;
4377 xmlNodeSetPtr ns;
4378 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004379 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004380
4381 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004382 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4383 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004384 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004385 /*
4386 * A NULL nodeset compared with a string is always false
4387 * (since there is no node equal, and no node not equal)
4388 */
4389 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004390 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004391 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004392 for (i = 0; i < ns->nodeNr; i++) {
4393 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4394 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4395 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4396 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004397 if (neq)
4398 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004399 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004400 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4401 if (neq)
4402 continue;
4403 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004404 } else if (neq) {
4405 if (str2 != NULL)
4406 xmlFree(str2);
4407 return (1);
4408 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004409 if (str2 != NULL)
4410 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004411 } else if (neq)
4412 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004413 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004414 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004415}
4416
4417/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004418 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004419 * @arg: the nodeset object argument
4420 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004421 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004422 *
4423 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4424 * If one object to be compared is a node-set and the other is a number,
4425 * then the comparison will be true if and only if there is a node in
4426 * the node-set such that the result of performing the comparison on the
4427 * number to be compared and on the result of converting the string-value
4428 * of that node to a number using the number function is true.
4429 *
4430 * Returns 0 or 1 depending on the results of the test.
4431 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004432static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004433xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4434 xmlXPathObjectPtr arg, double f, int neq) {
4435 int i, ret=0;
4436 xmlNodeSetPtr ns;
4437 xmlChar *str2;
4438 xmlXPathObjectPtr val;
4439 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004440
4441 if ((arg == NULL) ||
4442 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4443 return(0);
4444
William M. Brack0c022ad2002-07-12 00:56:01 +00004445 ns = arg->nodesetval;
4446 if (ns != NULL) {
4447 for (i=0;i<ns->nodeNr;i++) {
4448 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4449 if (str2 != NULL) {
4450 valuePush(ctxt, xmlXPathNewString(str2));
4451 xmlFree(str2);
4452 xmlXPathNumberFunction(ctxt, 1);
4453 val = valuePop(ctxt);
4454 v = val->floatval;
4455 xmlXPathFreeObject(val);
4456 if (!xmlXPathIsNaN(v)) {
4457 if ((!neq) && (v==f)) {
4458 ret = 1;
4459 break;
4460 } else if ((neq) && (v!=f)) {
4461 ret = 1;
4462 break;
4463 }
4464 }
4465 }
4466 }
4467 }
4468
4469 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004470}
4471
4472
4473/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004474 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004475 * @arg1: first nodeset object argument
4476 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004477 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004478 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004479 * Implement the equal / not equal operation on XPath nodesets:
4480 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004481 * If both objects to be compared are node-sets, then the comparison
4482 * will be true if and only if there is a node in the first node-set and
4483 * a node in the second node-set such that the result of performing the
4484 * comparison on the string-values of the two nodes is true.
4485 *
4486 * (needless to say, this is a costly operation)
4487 *
4488 * Returns 0 or 1 depending on the results of the test.
4489 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004490static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004491xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004492 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004493 unsigned int *hashs1;
4494 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004495 xmlChar **values1;
4496 xmlChar **values2;
4497 int ret = 0;
4498 xmlNodeSetPtr ns1;
4499 xmlNodeSetPtr ns2;
4500
4501 if ((arg1 == NULL) ||
4502 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4503 return(0);
4504 if ((arg2 == NULL) ||
4505 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4506 return(0);
4507
4508 ns1 = arg1->nodesetval;
4509 ns2 = arg2->nodesetval;
4510
Daniel Veillard911f49a2001-04-07 15:39:35 +00004511 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004512 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004513 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004514 return(0);
4515
4516 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004517 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004518 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004519 if (neq == 0)
4520 for (i = 0;i < ns1->nodeNr;i++)
4521 for (j = 0;j < ns2->nodeNr;j++)
4522 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4523 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004524
4525 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004526 if (values1 == NULL) {
4527 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004528 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004529 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004530 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4531 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004532 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004533 xmlFree(values1);
4534 return(0);
4535 }
Owen Taylor3473f882001-02-23 17:55:21 +00004536 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4537 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4538 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004539 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004540 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004541 xmlFree(values1);
4542 return(0);
4543 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004544 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4545 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004546 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004547 xmlFree(hashs1);
4548 xmlFree(values1);
4549 xmlFree(values2);
4550 return(0);
4551 }
Owen Taylor3473f882001-02-23 17:55:21 +00004552 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4553 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004554 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004555 for (j = 0;j < ns2->nodeNr;j++) {
4556 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004557 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004558 if (hashs1[i] != hashs2[j]) {
4559 if (neq) {
4560 ret = 1;
4561 break;
4562 }
4563 }
4564 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004565 if (values1[i] == NULL)
4566 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4567 if (values2[j] == NULL)
4568 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004569 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004570 if (ret)
4571 break;
4572 }
Owen Taylor3473f882001-02-23 17:55:21 +00004573 }
4574 if (ret)
4575 break;
4576 }
4577 for (i = 0;i < ns1->nodeNr;i++)
4578 if (values1[i] != NULL)
4579 xmlFree(values1[i]);
4580 for (j = 0;j < ns2->nodeNr;j++)
4581 if (values2[j] != NULL)
4582 xmlFree(values2[j]);
4583 xmlFree(values1);
4584 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004585 xmlFree(hashs1);
4586 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004587 return(ret);
4588}
4589
William M. Brack0c022ad2002-07-12 00:56:01 +00004590static int
4591xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4592 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004593 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004594 /*
4595 *At this point we are assured neither arg1 nor arg2
4596 *is a nodeset, so we can just pick the appropriate routine.
4597 */
Owen Taylor3473f882001-02-23 17:55:21 +00004598 switch (arg1->type) {
4599 case XPATH_UNDEFINED:
4600#ifdef DEBUG_EXPR
4601 xmlGenericError(xmlGenericErrorContext,
4602 "Equal: undefined\n");
4603#endif
4604 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004605 case XPATH_BOOLEAN:
4606 switch (arg2->type) {
4607 case XPATH_UNDEFINED:
4608#ifdef DEBUG_EXPR
4609 xmlGenericError(xmlGenericErrorContext,
4610 "Equal: undefined\n");
4611#endif
4612 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004613 case XPATH_BOOLEAN:
4614#ifdef DEBUG_EXPR
4615 xmlGenericError(xmlGenericErrorContext,
4616 "Equal: %d boolean %d \n",
4617 arg1->boolval, arg2->boolval);
4618#endif
4619 ret = (arg1->boolval == arg2->boolval);
4620 break;
4621 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004622 ret = (arg1->boolval ==
4623 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004624 break;
4625 case XPATH_STRING:
4626 if ((arg2->stringval == NULL) ||
4627 (arg2->stringval[0] == 0)) ret = 0;
4628 else
4629 ret = 1;
4630 ret = (arg1->boolval == ret);
4631 break;
4632 case XPATH_USERS:
4633 case XPATH_POINT:
4634 case XPATH_RANGE:
4635 case XPATH_LOCATIONSET:
4636 TODO
4637 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004638 case XPATH_NODESET:
4639 case XPATH_XSLT_TREE:
4640 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004641 }
4642 break;
4643 case XPATH_NUMBER:
4644 switch (arg2->type) {
4645 case XPATH_UNDEFINED:
4646#ifdef DEBUG_EXPR
4647 xmlGenericError(xmlGenericErrorContext,
4648 "Equal: undefined\n");
4649#endif
4650 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004651 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004652 ret = (arg2->boolval==
4653 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004654 break;
4655 case XPATH_STRING:
4656 valuePush(ctxt, arg2);
4657 xmlXPathNumberFunction(ctxt, 1);
4658 arg2 = valuePop(ctxt);
4659 /* no break on purpose */
4660 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004661 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004662 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4663 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004664 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4665 if (xmlXPathIsInf(arg2->floatval) == 1)
4666 ret = 1;
4667 else
4668 ret = 0;
4669 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4670 if (xmlXPathIsInf(arg2->floatval) == -1)
4671 ret = 1;
4672 else
4673 ret = 0;
4674 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4675 if (xmlXPathIsInf(arg1->floatval) == 1)
4676 ret = 1;
4677 else
4678 ret = 0;
4679 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4680 if (xmlXPathIsInf(arg1->floatval) == -1)
4681 ret = 1;
4682 else
4683 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004684 } else {
4685 ret = (arg1->floatval == arg2->floatval);
4686 }
Owen Taylor3473f882001-02-23 17:55:21 +00004687 break;
4688 case XPATH_USERS:
4689 case XPATH_POINT:
4690 case XPATH_RANGE:
4691 case XPATH_LOCATIONSET:
4692 TODO
4693 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004694 case XPATH_NODESET:
4695 case XPATH_XSLT_TREE:
4696 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004697 }
4698 break;
4699 case XPATH_STRING:
4700 switch (arg2->type) {
4701 case XPATH_UNDEFINED:
4702#ifdef DEBUG_EXPR
4703 xmlGenericError(xmlGenericErrorContext,
4704 "Equal: undefined\n");
4705#endif
4706 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004707 case XPATH_BOOLEAN:
4708 if ((arg1->stringval == NULL) ||
4709 (arg1->stringval[0] == 0)) ret = 0;
4710 else
4711 ret = 1;
4712 ret = (arg2->boolval == ret);
4713 break;
4714 case XPATH_STRING:
4715 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4716 break;
4717 case XPATH_NUMBER:
4718 valuePush(ctxt, arg1);
4719 xmlXPathNumberFunction(ctxt, 1);
4720 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004721 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004722 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4723 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004724 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4725 if (xmlXPathIsInf(arg2->floatval) == 1)
4726 ret = 1;
4727 else
4728 ret = 0;
4729 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4730 if (xmlXPathIsInf(arg2->floatval) == -1)
4731 ret = 1;
4732 else
4733 ret = 0;
4734 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4735 if (xmlXPathIsInf(arg1->floatval) == 1)
4736 ret = 1;
4737 else
4738 ret = 0;
4739 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4740 if (xmlXPathIsInf(arg1->floatval) == -1)
4741 ret = 1;
4742 else
4743 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004744 } else {
4745 ret = (arg1->floatval == arg2->floatval);
4746 }
Owen Taylor3473f882001-02-23 17:55:21 +00004747 break;
4748 case XPATH_USERS:
4749 case XPATH_POINT:
4750 case XPATH_RANGE:
4751 case XPATH_LOCATIONSET:
4752 TODO
4753 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004754 case XPATH_NODESET:
4755 case XPATH_XSLT_TREE:
4756 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004757 }
4758 break;
4759 case XPATH_USERS:
4760 case XPATH_POINT:
4761 case XPATH_RANGE:
4762 case XPATH_LOCATIONSET:
4763 TODO
4764 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004765 case XPATH_NODESET:
4766 case XPATH_XSLT_TREE:
4767 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004768 }
4769 xmlXPathFreeObject(arg1);
4770 xmlXPathFreeObject(arg2);
4771 return(ret);
4772}
4773
William M. Brack0c022ad2002-07-12 00:56:01 +00004774/**
4775 * xmlXPathEqualValues:
4776 * @ctxt: the XPath Parser context
4777 *
4778 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4779 *
4780 * Returns 0 or 1 depending on the results of the test.
4781 */
4782int
4783xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4784 xmlXPathObjectPtr arg1, arg2, argtmp;
4785 int ret = 0;
4786
4787 arg2 = valuePop(ctxt);
4788 arg1 = valuePop(ctxt);
4789 if ((arg1 == NULL) || (arg2 == NULL)) {
4790 if (arg1 != NULL)
4791 xmlXPathFreeObject(arg1);
4792 else
4793 xmlXPathFreeObject(arg2);
4794 XP_ERROR0(XPATH_INVALID_OPERAND);
4795 }
4796
4797 if (arg1 == arg2) {
4798#ifdef DEBUG_EXPR
4799 xmlGenericError(xmlGenericErrorContext,
4800 "Equal: by pointer\n");
4801#endif
4802 return(1);
4803 }
4804
4805 /*
4806 *If either argument is a nodeset, it's a 'special case'
4807 */
4808 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4809 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4810 /*
4811 *Hack it to assure arg1 is the nodeset
4812 */
4813 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4814 argtmp = arg2;
4815 arg2 = arg1;
4816 arg1 = argtmp;
4817 }
4818 switch (arg2->type) {
4819 case XPATH_UNDEFINED:
4820#ifdef DEBUG_EXPR
4821 xmlGenericError(xmlGenericErrorContext,
4822 "Equal: undefined\n");
4823#endif
4824 break;
4825 case XPATH_NODESET:
4826 case XPATH_XSLT_TREE:
4827 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4828 break;
4829 case XPATH_BOOLEAN:
4830 if ((arg1->nodesetval == NULL) ||
4831 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4832 else
4833 ret = 1;
4834 ret = (ret == arg2->boolval);
4835 break;
4836 case XPATH_NUMBER:
4837 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4838 break;
4839 case XPATH_STRING:
4840 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4841 break;
4842 case XPATH_USERS:
4843 case XPATH_POINT:
4844 case XPATH_RANGE:
4845 case XPATH_LOCATIONSET:
4846 TODO
4847 break;
4848 }
4849 xmlXPathFreeObject(arg1);
4850 xmlXPathFreeObject(arg2);
4851 return(ret);
4852 }
4853
4854 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4855}
4856
4857/**
4858 * xmlXPathNotEqualValues:
4859 * @ctxt: the XPath Parser context
4860 *
4861 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4862 *
4863 * Returns 0 or 1 depending on the results of the test.
4864 */
4865int
4866xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4867 xmlXPathObjectPtr arg1, arg2, argtmp;
4868 int ret = 0;
4869
4870 arg2 = valuePop(ctxt);
4871 arg1 = valuePop(ctxt);
4872 if ((arg1 == NULL) || (arg2 == NULL)) {
4873 if (arg1 != NULL)
4874 xmlXPathFreeObject(arg1);
4875 else
4876 xmlXPathFreeObject(arg2);
4877 XP_ERROR0(XPATH_INVALID_OPERAND);
4878 }
4879
4880 if (arg1 == arg2) {
4881#ifdef DEBUG_EXPR
4882 xmlGenericError(xmlGenericErrorContext,
4883 "NotEqual: by pointer\n");
4884#endif
4885 return(0);
4886 }
4887
4888 /*
4889 *If either argument is a nodeset, it's a 'special case'
4890 */
4891 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4892 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4893 /*
4894 *Hack it to assure arg1 is the nodeset
4895 */
4896 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4897 argtmp = arg2;
4898 arg2 = arg1;
4899 arg1 = argtmp;
4900 }
4901 switch (arg2->type) {
4902 case XPATH_UNDEFINED:
4903#ifdef DEBUG_EXPR
4904 xmlGenericError(xmlGenericErrorContext,
4905 "NotEqual: undefined\n");
4906#endif
4907 break;
4908 case XPATH_NODESET:
4909 case XPATH_XSLT_TREE:
4910 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4911 break;
4912 case XPATH_BOOLEAN:
4913 if ((arg1->nodesetval == NULL) ||
4914 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4915 else
4916 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004917 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004918 break;
4919 case XPATH_NUMBER:
4920 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4921 break;
4922 case XPATH_STRING:
4923 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4924 break;
4925 case XPATH_USERS:
4926 case XPATH_POINT:
4927 case XPATH_RANGE:
4928 case XPATH_LOCATIONSET:
4929 TODO
4930 break;
4931 }
4932 xmlXPathFreeObject(arg1);
4933 xmlXPathFreeObject(arg2);
4934 return(ret);
4935 }
4936
4937 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4938}
Owen Taylor3473f882001-02-23 17:55:21 +00004939
4940/**
4941 * xmlXPathCompareValues:
4942 * @ctxt: the XPath Parser context
4943 * @inf: less than (1) or greater than (0)
4944 * @strict: is the comparison strict
4945 *
4946 * Implement the compare operation on XPath objects:
4947 * @arg1 < @arg2 (1, 1, ...
4948 * @arg1 <= @arg2 (1, 0, ...
4949 * @arg1 > @arg2 (0, 1, ...
4950 * @arg1 >= @arg2 (0, 0, ...
4951 *
4952 * When neither object to be compared is a node-set and the operator is
4953 * <=, <, >=, >, then the objects are compared by converted both objects
4954 * to numbers and comparing the numbers according to IEEE 754. The <
4955 * comparison will be true if and only if the first number is less than the
4956 * second number. The <= comparison will be true if and only if the first
4957 * number is less than or equal to the second number. The > comparison
4958 * will be true if and only if the first number is greater than the second
4959 * number. The >= comparison will be true if and only if the first number
4960 * is greater than or equal to the second number.
4961 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004962 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004963 */
4964int
4965xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004966 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004967 xmlXPathObjectPtr arg1, arg2;
4968
William M. Brack0c022ad2002-07-12 00:56:01 +00004969 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004970 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004971 if ((arg1 == NULL) || (arg2 == NULL)) {
4972 if (arg1 != NULL)
4973 xmlXPathFreeObject(arg1);
4974 else
4975 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004976 XP_ERROR0(XPATH_INVALID_OPERAND);
4977 }
4978
William M. Brack0c022ad2002-07-12 00:56:01 +00004979 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4980 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4981 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4982 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004983 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004984 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004985 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004986 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4987 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004988 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004989 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4990 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004991 }
4992 }
4993 return(ret);
4994 }
4995
4996 if (arg1->type != XPATH_NUMBER) {
4997 valuePush(ctxt, arg1);
4998 xmlXPathNumberFunction(ctxt, 1);
4999 arg1 = valuePop(ctxt);
5000 }
5001 if (arg1->type != XPATH_NUMBER) {
5002 xmlXPathFreeObject(arg1);
5003 xmlXPathFreeObject(arg2);
5004 XP_ERROR0(XPATH_INVALID_OPERAND);
5005 }
5006 if (arg2->type != XPATH_NUMBER) {
5007 valuePush(ctxt, arg2);
5008 xmlXPathNumberFunction(ctxt, 1);
5009 arg2 = valuePop(ctxt);
5010 }
5011 if (arg2->type != XPATH_NUMBER) {
5012 xmlXPathFreeObject(arg1);
5013 xmlXPathFreeObject(arg2);
5014 XP_ERROR0(XPATH_INVALID_OPERAND);
5015 }
5016 /*
5017 * Add tests for infinity and nan
5018 * => feedback on 3.4 for Inf and NaN
5019 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005020 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005021 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005022 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005023 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005024 arg1i=xmlXPathIsInf(arg1->floatval);
5025 arg2i=xmlXPathIsInf(arg2->floatval);
5026 if (inf && strict) {
5027 if ((arg1i == -1 && arg2i != -1) ||
5028 (arg2i == 1 && arg1i != 1)) {
5029 ret = 1;
5030 } else if (arg1i == 0 && arg2i == 0) {
5031 ret = (arg1->floatval < arg2->floatval);
5032 } else {
5033 ret = 0;
5034 }
5035 }
5036 else if (inf && !strict) {
5037 if (arg1i == -1 || arg2i == 1) {
5038 ret = 1;
5039 } else if (arg1i == 0 && arg2i == 0) {
5040 ret = (arg1->floatval <= arg2->floatval);
5041 } else {
5042 ret = 0;
5043 }
5044 }
5045 else if (!inf && strict) {
5046 if ((arg1i == 1 && arg2i != 1) ||
5047 (arg2i == -1 && arg1i != -1)) {
5048 ret = 1;
5049 } else if (arg1i == 0 && arg2i == 0) {
5050 ret = (arg1->floatval > arg2->floatval);
5051 } else {
5052 ret = 0;
5053 }
5054 }
5055 else if (!inf && !strict) {
5056 if (arg1i == 1 || arg2i == -1) {
5057 ret = 1;
5058 } else if (arg1i == 0 && arg2i == 0) {
5059 ret = (arg1->floatval >= arg2->floatval);
5060 } else {
5061 ret = 0;
5062 }
5063 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005064 }
Owen Taylor3473f882001-02-23 17:55:21 +00005065 xmlXPathFreeObject(arg1);
5066 xmlXPathFreeObject(arg2);
5067 return(ret);
5068}
5069
5070/**
5071 * xmlXPathValueFlipSign:
5072 * @ctxt: the XPath Parser context
5073 *
5074 * Implement the unary - operation on an XPath object
5075 * The numeric operators convert their operands to numbers as if
5076 * by calling the number function.
5077 */
5078void
5079xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005080 CAST_TO_NUMBER;
5081 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005082 if (xmlXPathIsNaN(ctxt->value->floatval))
5083 ctxt->value->floatval=xmlXPathNAN;
5084 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5085 ctxt->value->floatval=xmlXPathNINF;
5086 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5087 ctxt->value->floatval=xmlXPathPINF;
5088 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005089 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5090 ctxt->value->floatval = xmlXPathNZERO;
5091 else
5092 ctxt->value->floatval = 0;
5093 }
5094 else
5095 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005096}
5097
5098/**
5099 * xmlXPathAddValues:
5100 * @ctxt: the XPath Parser context
5101 *
5102 * Implement the add operation on XPath objects:
5103 * The numeric operators convert their operands to numbers as if
5104 * by calling the number function.
5105 */
5106void
5107xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5108 xmlXPathObjectPtr arg;
5109 double val;
5110
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005111 arg = valuePop(ctxt);
5112 if (arg == NULL)
5113 XP_ERROR(XPATH_INVALID_OPERAND);
5114 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005115 xmlXPathFreeObject(arg);
5116
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005117 CAST_TO_NUMBER;
5118 CHECK_TYPE(XPATH_NUMBER);
5119 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005120}
5121
5122/**
5123 * xmlXPathSubValues:
5124 * @ctxt: the XPath Parser context
5125 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005126 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005127 * The numeric operators convert their operands to numbers as if
5128 * by calling the number function.
5129 */
5130void
5131xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5132 xmlXPathObjectPtr arg;
5133 double val;
5134
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005135 arg = valuePop(ctxt);
5136 if (arg == NULL)
5137 XP_ERROR(XPATH_INVALID_OPERAND);
5138 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005139 xmlXPathFreeObject(arg);
5140
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005141 CAST_TO_NUMBER;
5142 CHECK_TYPE(XPATH_NUMBER);
5143 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005144}
5145
5146/**
5147 * xmlXPathMultValues:
5148 * @ctxt: the XPath Parser context
5149 *
5150 * Implement the multiply operation on XPath objects:
5151 * The numeric operators convert their operands to numbers as if
5152 * by calling the number function.
5153 */
5154void
5155xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5156 xmlXPathObjectPtr arg;
5157 double val;
5158
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005159 arg = valuePop(ctxt);
5160 if (arg == NULL)
5161 XP_ERROR(XPATH_INVALID_OPERAND);
5162 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005163 xmlXPathFreeObject(arg);
5164
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005165 CAST_TO_NUMBER;
5166 CHECK_TYPE(XPATH_NUMBER);
5167 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005168}
5169
5170/**
5171 * xmlXPathDivValues:
5172 * @ctxt: the XPath Parser context
5173 *
5174 * Implement the div operation on XPath objects @arg1 / @arg2:
5175 * The numeric operators convert their operands to numbers as if
5176 * by calling the number function.
5177 */
5178void
5179xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5180 xmlXPathObjectPtr arg;
5181 double val;
5182
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005183 arg = valuePop(ctxt);
5184 if (arg == NULL)
5185 XP_ERROR(XPATH_INVALID_OPERAND);
5186 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005187 xmlXPathFreeObject(arg);
5188
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005189 CAST_TO_NUMBER;
5190 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005191 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5192 ctxt->value->floatval = xmlXPathNAN;
5193 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005194 if (ctxt->value->floatval == 0)
5195 ctxt->value->floatval = xmlXPathNAN;
5196 else if (ctxt->value->floatval > 0)
5197 ctxt->value->floatval = xmlXPathNINF;
5198 else if (ctxt->value->floatval < 0)
5199 ctxt->value->floatval = xmlXPathPINF;
5200 }
5201 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005202 if (ctxt->value->floatval == 0)
5203 ctxt->value->floatval = xmlXPathNAN;
5204 else if (ctxt->value->floatval > 0)
5205 ctxt->value->floatval = xmlXPathPINF;
5206 else if (ctxt->value->floatval < 0)
5207 ctxt->value->floatval = xmlXPathNINF;
5208 } else
5209 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005210}
5211
5212/**
5213 * xmlXPathModValues:
5214 * @ctxt: the XPath Parser context
5215 *
5216 * Implement the mod operation on XPath objects: @arg1 / @arg2
5217 * The numeric operators convert their operands to numbers as if
5218 * by calling the number function.
5219 */
5220void
5221xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5222 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005223 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005224
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005225 arg = valuePop(ctxt);
5226 if (arg == NULL)
5227 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005228 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005229 xmlXPathFreeObject(arg);
5230
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005231 CAST_TO_NUMBER;
5232 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005233 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005234 if (arg2 == 0)
5235 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005236 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005237 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005238 }
Owen Taylor3473f882001-02-23 17:55:21 +00005239}
5240
5241/************************************************************************
5242 * *
5243 * The traversal functions *
5244 * *
5245 ************************************************************************/
5246
Owen Taylor3473f882001-02-23 17:55:21 +00005247/*
5248 * A traversal function enumerates nodes along an axis.
5249 * Initially it must be called with NULL, and it indicates
5250 * termination on the axis by returning NULL.
5251 */
5252typedef xmlNodePtr (*xmlXPathTraversalFunction)
5253 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5254
5255/**
5256 * xmlXPathNextSelf:
5257 * @ctxt: the XPath Parser context
5258 * @cur: the current node in the traversal
5259 *
5260 * Traversal function for the "self" direction
5261 * The self axis contains just the context node itself
5262 *
5263 * Returns the next element following that axis
5264 */
5265xmlNodePtr
5266xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5267 if (cur == NULL)
5268 return(ctxt->context->node);
5269 return(NULL);
5270}
5271
5272/**
5273 * xmlXPathNextChild:
5274 * @ctxt: the XPath Parser context
5275 * @cur: the current node in the traversal
5276 *
5277 * Traversal function for the "child" direction
5278 * The child axis contains the children of the context node in document order.
5279 *
5280 * Returns the next element following that axis
5281 */
5282xmlNodePtr
5283xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5284 if (cur == NULL) {
5285 if (ctxt->context->node == NULL) return(NULL);
5286 switch (ctxt->context->node->type) {
5287 case XML_ELEMENT_NODE:
5288 case XML_TEXT_NODE:
5289 case XML_CDATA_SECTION_NODE:
5290 case XML_ENTITY_REF_NODE:
5291 case XML_ENTITY_NODE:
5292 case XML_PI_NODE:
5293 case XML_COMMENT_NODE:
5294 case XML_NOTATION_NODE:
5295 case XML_DTD_NODE:
5296 return(ctxt->context->node->children);
5297 case XML_DOCUMENT_NODE:
5298 case XML_DOCUMENT_TYPE_NODE:
5299 case XML_DOCUMENT_FRAG_NODE:
5300 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005301#ifdef LIBXML_DOCB_ENABLED
5302 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005303#endif
5304 return(((xmlDocPtr) ctxt->context->node)->children);
5305 case XML_ELEMENT_DECL:
5306 case XML_ATTRIBUTE_DECL:
5307 case XML_ENTITY_DECL:
5308 case XML_ATTRIBUTE_NODE:
5309 case XML_NAMESPACE_DECL:
5310 case XML_XINCLUDE_START:
5311 case XML_XINCLUDE_END:
5312 return(NULL);
5313 }
5314 return(NULL);
5315 }
5316 if ((cur->type == XML_DOCUMENT_NODE) ||
5317 (cur->type == XML_HTML_DOCUMENT_NODE))
5318 return(NULL);
5319 return(cur->next);
5320}
5321
5322/**
5323 * xmlXPathNextDescendant:
5324 * @ctxt: the XPath Parser context
5325 * @cur: the current node in the traversal
5326 *
5327 * Traversal function for the "descendant" direction
5328 * the descendant axis contains the descendants of the context node in document
5329 * order; a descendant is a child or a child of a child and so on.
5330 *
5331 * Returns the next element following that axis
5332 */
5333xmlNodePtr
5334xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5335 if (cur == NULL) {
5336 if (ctxt->context->node == NULL)
5337 return(NULL);
5338 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5339 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5340 return(NULL);
5341
5342 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5343 return(ctxt->context->doc->children);
5344 return(ctxt->context->node->children);
5345 }
5346
Daniel Veillard567e1b42001-08-01 15:53:47 +00005347 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005348 /*
5349 * Do not descend on entities declarations
5350 */
5351 if (cur->children->type != XML_ENTITY_DECL) {
5352 cur = cur->children;
5353 /*
5354 * Skip DTDs
5355 */
5356 if (cur->type != XML_DTD_NODE)
5357 return(cur);
5358 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005359 }
5360
5361 if (cur == ctxt->context->node) return(NULL);
5362
Daniel Veillard68e9e742002-11-16 15:35:11 +00005363 while (cur->next != NULL) {
5364 cur = cur->next;
5365 if ((cur->type != XML_ENTITY_DECL) &&
5366 (cur->type != XML_DTD_NODE))
5367 return(cur);
5368 }
Owen Taylor3473f882001-02-23 17:55:21 +00005369
5370 do {
5371 cur = cur->parent;
5372 if (cur == NULL) return(NULL);
5373 if (cur == ctxt->context->node) return(NULL);
5374 if (cur->next != NULL) {
5375 cur = cur->next;
5376 return(cur);
5377 }
5378 } while (cur != NULL);
5379 return(cur);
5380}
5381
5382/**
5383 * xmlXPathNextDescendantOrSelf:
5384 * @ctxt: the XPath Parser context
5385 * @cur: the current node in the traversal
5386 *
5387 * Traversal function for the "descendant-or-self" direction
5388 * the descendant-or-self axis contains the context node and the descendants
5389 * of the context node in document order; thus the context node is the first
5390 * node on the axis, and the first child of the context node is the second node
5391 * on the axis
5392 *
5393 * Returns the next element following that axis
5394 */
5395xmlNodePtr
5396xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5397 if (cur == NULL) {
5398 if (ctxt->context->node == NULL)
5399 return(NULL);
5400 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5401 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5402 return(NULL);
5403 return(ctxt->context->node);
5404 }
5405
5406 return(xmlXPathNextDescendant(ctxt, cur));
5407}
5408
5409/**
5410 * xmlXPathNextParent:
5411 * @ctxt: the XPath Parser context
5412 * @cur: the current node in the traversal
5413 *
5414 * Traversal function for the "parent" direction
5415 * The parent axis contains the parent of the context node, if there is one.
5416 *
5417 * Returns the next element following that axis
5418 */
5419xmlNodePtr
5420xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5421 /*
5422 * the parent of an attribute or namespace node is the element
5423 * to which the attribute or namespace node is attached
5424 * Namespace handling !!!
5425 */
5426 if (cur == NULL) {
5427 if (ctxt->context->node == NULL) return(NULL);
5428 switch (ctxt->context->node->type) {
5429 case XML_ELEMENT_NODE:
5430 case XML_TEXT_NODE:
5431 case XML_CDATA_SECTION_NODE:
5432 case XML_ENTITY_REF_NODE:
5433 case XML_ENTITY_NODE:
5434 case XML_PI_NODE:
5435 case XML_COMMENT_NODE:
5436 case XML_NOTATION_NODE:
5437 case XML_DTD_NODE:
5438 case XML_ELEMENT_DECL:
5439 case XML_ATTRIBUTE_DECL:
5440 case XML_XINCLUDE_START:
5441 case XML_XINCLUDE_END:
5442 case XML_ENTITY_DECL:
5443 if (ctxt->context->node->parent == NULL)
5444 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005445 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005446 ((ctxt->context->node->parent->name[0] == ' ') ||
5447 (xmlStrEqual(ctxt->context->node->parent->name,
5448 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005449 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005450 return(ctxt->context->node->parent);
5451 case XML_ATTRIBUTE_NODE: {
5452 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5453
5454 return(att->parent);
5455 }
5456 case XML_DOCUMENT_NODE:
5457 case XML_DOCUMENT_TYPE_NODE:
5458 case XML_DOCUMENT_FRAG_NODE:
5459 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005460#ifdef LIBXML_DOCB_ENABLED
5461 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005462#endif
5463 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005464 case XML_NAMESPACE_DECL: {
5465 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5466
5467 if ((ns->next != NULL) &&
5468 (ns->next->type != XML_NAMESPACE_DECL))
5469 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005470 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005471 }
Owen Taylor3473f882001-02-23 17:55:21 +00005472 }
5473 }
5474 return(NULL);
5475}
5476
5477/**
5478 * xmlXPathNextAncestor:
5479 * @ctxt: the XPath Parser context
5480 * @cur: the current node in the traversal
5481 *
5482 * Traversal function for the "ancestor" direction
5483 * the ancestor axis contains the ancestors of the context node; the ancestors
5484 * of the context node consist of the parent of context node and the parent's
5485 * parent and so on; the nodes are ordered in reverse document order; thus the
5486 * parent is the first node on the axis, and the parent's parent is the second
5487 * node on the axis
5488 *
5489 * Returns the next element following that axis
5490 */
5491xmlNodePtr
5492xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5493 /*
5494 * the parent of an attribute or namespace node is the element
5495 * to which the attribute or namespace node is attached
5496 * !!!!!!!!!!!!!
5497 */
5498 if (cur == NULL) {
5499 if (ctxt->context->node == NULL) return(NULL);
5500 switch (ctxt->context->node->type) {
5501 case XML_ELEMENT_NODE:
5502 case XML_TEXT_NODE:
5503 case XML_CDATA_SECTION_NODE:
5504 case XML_ENTITY_REF_NODE:
5505 case XML_ENTITY_NODE:
5506 case XML_PI_NODE:
5507 case XML_COMMENT_NODE:
5508 case XML_DTD_NODE:
5509 case XML_ELEMENT_DECL:
5510 case XML_ATTRIBUTE_DECL:
5511 case XML_ENTITY_DECL:
5512 case XML_NOTATION_NODE:
5513 case XML_XINCLUDE_START:
5514 case XML_XINCLUDE_END:
5515 if (ctxt->context->node->parent == NULL)
5516 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005517 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005518 ((ctxt->context->node->parent->name[0] == ' ') ||
5519 (xmlStrEqual(ctxt->context->node->parent->name,
5520 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005521 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005522 return(ctxt->context->node->parent);
5523 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005524 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005525
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005526 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005527 }
5528 case XML_DOCUMENT_NODE:
5529 case XML_DOCUMENT_TYPE_NODE:
5530 case XML_DOCUMENT_FRAG_NODE:
5531 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005532#ifdef LIBXML_DOCB_ENABLED
5533 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005534#endif
5535 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005536 case XML_NAMESPACE_DECL: {
5537 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5538
5539 if ((ns->next != NULL) &&
5540 (ns->next->type != XML_NAMESPACE_DECL))
5541 return((xmlNodePtr) ns->next);
5542 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005543 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005544 }
Owen Taylor3473f882001-02-23 17:55:21 +00005545 }
5546 return(NULL);
5547 }
5548 if (cur == ctxt->context->doc->children)
5549 return((xmlNodePtr) ctxt->context->doc);
5550 if (cur == (xmlNodePtr) ctxt->context->doc)
5551 return(NULL);
5552 switch (cur->type) {
5553 case XML_ELEMENT_NODE:
5554 case XML_TEXT_NODE:
5555 case XML_CDATA_SECTION_NODE:
5556 case XML_ENTITY_REF_NODE:
5557 case XML_ENTITY_NODE:
5558 case XML_PI_NODE:
5559 case XML_COMMENT_NODE:
5560 case XML_NOTATION_NODE:
5561 case XML_DTD_NODE:
5562 case XML_ELEMENT_DECL:
5563 case XML_ATTRIBUTE_DECL:
5564 case XML_ENTITY_DECL:
5565 case XML_XINCLUDE_START:
5566 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005567 if (cur->parent == NULL)
5568 return(NULL);
5569 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005570 ((cur->parent->name[0] == ' ') ||
5571 (xmlStrEqual(cur->parent->name,
5572 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005573 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005574 return(cur->parent);
5575 case XML_ATTRIBUTE_NODE: {
5576 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5577
5578 return(att->parent);
5579 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005580 case XML_NAMESPACE_DECL: {
5581 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5582
5583 if ((ns->next != NULL) &&
5584 (ns->next->type != XML_NAMESPACE_DECL))
5585 return((xmlNodePtr) ns->next);
5586 /* Bad, how did that namespace ended-up there ? */
5587 return(NULL);
5588 }
Owen Taylor3473f882001-02-23 17:55:21 +00005589 case XML_DOCUMENT_NODE:
5590 case XML_DOCUMENT_TYPE_NODE:
5591 case XML_DOCUMENT_FRAG_NODE:
5592 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005593#ifdef LIBXML_DOCB_ENABLED
5594 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005595#endif
5596 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005597 }
5598 return(NULL);
5599}
5600
5601/**
5602 * xmlXPathNextAncestorOrSelf:
5603 * @ctxt: the XPath Parser context
5604 * @cur: the current node in the traversal
5605 *
5606 * Traversal function for the "ancestor-or-self" direction
5607 * he ancestor-or-self axis contains the context node and ancestors of
5608 * the context node in reverse document order; thus the context node is
5609 * the first node on the axis, and the context node's parent the second;
5610 * parent here is defined the same as with the parent axis.
5611 *
5612 * Returns the next element following that axis
5613 */
5614xmlNodePtr
5615xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5616 if (cur == NULL)
5617 return(ctxt->context->node);
5618 return(xmlXPathNextAncestor(ctxt, cur));
5619}
5620
5621/**
5622 * xmlXPathNextFollowingSibling:
5623 * @ctxt: the XPath Parser context
5624 * @cur: the current node in the traversal
5625 *
5626 * Traversal function for the "following-sibling" direction
5627 * The following-sibling axis contains the following siblings of the context
5628 * node in document order.
5629 *
5630 * Returns the next element following that axis
5631 */
5632xmlNodePtr
5633xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5634 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5635 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5636 return(NULL);
5637 if (cur == (xmlNodePtr) ctxt->context->doc)
5638 return(NULL);
5639 if (cur == NULL)
5640 return(ctxt->context->node->next);
5641 return(cur->next);
5642}
5643
5644/**
5645 * xmlXPathNextPrecedingSibling:
5646 * @ctxt: the XPath Parser context
5647 * @cur: the current node in the traversal
5648 *
5649 * Traversal function for the "preceding-sibling" direction
5650 * The preceding-sibling axis contains the preceding siblings of the context
5651 * node in reverse document order; the first preceding sibling is first on the
5652 * axis; the sibling preceding that node is the second on the axis and so on.
5653 *
5654 * Returns the next element following that axis
5655 */
5656xmlNodePtr
5657xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5658 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5659 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5660 return(NULL);
5661 if (cur == (xmlNodePtr) ctxt->context->doc)
5662 return(NULL);
5663 if (cur == NULL)
5664 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005665 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5666 cur = cur->prev;
5667 if (cur == NULL)
5668 return(ctxt->context->node->prev);
5669 }
Owen Taylor3473f882001-02-23 17:55:21 +00005670 return(cur->prev);
5671}
5672
5673/**
5674 * xmlXPathNextFollowing:
5675 * @ctxt: the XPath Parser context
5676 * @cur: the current node in the traversal
5677 *
5678 * Traversal function for the "following" direction
5679 * The following axis contains all nodes in the same document as the context
5680 * node that are after the context node in document order, excluding any
5681 * descendants and excluding attribute nodes and namespace nodes; the nodes
5682 * are ordered in document order
5683 *
5684 * Returns the next element following that axis
5685 */
5686xmlNodePtr
5687xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5688 if (cur != NULL && cur->children != NULL)
5689 return cur->children ;
5690 if (cur == NULL) cur = ctxt->context->node;
5691 if (cur == NULL) return(NULL) ; /* ERROR */
5692 if (cur->next != NULL) return(cur->next) ;
5693 do {
5694 cur = cur->parent;
5695 if (cur == NULL) return(NULL);
5696 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5697 if (cur->next != NULL) return(cur->next);
5698 } while (cur != NULL);
5699 return(cur);
5700}
5701
5702/*
5703 * xmlXPathIsAncestor:
5704 * @ancestor: the ancestor node
5705 * @node: the current node
5706 *
5707 * Check that @ancestor is a @node's ancestor
5708 *
5709 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5710 */
5711static int
5712xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5713 if ((ancestor == NULL) || (node == NULL)) return(0);
5714 /* nodes need to be in the same document */
5715 if (ancestor->doc != node->doc) return(0);
5716 /* avoid searching if ancestor or node is the root node */
5717 if (ancestor == (xmlNodePtr) node->doc) return(1);
5718 if (node == (xmlNodePtr) ancestor->doc) return(0);
5719 while (node->parent != NULL) {
5720 if (node->parent == ancestor)
5721 return(1);
5722 node = node->parent;
5723 }
5724 return(0);
5725}
5726
5727/**
5728 * xmlXPathNextPreceding:
5729 * @ctxt: the XPath Parser context
5730 * @cur: the current node in the traversal
5731 *
5732 * Traversal function for the "preceding" direction
5733 * the preceding axis contains all nodes in the same document as the context
5734 * node that are before the context node in document order, excluding any
5735 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5736 * ordered in reverse document order
5737 *
5738 * Returns the next element following that axis
5739 */
5740xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005741xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5742{
Owen Taylor3473f882001-02-23 17:55:21 +00005743 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005744 cur = ctxt->context->node;
5745 if (cur == NULL)
5746 return (NULL);
5747 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5748 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005749 do {
5750 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005751 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5752 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005753 }
5754
5755 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005756 if (cur == NULL)
5757 return (NULL);
5758 if (cur == ctxt->context->doc->children)
5759 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005760 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005761 return (cur);
5762}
5763
5764/**
5765 * xmlXPathNextPrecedingInternal:
5766 * @ctxt: the XPath Parser context
5767 * @cur: the current node in the traversal
5768 *
5769 * Traversal function for the "preceding" direction
5770 * the preceding axis contains all nodes in the same document as the context
5771 * node that are before the context node in document order, excluding any
5772 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5773 * ordered in reverse document order
5774 * This is a faster implementation but internal only since it requires a
5775 * state kept in the parser context: ctxt->ancestor.
5776 *
5777 * Returns the next element following that axis
5778 */
5779static xmlNodePtr
5780xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5781 xmlNodePtr cur)
5782{
5783 if (cur == NULL) {
5784 cur = ctxt->context->node;
5785 if (cur == NULL)
5786 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005787 if (cur->type == XML_NAMESPACE_DECL)
5788 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005789 ctxt->ancestor = cur->parent;
5790 }
5791 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5792 cur = cur->prev;
5793 while (cur->prev == NULL) {
5794 cur = cur->parent;
5795 if (cur == NULL)
5796 return (NULL);
5797 if (cur == ctxt->context->doc->children)
5798 return (NULL);
5799 if (cur != ctxt->ancestor)
5800 return (cur);
5801 ctxt->ancestor = cur->parent;
5802 }
5803 cur = cur->prev;
5804 while (cur->last != NULL)
5805 cur = cur->last;
5806 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005807}
5808
5809/**
5810 * xmlXPathNextNamespace:
5811 * @ctxt: the XPath Parser context
5812 * @cur: the current attribute in the traversal
5813 *
5814 * Traversal function for the "namespace" direction
5815 * the namespace axis contains the namespace nodes of the context node;
5816 * the order of nodes on this axis is implementation-defined; the axis will
5817 * be empty unless the context node is an element
5818 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005819 * We keep the XML namespace node at the end of the list.
5820 *
Owen Taylor3473f882001-02-23 17:55:21 +00005821 * Returns the next element following that axis
5822 */
5823xmlNodePtr
5824xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5825 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005826 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005827 if (ctxt->context->tmpNsList != NULL)
5828 xmlFree(ctxt->context->tmpNsList);
5829 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005830 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005831 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005832 if (ctxt->context->tmpNsList != NULL) {
5833 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5834 ctxt->context->tmpNsNr++;
5835 }
5836 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005837 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005838 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005839 if (ctxt->context->tmpNsNr > 0) {
5840 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5841 } else {
5842 if (ctxt->context->tmpNsList != NULL)
5843 xmlFree(ctxt->context->tmpNsList);
5844 ctxt->context->tmpNsList = NULL;
5845 return(NULL);
5846 }
Owen Taylor3473f882001-02-23 17:55:21 +00005847}
5848
5849/**
5850 * xmlXPathNextAttribute:
5851 * @ctxt: the XPath Parser context
5852 * @cur: the current attribute in the traversal
5853 *
5854 * Traversal function for the "attribute" direction
5855 * TODO: support DTD inherited default attributes
5856 *
5857 * Returns the next element following that axis
5858 */
5859xmlNodePtr
5860xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005861 if (ctxt->context->node == NULL)
5862 return(NULL);
5863 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5864 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005865 if (cur == NULL) {
5866 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5867 return(NULL);
5868 return((xmlNodePtr)ctxt->context->node->properties);
5869 }
5870 return((xmlNodePtr)cur->next);
5871}
5872
5873/************************************************************************
5874 * *
5875 * NodeTest Functions *
5876 * *
5877 ************************************************************************/
5878
Owen Taylor3473f882001-02-23 17:55:21 +00005879#define IS_FUNCTION 200
5880
Owen Taylor3473f882001-02-23 17:55:21 +00005881
5882/************************************************************************
5883 * *
5884 * Implicit tree core function library *
5885 * *
5886 ************************************************************************/
5887
5888/**
5889 * xmlXPathRoot:
5890 * @ctxt: the XPath Parser context
5891 *
5892 * Initialize the context to the root of the document
5893 */
5894void
5895xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5896 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5897 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5898}
5899
5900/************************************************************************
5901 * *
5902 * The explicit core function library *
5903 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5904 * *
5905 ************************************************************************/
5906
5907
5908/**
5909 * xmlXPathLastFunction:
5910 * @ctxt: the XPath Parser context
5911 * @nargs: the number of arguments
5912 *
5913 * Implement the last() XPath function
5914 * number last()
5915 * The last function returns the number of nodes in the context node list.
5916 */
5917void
5918xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5919 CHECK_ARITY(0);
5920 if (ctxt->context->contextSize >= 0) {
5921 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5922#ifdef DEBUG_EXPR
5923 xmlGenericError(xmlGenericErrorContext,
5924 "last() : %d\n", ctxt->context->contextSize);
5925#endif
5926 } else {
5927 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5928 }
5929}
5930
5931/**
5932 * xmlXPathPositionFunction:
5933 * @ctxt: the XPath Parser context
5934 * @nargs: the number of arguments
5935 *
5936 * Implement the position() XPath function
5937 * number position()
5938 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005939 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005940 * will be equal to last().
5941 */
5942void
5943xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5944 CHECK_ARITY(0);
5945 if (ctxt->context->proximityPosition >= 0) {
5946 valuePush(ctxt,
5947 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5948#ifdef DEBUG_EXPR
5949 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5950 ctxt->context->proximityPosition);
5951#endif
5952 } else {
5953 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5954 }
5955}
5956
5957/**
5958 * xmlXPathCountFunction:
5959 * @ctxt: the XPath Parser context
5960 * @nargs: the number of arguments
5961 *
5962 * Implement the count() XPath function
5963 * number count(node-set)
5964 */
5965void
5966xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5967 xmlXPathObjectPtr cur;
5968
5969 CHECK_ARITY(1);
5970 if ((ctxt->value == NULL) ||
5971 ((ctxt->value->type != XPATH_NODESET) &&
5972 (ctxt->value->type != XPATH_XSLT_TREE)))
5973 XP_ERROR(XPATH_INVALID_TYPE);
5974 cur = valuePop(ctxt);
5975
Daniel Veillard911f49a2001-04-07 15:39:35 +00005976 if ((cur == NULL) || (cur->nodesetval == NULL))
5977 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005978 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005979 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005980 } else {
5981 if ((cur->nodesetval->nodeNr != 1) ||
5982 (cur->nodesetval->nodeTab == NULL)) {
5983 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5984 } else {
5985 xmlNodePtr tmp;
5986 int i = 0;
5987
5988 tmp = cur->nodesetval->nodeTab[0];
5989 if (tmp != NULL) {
5990 tmp = tmp->children;
5991 while (tmp != NULL) {
5992 tmp = tmp->next;
5993 i++;
5994 }
5995 }
5996 valuePush(ctxt, xmlXPathNewFloat((double) i));
5997 }
5998 }
Owen Taylor3473f882001-02-23 17:55:21 +00005999 xmlXPathFreeObject(cur);
6000}
6001
6002/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006003 * xmlXPathGetElementsByIds:
6004 * @doc: the document
6005 * @ids: a whitespace separated list of IDs
6006 *
6007 * Selects elements by their unique ID.
6008 *
6009 * Returns a node-set of selected elements.
6010 */
6011static xmlNodeSetPtr
6012xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6013 xmlNodeSetPtr ret;
6014 const xmlChar *cur = ids;
6015 xmlChar *ID;
6016 xmlAttrPtr attr;
6017 xmlNodePtr elem = NULL;
6018
Daniel Veillard7a985a12003-07-06 17:57:42 +00006019 if (ids == NULL) return(NULL);
6020
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006021 ret = xmlXPathNodeSetCreate(NULL);
6022
William M. Brack76e95df2003-10-18 16:20:14 +00006023 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006024 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006025 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006026 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006027
6028 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006029 if (ID != NULL) {
6030 if (xmlValidateNCName(ID, 1) == 0) {
6031 attr = xmlGetID(doc, ID);
6032 if (attr != NULL) {
6033 if (attr->type == XML_ATTRIBUTE_NODE)
6034 elem = attr->parent;
6035 else if (attr->type == XML_ELEMENT_NODE)
6036 elem = (xmlNodePtr) attr;
6037 else
6038 elem = NULL;
6039 if (elem != NULL)
6040 xmlXPathNodeSetAdd(ret, elem);
6041 }
6042 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006043 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006044 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006045
William M. Brack76e95df2003-10-18 16:20:14 +00006046 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006047 ids = cur;
6048 }
6049 return(ret);
6050}
6051
6052/**
Owen Taylor3473f882001-02-23 17:55:21 +00006053 * xmlXPathIdFunction:
6054 * @ctxt: the XPath Parser context
6055 * @nargs: the number of arguments
6056 *
6057 * Implement the id() XPath function
6058 * node-set id(object)
6059 * The id function selects elements by their unique ID
6060 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6061 * then the result is the union of the result of applying id to the
6062 * string value of each of the nodes in the argument node-set. When the
6063 * argument to id is of any other type, the argument is converted to a
6064 * string as if by a call to the string function; the string is split
6065 * into a whitespace-separated list of tokens (whitespace is any sequence
6066 * of characters matching the production S); the result is a node-set
6067 * containing the elements in the same document as the context node that
6068 * have a unique ID equal to any of the tokens in the list.
6069 */
6070void
6071xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006072 xmlChar *tokens;
6073 xmlNodeSetPtr ret;
6074 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006075
6076 CHECK_ARITY(1);
6077 obj = valuePop(ctxt);
6078 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006079 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006080 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006081 int i;
6082
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006083 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006084
Daniel Veillard911f49a2001-04-07 15:39:35 +00006085 if (obj->nodesetval != NULL) {
6086 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006087 tokens =
6088 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6089 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6090 ret = xmlXPathNodeSetMerge(ret, ns);
6091 xmlXPathFreeNodeSet(ns);
6092 if (tokens != NULL)
6093 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006094 }
Owen Taylor3473f882001-02-23 17:55:21 +00006095 }
6096
6097 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006098 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006099 return;
6100 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006101 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006102
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006103 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6104 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006105
Owen Taylor3473f882001-02-23 17:55:21 +00006106 xmlXPathFreeObject(obj);
6107 return;
6108}
6109
6110/**
6111 * xmlXPathLocalNameFunction:
6112 * @ctxt: the XPath Parser context
6113 * @nargs: the number of arguments
6114 *
6115 * Implement the local-name() XPath function
6116 * string local-name(node-set?)
6117 * The local-name function returns a string containing the local part
6118 * of the name of the node in the argument node-set that is first in
6119 * document order. If the node-set is empty or the first node has no
6120 * name, an empty string is returned. If the argument is omitted it
6121 * defaults to the context node.
6122 */
6123void
6124xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6125 xmlXPathObjectPtr cur;
6126
6127 if (nargs == 0) {
6128 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6129 nargs = 1;
6130 }
6131
6132 CHECK_ARITY(1);
6133 if ((ctxt->value == NULL) ||
6134 ((ctxt->value->type != XPATH_NODESET) &&
6135 (ctxt->value->type != XPATH_XSLT_TREE)))
6136 XP_ERROR(XPATH_INVALID_TYPE);
6137 cur = valuePop(ctxt);
6138
Daniel Veillard911f49a2001-04-07 15:39:35 +00006139 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006140 valuePush(ctxt, xmlXPathNewCString(""));
6141 } else {
6142 int i = 0; /* Should be first in document order !!!!! */
6143 switch (cur->nodesetval->nodeTab[i]->type) {
6144 case XML_ELEMENT_NODE:
6145 case XML_ATTRIBUTE_NODE:
6146 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006147 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6148 valuePush(ctxt, xmlXPathNewCString(""));
6149 else
6150 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006151 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6152 break;
6153 case XML_NAMESPACE_DECL:
6154 valuePush(ctxt, xmlXPathNewString(
6155 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6156 break;
6157 default:
6158 valuePush(ctxt, xmlXPathNewCString(""));
6159 }
6160 }
6161 xmlXPathFreeObject(cur);
6162}
6163
6164/**
6165 * xmlXPathNamespaceURIFunction:
6166 * @ctxt: the XPath Parser context
6167 * @nargs: the number of arguments
6168 *
6169 * Implement the namespace-uri() XPath function
6170 * string namespace-uri(node-set?)
6171 * The namespace-uri function returns a string containing the
6172 * namespace URI of the expanded name of the node in the argument
6173 * node-set that is first in document order. If the node-set is empty,
6174 * the first node has no name, or the expanded name has no namespace
6175 * URI, an empty string is returned. If the argument is omitted it
6176 * defaults to the context node.
6177 */
6178void
6179xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6180 xmlXPathObjectPtr cur;
6181
6182 if (nargs == 0) {
6183 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6184 nargs = 1;
6185 }
6186 CHECK_ARITY(1);
6187 if ((ctxt->value == NULL) ||
6188 ((ctxt->value->type != XPATH_NODESET) &&
6189 (ctxt->value->type != XPATH_XSLT_TREE)))
6190 XP_ERROR(XPATH_INVALID_TYPE);
6191 cur = valuePop(ctxt);
6192
Daniel Veillard911f49a2001-04-07 15:39:35 +00006193 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006194 valuePush(ctxt, xmlXPathNewCString(""));
6195 } else {
6196 int i = 0; /* Should be first in document order !!!!! */
6197 switch (cur->nodesetval->nodeTab[i]->type) {
6198 case XML_ELEMENT_NODE:
6199 case XML_ATTRIBUTE_NODE:
6200 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6201 valuePush(ctxt, xmlXPathNewCString(""));
6202 else
6203 valuePush(ctxt, xmlXPathNewString(
6204 cur->nodesetval->nodeTab[i]->ns->href));
6205 break;
6206 default:
6207 valuePush(ctxt, xmlXPathNewCString(""));
6208 }
6209 }
6210 xmlXPathFreeObject(cur);
6211}
6212
6213/**
6214 * xmlXPathNameFunction:
6215 * @ctxt: the XPath Parser context
6216 * @nargs: the number of arguments
6217 *
6218 * Implement the name() XPath function
6219 * string name(node-set?)
6220 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006221 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006222 * order. The QName must represent the name with respect to the namespace
6223 * declarations in effect on the node whose name is being represented.
6224 * Typically, this will be the form in which the name occurred in the XML
6225 * source. This need not be the case if there are namespace declarations
6226 * in effect on the node that associate multiple prefixes with the same
6227 * namespace. However, an implementation may include information about
6228 * the original prefix in its representation of nodes; in this case, an
6229 * implementation can ensure that the returned string is always the same
6230 * as the QName used in the XML source. If the argument it omitted it
6231 * defaults to the context node.
6232 * Libxml keep the original prefix so the "real qualified name" used is
6233 * returned.
6234 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006235static void
Daniel Veillard04383752001-07-08 14:27:15 +00006236xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6237{
Owen Taylor3473f882001-02-23 17:55:21 +00006238 xmlXPathObjectPtr cur;
6239
6240 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006241 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6242 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006243 }
6244
6245 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006246 if ((ctxt->value == NULL) ||
6247 ((ctxt->value->type != XPATH_NODESET) &&
6248 (ctxt->value->type != XPATH_XSLT_TREE)))
6249 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006250 cur = valuePop(ctxt);
6251
Daniel Veillard911f49a2001-04-07 15:39:35 +00006252 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006253 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006254 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006255 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006256
Daniel Veillard04383752001-07-08 14:27:15 +00006257 switch (cur->nodesetval->nodeTab[i]->type) {
6258 case XML_ELEMENT_NODE:
6259 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006260 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6261 valuePush(ctxt, xmlXPathNewCString(""));
6262 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6263 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006264 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006265 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006266
Daniel Veillard652d8a92003-02-04 19:28:49 +00006267 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006268 xmlChar *fullname;
6269
6270 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6271 cur->nodesetval->nodeTab[i]->ns->prefix,
6272 NULL, 0);
6273 if (fullname == cur->nodesetval->nodeTab[i]->name)
6274 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6275 if (fullname == NULL) {
6276 XP_ERROR(XPATH_MEMORY_ERROR);
6277 }
6278 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006279 }
6280 break;
6281 default:
6282 valuePush(ctxt,
6283 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6284 xmlXPathLocalNameFunction(ctxt, 1);
6285 }
Owen Taylor3473f882001-02-23 17:55:21 +00006286 }
6287 xmlXPathFreeObject(cur);
6288}
6289
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006290
6291/**
Owen Taylor3473f882001-02-23 17:55:21 +00006292 * xmlXPathStringFunction:
6293 * @ctxt: the XPath Parser context
6294 * @nargs: the number of arguments
6295 *
6296 * Implement the string() XPath function
6297 * string string(object?)
6298 * he string function converts an object to a string as follows:
6299 * - A node-set is converted to a string by returning the value of
6300 * the node in the node-set that is first in document order.
6301 * If the node-set is empty, an empty string is returned.
6302 * - A number is converted to a string as follows
6303 * + NaN is converted to the string NaN
6304 * + positive zero is converted to the string 0
6305 * + negative zero is converted to the string 0
6306 * + positive infinity is converted to the string Infinity
6307 * + negative infinity is converted to the string -Infinity
6308 * + if the number is an integer, the number is represented in
6309 * decimal form as a Number with no decimal point and no leading
6310 * zeros, preceded by a minus sign (-) if the number is negative
6311 * + otherwise, the number is represented in decimal form as a
6312 * Number including a decimal point with at least one digit
6313 * before the decimal point and at least one digit after the
6314 * decimal point, preceded by a minus sign (-) if the number
6315 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006316 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006317 * before the decimal point; beyond the one required digit
6318 * after the decimal point there must be as many, but only as
6319 * many, more digits as are needed to uniquely distinguish the
6320 * number from all other IEEE 754 numeric values.
6321 * - The boolean false value is converted to the string false.
6322 * The boolean true value is converted to the string true.
6323 *
6324 * If the argument is omitted, it defaults to a node-set with the
6325 * context node as its only member.
6326 */
6327void
6328xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6329 xmlXPathObjectPtr cur;
6330
6331 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006332 valuePush(ctxt,
6333 xmlXPathWrapString(
6334 xmlXPathCastNodeToString(ctxt->context->node)));
6335 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006336 }
6337
6338 CHECK_ARITY(1);
6339 cur = valuePop(ctxt);
6340 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006341 cur = xmlXPathConvertString(cur);
6342 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006343}
6344
6345/**
6346 * xmlXPathStringLengthFunction:
6347 * @ctxt: the XPath Parser context
6348 * @nargs: the number of arguments
6349 *
6350 * Implement the string-length() XPath function
6351 * number string-length(string?)
6352 * The string-length returns the number of characters in the string
6353 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6354 * the context node converted to a string, in other words the value
6355 * of the context node.
6356 */
6357void
6358xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6359 xmlXPathObjectPtr cur;
6360
6361 if (nargs == 0) {
6362 if (ctxt->context->node == NULL) {
6363 valuePush(ctxt, xmlXPathNewFloat(0));
6364 } else {
6365 xmlChar *content;
6366
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006367 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006368 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006369 xmlFree(content);
6370 }
6371 return;
6372 }
6373 CHECK_ARITY(1);
6374 CAST_TO_STRING;
6375 CHECK_TYPE(XPATH_STRING);
6376 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006377 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006378 xmlXPathFreeObject(cur);
6379}
6380
6381/**
6382 * xmlXPathConcatFunction:
6383 * @ctxt: the XPath Parser context
6384 * @nargs: the number of arguments
6385 *
6386 * Implement the concat() XPath function
6387 * string concat(string, string, string*)
6388 * The concat function returns the concatenation of its arguments.
6389 */
6390void
6391xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6392 xmlXPathObjectPtr cur, newobj;
6393 xmlChar *tmp;
6394
6395 if (nargs < 2) {
6396 CHECK_ARITY(2);
6397 }
6398
6399 CAST_TO_STRING;
6400 cur = valuePop(ctxt);
6401 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6402 xmlXPathFreeObject(cur);
6403 return;
6404 }
6405 nargs--;
6406
6407 while (nargs > 0) {
6408 CAST_TO_STRING;
6409 newobj = valuePop(ctxt);
6410 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6411 xmlXPathFreeObject(newobj);
6412 xmlXPathFreeObject(cur);
6413 XP_ERROR(XPATH_INVALID_TYPE);
6414 }
6415 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6416 newobj->stringval = cur->stringval;
6417 cur->stringval = tmp;
6418
6419 xmlXPathFreeObject(newobj);
6420 nargs--;
6421 }
6422 valuePush(ctxt, cur);
6423}
6424
6425/**
6426 * xmlXPathContainsFunction:
6427 * @ctxt: the XPath Parser context
6428 * @nargs: the number of arguments
6429 *
6430 * Implement the contains() XPath function
6431 * boolean contains(string, string)
6432 * The contains function returns true if the first argument string
6433 * contains the second argument string, and otherwise returns false.
6434 */
6435void
6436xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6437 xmlXPathObjectPtr hay, needle;
6438
6439 CHECK_ARITY(2);
6440 CAST_TO_STRING;
6441 CHECK_TYPE(XPATH_STRING);
6442 needle = valuePop(ctxt);
6443 CAST_TO_STRING;
6444 hay = valuePop(ctxt);
6445 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6446 xmlXPathFreeObject(hay);
6447 xmlXPathFreeObject(needle);
6448 XP_ERROR(XPATH_INVALID_TYPE);
6449 }
6450 if (xmlStrstr(hay->stringval, needle->stringval))
6451 valuePush(ctxt, xmlXPathNewBoolean(1));
6452 else
6453 valuePush(ctxt, xmlXPathNewBoolean(0));
6454 xmlXPathFreeObject(hay);
6455 xmlXPathFreeObject(needle);
6456}
6457
6458/**
6459 * xmlXPathStartsWithFunction:
6460 * @ctxt: the XPath Parser context
6461 * @nargs: the number of arguments
6462 *
6463 * Implement the starts-with() XPath function
6464 * boolean starts-with(string, string)
6465 * The starts-with function returns true if the first argument string
6466 * starts with the second argument string, and otherwise returns false.
6467 */
6468void
6469xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6470 xmlXPathObjectPtr hay, needle;
6471 int n;
6472
6473 CHECK_ARITY(2);
6474 CAST_TO_STRING;
6475 CHECK_TYPE(XPATH_STRING);
6476 needle = valuePop(ctxt);
6477 CAST_TO_STRING;
6478 hay = valuePop(ctxt);
6479 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6480 xmlXPathFreeObject(hay);
6481 xmlXPathFreeObject(needle);
6482 XP_ERROR(XPATH_INVALID_TYPE);
6483 }
6484 n = xmlStrlen(needle->stringval);
6485 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6486 valuePush(ctxt, xmlXPathNewBoolean(0));
6487 else
6488 valuePush(ctxt, xmlXPathNewBoolean(1));
6489 xmlXPathFreeObject(hay);
6490 xmlXPathFreeObject(needle);
6491}
6492
6493/**
6494 * xmlXPathSubstringFunction:
6495 * @ctxt: the XPath Parser context
6496 * @nargs: the number of arguments
6497 *
6498 * Implement the substring() XPath function
6499 * string substring(string, number, number?)
6500 * The substring function returns the substring of the first argument
6501 * starting at the position specified in the second argument with
6502 * length specified in the third argument. For example,
6503 * substring("12345",2,3) returns "234". If the third argument is not
6504 * specified, it returns the substring starting at the position specified
6505 * in the second argument and continuing to the end of the string. For
6506 * example, substring("12345",2) returns "2345". More precisely, each
6507 * character in the string (see [3.6 Strings]) is considered to have a
6508 * numeric position: the position of the first character is 1, the position
6509 * of the second character is 2 and so on. The returned substring contains
6510 * those characters for which the position of the character is greater than
6511 * or equal to the second argument and, if the third argument is specified,
6512 * less than the sum of the second and third arguments; the comparisons
6513 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6514 * - substring("12345", 1.5, 2.6) returns "234"
6515 * - substring("12345", 0, 3) returns "12"
6516 * - substring("12345", 0 div 0, 3) returns ""
6517 * - substring("12345", 1, 0 div 0) returns ""
6518 * - substring("12345", -42, 1 div 0) returns "12345"
6519 * - substring("12345", -1 div 0, 1 div 0) returns ""
6520 */
6521void
6522xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6523 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006524 double le=0, in;
6525 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006526 xmlChar *ret;
6527
Owen Taylor3473f882001-02-23 17:55:21 +00006528 if (nargs < 2) {
6529 CHECK_ARITY(2);
6530 }
6531 if (nargs > 3) {
6532 CHECK_ARITY(3);
6533 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006534 /*
6535 * take care of possible last (position) argument
6536 */
Owen Taylor3473f882001-02-23 17:55:21 +00006537 if (nargs == 3) {
6538 CAST_TO_NUMBER;
6539 CHECK_TYPE(XPATH_NUMBER);
6540 len = valuePop(ctxt);
6541 le = len->floatval;
6542 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006543 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006544
Owen Taylor3473f882001-02-23 17:55:21 +00006545 CAST_TO_NUMBER;
6546 CHECK_TYPE(XPATH_NUMBER);
6547 start = valuePop(ctxt);
6548 in = start->floatval;
6549 xmlXPathFreeObject(start);
6550 CAST_TO_STRING;
6551 CHECK_TYPE(XPATH_STRING);
6552 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006553 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006554
Daniel Veillard97ac1312001-05-30 19:14:17 +00006555 /*
6556 * If last pos not present, calculate last position
6557 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006558 if (nargs != 3) {
6559 le = (double)m;
6560 if (in < 1.0)
6561 in = 1.0;
6562 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006563
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006564 /* Need to check for the special cases where either
6565 * the index is NaN, the length is NaN, or both
6566 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006567 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006568 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006569 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006570 * To meet the requirements of the spec, the arguments
6571 * must be converted to integer format before
6572 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006573 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006574 * First we go to integer form, rounding up
6575 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006576 */
6577 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006578 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006579
Daniel Veillard9e412302002-06-10 15:59:44 +00006580 if (xmlXPathIsInf(le) == 1) {
6581 l = m;
6582 if (i < 1)
6583 i = 1;
6584 }
6585 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6586 l = 0;
6587 else {
6588 l = (int) le;
6589 if (((double)l)+0.5 <= le) l++;
6590 }
6591
6592 /* Now we normalize inidices */
6593 i -= 1;
6594 l += i;
6595 if (i < 0)
6596 i = 0;
6597 if (l > m)
6598 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006599
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006600 /* number of chars to copy */
6601 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006602
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006603 ret = xmlUTF8Strsub(str->stringval, i, l);
6604 }
6605 else {
6606 ret = NULL;
6607 }
6608
Owen Taylor3473f882001-02-23 17:55:21 +00006609 if (ret == NULL)
6610 valuePush(ctxt, xmlXPathNewCString(""));
6611 else {
6612 valuePush(ctxt, xmlXPathNewString(ret));
6613 xmlFree(ret);
6614 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006615
Owen Taylor3473f882001-02-23 17:55:21 +00006616 xmlXPathFreeObject(str);
6617}
6618
6619/**
6620 * xmlXPathSubstringBeforeFunction:
6621 * @ctxt: the XPath Parser context
6622 * @nargs: the number of arguments
6623 *
6624 * Implement the substring-before() XPath function
6625 * string substring-before(string, string)
6626 * The substring-before function returns the substring of the first
6627 * argument string that precedes the first occurrence of the second
6628 * argument string in the first argument string, or the empty string
6629 * if the first argument string does not contain the second argument
6630 * string. For example, substring-before("1999/04/01","/") returns 1999.
6631 */
6632void
6633xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6634 xmlXPathObjectPtr str;
6635 xmlXPathObjectPtr find;
6636 xmlBufferPtr target;
6637 const xmlChar *point;
6638 int offset;
6639
6640 CHECK_ARITY(2);
6641 CAST_TO_STRING;
6642 find = valuePop(ctxt);
6643 CAST_TO_STRING;
6644 str = valuePop(ctxt);
6645
6646 target = xmlBufferCreate();
6647 if (target) {
6648 point = xmlStrstr(str->stringval, find->stringval);
6649 if (point) {
6650 offset = (int)(point - str->stringval);
6651 xmlBufferAdd(target, str->stringval, offset);
6652 }
6653 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6654 xmlBufferFree(target);
6655 }
6656
6657 xmlXPathFreeObject(str);
6658 xmlXPathFreeObject(find);
6659}
6660
6661/**
6662 * xmlXPathSubstringAfterFunction:
6663 * @ctxt: the XPath Parser context
6664 * @nargs: the number of arguments
6665 *
6666 * Implement the substring-after() XPath function
6667 * string substring-after(string, string)
6668 * The substring-after function returns the substring of the first
6669 * argument string that follows the first occurrence of the second
6670 * argument string in the first argument string, or the empty stringi
6671 * if the first argument string does not contain the second argument
6672 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6673 * and substring-after("1999/04/01","19") returns 99/04/01.
6674 */
6675void
6676xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6677 xmlXPathObjectPtr str;
6678 xmlXPathObjectPtr find;
6679 xmlBufferPtr target;
6680 const xmlChar *point;
6681 int offset;
6682
6683 CHECK_ARITY(2);
6684 CAST_TO_STRING;
6685 find = valuePop(ctxt);
6686 CAST_TO_STRING;
6687 str = valuePop(ctxt);
6688
6689 target = xmlBufferCreate();
6690 if (target) {
6691 point = xmlStrstr(str->stringval, find->stringval);
6692 if (point) {
6693 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6694 xmlBufferAdd(target, &str->stringval[offset],
6695 xmlStrlen(str->stringval) - offset);
6696 }
6697 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6698 xmlBufferFree(target);
6699 }
6700
6701 xmlXPathFreeObject(str);
6702 xmlXPathFreeObject(find);
6703}
6704
6705/**
6706 * xmlXPathNormalizeFunction:
6707 * @ctxt: the XPath Parser context
6708 * @nargs: the number of arguments
6709 *
6710 * Implement the normalize-space() XPath function
6711 * string normalize-space(string?)
6712 * The normalize-space function returns the argument string with white
6713 * space normalized by stripping leading and trailing whitespace
6714 * and replacing sequences of whitespace characters by a single
6715 * space. Whitespace characters are the same allowed by the S production
6716 * in XML. If the argument is omitted, it defaults to the context
6717 * node converted to a string, in other words the value of the context node.
6718 */
6719void
6720xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6721 xmlXPathObjectPtr obj = NULL;
6722 xmlChar *source = NULL;
6723 xmlBufferPtr target;
6724 xmlChar blank;
6725
6726 if (nargs == 0) {
6727 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006728 valuePush(ctxt,
6729 xmlXPathWrapString(
6730 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006731 nargs = 1;
6732 }
6733
6734 CHECK_ARITY(1);
6735 CAST_TO_STRING;
6736 CHECK_TYPE(XPATH_STRING);
6737 obj = valuePop(ctxt);
6738 source = obj->stringval;
6739
6740 target = xmlBufferCreate();
6741 if (target && source) {
6742
6743 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006744 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006745 source++;
6746
6747 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6748 blank = 0;
6749 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006750 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006751 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006752 } else {
6753 if (blank) {
6754 xmlBufferAdd(target, &blank, 1);
6755 blank = 0;
6756 }
6757 xmlBufferAdd(target, source, 1);
6758 }
6759 source++;
6760 }
6761
6762 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6763 xmlBufferFree(target);
6764 }
6765 xmlXPathFreeObject(obj);
6766}
6767
6768/**
6769 * xmlXPathTranslateFunction:
6770 * @ctxt: the XPath Parser context
6771 * @nargs: the number of arguments
6772 *
6773 * Implement the translate() XPath function
6774 * string translate(string, string, string)
6775 * The translate function returns the first argument string with
6776 * occurrences of characters in the second argument string replaced
6777 * by the character at the corresponding position in the third argument
6778 * string. For example, translate("bar","abc","ABC") returns the string
6779 * BAr. If there is a character in the second argument string with no
6780 * character at a corresponding position in the third argument string
6781 * (because the second argument string is longer than the third argument
6782 * string), then occurrences of that character in the first argument
6783 * string are removed. For example, translate("--aaa--","abc-","ABC")
6784 * returns "AAA". If a character occurs more than once in second
6785 * argument string, then the first occurrence determines the replacement
6786 * character. If the third argument string is longer than the second
6787 * argument string, then excess characters are ignored.
6788 */
6789void
6790xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006791 xmlXPathObjectPtr str;
6792 xmlXPathObjectPtr from;
6793 xmlXPathObjectPtr to;
6794 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006795 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006796 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006797 xmlChar *point;
6798 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006799
Daniel Veillarde043ee12001-04-16 14:08:07 +00006800 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006801
Daniel Veillarde043ee12001-04-16 14:08:07 +00006802 CAST_TO_STRING;
6803 to = valuePop(ctxt);
6804 CAST_TO_STRING;
6805 from = valuePop(ctxt);
6806 CAST_TO_STRING;
6807 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006808
Daniel Veillarde043ee12001-04-16 14:08:07 +00006809 target = xmlBufferCreate();
6810 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006811 max = xmlUTF8Strlen(to->stringval);
6812 for (cptr = str->stringval; (ch=*cptr); ) {
6813 offset = xmlUTF8Strloc(from->stringval, cptr);
6814 if (offset >= 0) {
6815 if (offset < max) {
6816 point = xmlUTF8Strpos(to->stringval, offset);
6817 if (point)
6818 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6819 }
6820 } else
6821 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6822
6823 /* Step to next character in input */
6824 cptr++;
6825 if ( ch & 0x80 ) {
6826 /* if not simple ascii, verify proper format */
6827 if ( (ch & 0xc0) != 0xc0 ) {
6828 xmlGenericError(xmlGenericErrorContext,
6829 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6830 break;
6831 }
6832 /* then skip over remaining bytes for this char */
6833 while ( (ch <<= 1) & 0x80 )
6834 if ( (*cptr++ & 0xc0) != 0x80 ) {
6835 xmlGenericError(xmlGenericErrorContext,
6836 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6837 break;
6838 }
6839 if (ch & 0x80) /* must have had error encountered */
6840 break;
6841 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006842 }
Owen Taylor3473f882001-02-23 17:55:21 +00006843 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006844 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6845 xmlBufferFree(target);
6846 xmlXPathFreeObject(str);
6847 xmlXPathFreeObject(from);
6848 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006849}
6850
6851/**
6852 * xmlXPathBooleanFunction:
6853 * @ctxt: the XPath Parser context
6854 * @nargs: the number of arguments
6855 *
6856 * Implement the boolean() XPath function
6857 * boolean boolean(object)
6858 * he boolean function converts its argument to a boolean as follows:
6859 * - a number is true if and only if it is neither positive or
6860 * negative zero nor NaN
6861 * - a node-set is true if and only if it is non-empty
6862 * - a string is true if and only if its length is non-zero
6863 */
6864void
6865xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6866 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006867
6868 CHECK_ARITY(1);
6869 cur = valuePop(ctxt);
6870 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006871 cur = xmlXPathConvertBoolean(cur);
6872 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006873}
6874
6875/**
6876 * xmlXPathNotFunction:
6877 * @ctxt: the XPath Parser context
6878 * @nargs: the number of arguments
6879 *
6880 * Implement the not() XPath function
6881 * boolean not(boolean)
6882 * The not function returns true if its argument is false,
6883 * and false otherwise.
6884 */
6885void
6886xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6887 CHECK_ARITY(1);
6888 CAST_TO_BOOLEAN;
6889 CHECK_TYPE(XPATH_BOOLEAN);
6890 ctxt->value->boolval = ! ctxt->value->boolval;
6891}
6892
6893/**
6894 * xmlXPathTrueFunction:
6895 * @ctxt: the XPath Parser context
6896 * @nargs: the number of arguments
6897 *
6898 * Implement the true() XPath function
6899 * boolean true()
6900 */
6901void
6902xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6903 CHECK_ARITY(0);
6904 valuePush(ctxt, xmlXPathNewBoolean(1));
6905}
6906
6907/**
6908 * xmlXPathFalseFunction:
6909 * @ctxt: the XPath Parser context
6910 * @nargs: the number of arguments
6911 *
6912 * Implement the false() XPath function
6913 * boolean false()
6914 */
6915void
6916xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6917 CHECK_ARITY(0);
6918 valuePush(ctxt, xmlXPathNewBoolean(0));
6919}
6920
6921/**
6922 * xmlXPathLangFunction:
6923 * @ctxt: the XPath Parser context
6924 * @nargs: the number of arguments
6925 *
6926 * Implement the lang() XPath function
6927 * boolean lang(string)
6928 * The lang function returns true or false depending on whether the
6929 * language of the context node as specified by xml:lang attributes
6930 * is the same as or is a sublanguage of the language specified by
6931 * the argument string. The language of the context node is determined
6932 * by the value of the xml:lang attribute on the context node, or, if
6933 * the context node has no xml:lang attribute, by the value of the
6934 * xml:lang attribute on the nearest ancestor of the context node that
6935 * has an xml:lang attribute. If there is no such attribute, then lang
6936 * returns false. If there is such an attribute, then lang returns
6937 * true if the attribute value is equal to the argument ignoring case,
6938 * or if there is some suffix starting with - such that the attribute
6939 * value is equal to the argument ignoring that suffix of the attribute
6940 * value and ignoring case.
6941 */
6942void
6943xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6944 xmlXPathObjectPtr val;
6945 const xmlChar *theLang;
6946 const xmlChar *lang;
6947 int ret = 0;
6948 int i;
6949
6950 CHECK_ARITY(1);
6951 CAST_TO_STRING;
6952 CHECK_TYPE(XPATH_STRING);
6953 val = valuePop(ctxt);
6954 lang = val->stringval;
6955 theLang = xmlNodeGetLang(ctxt->context->node);
6956 if ((theLang != NULL) && (lang != NULL)) {
6957 for (i = 0;lang[i] != 0;i++)
6958 if (toupper(lang[i]) != toupper(theLang[i]))
6959 goto not_equal;
6960 ret = 1;
6961 }
6962not_equal:
6963 xmlXPathFreeObject(val);
6964 valuePush(ctxt, xmlXPathNewBoolean(ret));
6965}
6966
6967/**
6968 * xmlXPathNumberFunction:
6969 * @ctxt: the XPath Parser context
6970 * @nargs: the number of arguments
6971 *
6972 * Implement the number() XPath function
6973 * number number(object?)
6974 */
6975void
6976xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6977 xmlXPathObjectPtr cur;
6978 double res;
6979
6980 if (nargs == 0) {
6981 if (ctxt->context->node == NULL) {
6982 valuePush(ctxt, xmlXPathNewFloat(0.0));
6983 } else {
6984 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6985
6986 res = xmlXPathStringEvalNumber(content);
6987 valuePush(ctxt, xmlXPathNewFloat(res));
6988 xmlFree(content);
6989 }
6990 return;
6991 }
6992
6993 CHECK_ARITY(1);
6994 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006995 cur = xmlXPathConvertNumber(cur);
6996 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006997}
6998
6999/**
7000 * xmlXPathSumFunction:
7001 * @ctxt: the XPath Parser context
7002 * @nargs: the number of arguments
7003 *
7004 * Implement the sum() XPath function
7005 * number sum(node-set)
7006 * The sum function returns the sum of the values of the nodes in
7007 * the argument node-set.
7008 */
7009void
7010xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7011 xmlXPathObjectPtr cur;
7012 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007013 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007014
7015 CHECK_ARITY(1);
7016 if ((ctxt->value == NULL) ||
7017 ((ctxt->value->type != XPATH_NODESET) &&
7018 (ctxt->value->type != XPATH_XSLT_TREE)))
7019 XP_ERROR(XPATH_INVALID_TYPE);
7020 cur = valuePop(ctxt);
7021
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007022 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007023 valuePush(ctxt, xmlXPathNewFloat(0.0));
7024 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007025 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7026 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007027 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007028 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007029 }
7030 xmlXPathFreeObject(cur);
7031}
7032
7033/**
7034 * xmlXPathFloorFunction:
7035 * @ctxt: the XPath Parser context
7036 * @nargs: the number of arguments
7037 *
7038 * Implement the floor() XPath function
7039 * number floor(number)
7040 * The floor function returns the largest (closest to positive infinity)
7041 * number that is not greater than the argument and that is an integer.
7042 */
7043void
7044xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007045 double f;
7046
Owen Taylor3473f882001-02-23 17:55:21 +00007047 CHECK_ARITY(1);
7048 CAST_TO_NUMBER;
7049 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007050
7051 f = (double)((int) ctxt->value->floatval);
7052 if (f != ctxt->value->floatval) {
7053 if (ctxt->value->floatval > 0)
7054 ctxt->value->floatval = f;
7055 else
7056 ctxt->value->floatval = f - 1;
7057 }
Owen Taylor3473f882001-02-23 17:55:21 +00007058}
7059
7060/**
7061 * xmlXPathCeilingFunction:
7062 * @ctxt: the XPath Parser context
7063 * @nargs: the number of arguments
7064 *
7065 * Implement the ceiling() XPath function
7066 * number ceiling(number)
7067 * The ceiling function returns the smallest (closest to negative infinity)
7068 * number that is not less than the argument and that is an integer.
7069 */
7070void
7071xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7072 double f;
7073
7074 CHECK_ARITY(1);
7075 CAST_TO_NUMBER;
7076 CHECK_TYPE(XPATH_NUMBER);
7077
7078#if 0
7079 ctxt->value->floatval = ceil(ctxt->value->floatval);
7080#else
7081 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007082 if (f != ctxt->value->floatval) {
7083 if (ctxt->value->floatval > 0)
7084 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007085 else {
7086 if (ctxt->value->floatval < 0 && f == 0)
7087 ctxt->value->floatval = xmlXPathNZERO;
7088 else
7089 ctxt->value->floatval = f;
7090 }
7091
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007092 }
Owen Taylor3473f882001-02-23 17:55:21 +00007093#endif
7094}
7095
7096/**
7097 * xmlXPathRoundFunction:
7098 * @ctxt: the XPath Parser context
7099 * @nargs: the number of arguments
7100 *
7101 * Implement the round() XPath function
7102 * number round(number)
7103 * The round function returns the number that is closest to the
7104 * argument and that is an integer. If there are two such numbers,
7105 * then the one that is even is returned.
7106 */
7107void
7108xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7109 double f;
7110
7111 CHECK_ARITY(1);
7112 CAST_TO_NUMBER;
7113 CHECK_TYPE(XPATH_NUMBER);
7114
Daniel Veillardcda96922001-08-21 10:56:31 +00007115 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7116 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7117 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007118 (ctxt->value->floatval == 0.0))
7119 return;
7120
Owen Taylor3473f882001-02-23 17:55:21 +00007121 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007122 if (ctxt->value->floatval < 0) {
7123 if (ctxt->value->floatval < f - 0.5)
7124 ctxt->value->floatval = f - 1;
7125 else
7126 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007127 if (ctxt->value->floatval == 0)
7128 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007129 } else {
7130 if (ctxt->value->floatval < f + 0.5)
7131 ctxt->value->floatval = f;
7132 else
7133 ctxt->value->floatval = f + 1;
7134 }
Owen Taylor3473f882001-02-23 17:55:21 +00007135}
7136
7137/************************************************************************
7138 * *
7139 * The Parser *
7140 * *
7141 ************************************************************************/
7142
7143/*
7144 * a couple of forward declarations since we use a recursive call based
7145 * implementation.
7146 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007147static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007148static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007149static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007150static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007151static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7152 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007153
7154/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007155 * xmlXPathCurrentChar:
7156 * @ctxt: the XPath parser context
7157 * @cur: pointer to the beginning of the char
7158 * @len: pointer to the length of the char read
7159 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007160 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007161 * bytes in the input buffer.
7162 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007163 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007164 */
7165
7166static int
7167xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7168 unsigned char c;
7169 unsigned int val;
7170 const xmlChar *cur;
7171
7172 if (ctxt == NULL)
7173 return(0);
7174 cur = ctxt->cur;
7175
7176 /*
7177 * We are supposed to handle UTF8, check it's valid
7178 * From rfc2044: encoding of the Unicode values on UTF-8:
7179 *
7180 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7181 * 0000 0000-0000 007F 0xxxxxxx
7182 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7183 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7184 *
7185 * Check for the 0x110000 limit too
7186 */
7187 c = *cur;
7188 if (c & 0x80) {
7189 if ((cur[1] & 0xc0) != 0x80)
7190 goto encoding_error;
7191 if ((c & 0xe0) == 0xe0) {
7192
7193 if ((cur[2] & 0xc0) != 0x80)
7194 goto encoding_error;
7195 if ((c & 0xf0) == 0xf0) {
7196 if (((c & 0xf8) != 0xf0) ||
7197 ((cur[3] & 0xc0) != 0x80))
7198 goto encoding_error;
7199 /* 4-byte code */
7200 *len = 4;
7201 val = (cur[0] & 0x7) << 18;
7202 val |= (cur[1] & 0x3f) << 12;
7203 val |= (cur[2] & 0x3f) << 6;
7204 val |= cur[3] & 0x3f;
7205 } else {
7206 /* 3-byte code */
7207 *len = 3;
7208 val = (cur[0] & 0xf) << 12;
7209 val |= (cur[1] & 0x3f) << 6;
7210 val |= cur[2] & 0x3f;
7211 }
7212 } else {
7213 /* 2-byte code */
7214 *len = 2;
7215 val = (cur[0] & 0x1f) << 6;
7216 val |= cur[1] & 0x3f;
7217 }
7218 if (!IS_CHAR(val)) {
7219 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7220 }
7221 return(val);
7222 } else {
7223 /* 1-byte code */
7224 *len = 1;
7225 return((int) *cur);
7226 }
7227encoding_error:
7228 /*
7229 * If we detect an UTF8 error that probably mean that the
7230 * input encoding didn't get properly advertized in the
7231 * declaration header. Report the error and switch the encoding
7232 * to ISO-Latin-1 (if you don't like this policy, just declare the
7233 * encoding !)
7234 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007235 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007236 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007237}
7238
7239/**
Owen Taylor3473f882001-02-23 17:55:21 +00007240 * xmlXPathParseNCName:
7241 * @ctxt: the XPath Parser context
7242 *
7243 * parse an XML namespace non qualified name.
7244 *
7245 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7246 *
7247 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7248 * CombiningChar | Extender
7249 *
7250 * Returns the namespace name or NULL
7251 */
7252
7253xmlChar *
7254xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007255 const xmlChar *in;
7256 xmlChar *ret;
7257 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007258
Daniel Veillard2156a562001-04-28 12:24:34 +00007259 /*
7260 * Accelerator for simple ASCII names
7261 */
7262 in = ctxt->cur;
7263 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7264 ((*in >= 0x41) && (*in <= 0x5A)) ||
7265 (*in == '_')) {
7266 in++;
7267 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7268 ((*in >= 0x41) && (*in <= 0x5A)) ||
7269 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007270 (*in == '_') || (*in == '.') ||
7271 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007272 in++;
7273 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7274 (*in == '[') || (*in == ']') || (*in == ':') ||
7275 (*in == '@') || (*in == '*')) {
7276 count = in - ctxt->cur;
7277 if (count == 0)
7278 return(NULL);
7279 ret = xmlStrndup(ctxt->cur, count);
7280 ctxt->cur = in;
7281 return(ret);
7282 }
7283 }
7284 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007285}
7286
Daniel Veillard2156a562001-04-28 12:24:34 +00007287
Owen Taylor3473f882001-02-23 17:55:21 +00007288/**
7289 * xmlXPathParseQName:
7290 * @ctxt: the XPath Parser context
7291 * @prefix: a xmlChar **
7292 *
7293 * parse an XML qualified name
7294 *
7295 * [NS 5] QName ::= (Prefix ':')? LocalPart
7296 *
7297 * [NS 6] Prefix ::= NCName
7298 *
7299 * [NS 7] LocalPart ::= NCName
7300 *
7301 * Returns the function returns the local part, and prefix is updated
7302 * to get the Prefix if any.
7303 */
7304
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007305static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007306xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7307 xmlChar *ret = NULL;
7308
7309 *prefix = NULL;
7310 ret = xmlXPathParseNCName(ctxt);
7311 if (CUR == ':') {
7312 *prefix = ret;
7313 NEXT;
7314 ret = xmlXPathParseNCName(ctxt);
7315 }
7316 return(ret);
7317}
7318
7319/**
7320 * xmlXPathParseName:
7321 * @ctxt: the XPath Parser context
7322 *
7323 * parse an XML name
7324 *
7325 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7326 * CombiningChar | Extender
7327 *
7328 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7329 *
7330 * Returns the namespace name or NULL
7331 */
7332
7333xmlChar *
7334xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007335 const xmlChar *in;
7336 xmlChar *ret;
7337 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007338
Daniel Veillard61d80a22001-04-27 17:13:01 +00007339 /*
7340 * Accelerator for simple ASCII names
7341 */
7342 in = ctxt->cur;
7343 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7344 ((*in >= 0x41) && (*in <= 0x5A)) ||
7345 (*in == '_') || (*in == ':')) {
7346 in++;
7347 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7348 ((*in >= 0x41) && (*in <= 0x5A)) ||
7349 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007350 (*in == '_') || (*in == '-') ||
7351 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007352 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007353 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007354 count = in - ctxt->cur;
7355 ret = xmlStrndup(ctxt->cur, count);
7356 ctxt->cur = in;
7357 return(ret);
7358 }
7359 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007360 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007361}
7362
Daniel Veillard61d80a22001-04-27 17:13:01 +00007363static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007364xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007365 xmlChar buf[XML_MAX_NAMELEN + 5];
7366 int len = 0, l;
7367 int c;
7368
7369 /*
7370 * Handler for more complex cases
7371 */
7372 c = CUR_CHAR(l);
7373 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007374 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7375 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007376 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007377 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007378 return(NULL);
7379 }
7380
7381 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7382 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7383 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007384 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007385 (IS_COMBINING(c)) ||
7386 (IS_EXTENDER(c)))) {
7387 COPY_BUF(l,buf,len,c);
7388 NEXTL(l);
7389 c = CUR_CHAR(l);
7390 if (len >= XML_MAX_NAMELEN) {
7391 /*
7392 * Okay someone managed to make a huge name, so he's ready to pay
7393 * for the processing speed.
7394 */
7395 xmlChar *buffer;
7396 int max = len * 2;
7397
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007398 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007399 if (buffer == NULL) {
7400 XP_ERROR0(XPATH_MEMORY_ERROR);
7401 }
7402 memcpy(buffer, buf, len);
7403 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7404 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007405 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007406 (IS_COMBINING(c)) ||
7407 (IS_EXTENDER(c))) {
7408 if (len + 10 > max) {
7409 max *= 2;
7410 buffer = (xmlChar *) xmlRealloc(buffer,
7411 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007412 if (buffer == NULL) {
7413 XP_ERROR0(XPATH_MEMORY_ERROR);
7414 }
7415 }
7416 COPY_BUF(l,buffer,len,c);
7417 NEXTL(l);
7418 c = CUR_CHAR(l);
7419 }
7420 buffer[len] = 0;
7421 return(buffer);
7422 }
7423 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007424 if (len == 0)
7425 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007426 return(xmlStrndup(buf, len));
7427}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007428
7429#define MAX_FRAC 20
7430
7431static double my_pow10[MAX_FRAC] = {
7432 1.0, 10.0, 100.0, 1000.0, 10000.0,
7433 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7434 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7435 100000000000000.0,
7436 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7437 1000000000000000000.0, 10000000000000000000.0
7438};
7439
Owen Taylor3473f882001-02-23 17:55:21 +00007440/**
7441 * xmlXPathStringEvalNumber:
7442 * @str: A string to scan
7443 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007444 * [30a] Float ::= Number ('e' Digits?)?
7445 *
Owen Taylor3473f882001-02-23 17:55:21 +00007446 * [30] Number ::= Digits ('.' Digits?)?
7447 * | '.' Digits
7448 * [31] Digits ::= [0-9]+
7449 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007450 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007451 * In complement of the Number expression, this function also handles
7452 * negative values : '-' Number.
7453 *
7454 * Returns the double value.
7455 */
7456double
7457xmlXPathStringEvalNumber(const xmlChar *str) {
7458 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007459 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007460 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007461 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007462 int exponent = 0;
7463 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007464#ifdef __GNUC__
7465 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007466 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007467#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007468 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007469 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007470 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7471 return(xmlXPathNAN);
7472 }
7473 if (*cur == '-') {
7474 isneg = 1;
7475 cur++;
7476 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007477
7478#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007479 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007480 * tmp/temp is a workaround against a gcc compiler bug
7481 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007482 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007483 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007484 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007485 ret = ret * 10;
7486 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007487 ok = 1;
7488 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007489 temp = (double) tmp;
7490 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007491 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007492#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007493 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007494 while ((*cur >= '0') && (*cur <= '9')) {
7495 ret = ret * 10 + (*cur - '0');
7496 ok = 1;
7497 cur++;
7498 }
7499#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007500
Owen Taylor3473f882001-02-23 17:55:21 +00007501 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007502 int v, frac = 0;
7503 double fraction = 0;
7504
Owen Taylor3473f882001-02-23 17:55:21 +00007505 cur++;
7506 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7507 return(xmlXPathNAN);
7508 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007509 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7510 v = (*cur - '0');
7511 fraction = fraction * 10 + v;
7512 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007513 cur++;
7514 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007515 fraction /= my_pow10[frac];
7516 ret = ret + fraction;
7517 while ((*cur >= '0') && (*cur <= '9'))
7518 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007519 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007520 if ((*cur == 'e') || (*cur == 'E')) {
7521 cur++;
7522 if (*cur == '-') {
7523 is_exponent_negative = 1;
7524 cur++;
7525 }
7526 while ((*cur >= '0') && (*cur <= '9')) {
7527 exponent = exponent * 10 + (*cur - '0');
7528 cur++;
7529 }
7530 }
William M. Brack76e95df2003-10-18 16:20:14 +00007531 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007532 if (*cur != 0) return(xmlXPathNAN);
7533 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007534 if (is_exponent_negative) exponent = -exponent;
7535 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007536 return(ret);
7537}
7538
7539/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007540 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007541 * @ctxt: the XPath Parser context
7542 *
7543 * [30] Number ::= Digits ('.' Digits?)?
7544 * | '.' Digits
7545 * [31] Digits ::= [0-9]+
7546 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007547 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007548 *
7549 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007550static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007551xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7552{
Owen Taylor3473f882001-02-23 17:55:21 +00007553 double ret = 0.0;
7554 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007555 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007556 int exponent = 0;
7557 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007558#ifdef __GNUC__
7559 unsigned long tmp = 0;
7560 double temp;
7561#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007562
7563 CHECK_ERROR;
7564 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7565 XP_ERROR(XPATH_NUMBER_ERROR);
7566 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007567#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007568 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007569 * tmp/temp is a workaround against a gcc compiler bug
7570 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007571 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007572 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007573 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007574 ret = ret * 10;
7575 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007576 ok = 1;
7577 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007578 temp = (double) tmp;
7579 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007580 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007581#else
7582 ret = 0;
7583 while ((CUR >= '0') && (CUR <= '9')) {
7584 ret = ret * 10 + (CUR - '0');
7585 ok = 1;
7586 NEXT;
7587 }
7588#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007589 if (CUR == '.') {
7590 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007591 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7592 XP_ERROR(XPATH_NUMBER_ERROR);
7593 }
7594 while ((CUR >= '0') && (CUR <= '9')) {
7595 mult /= 10;
7596 ret = ret + (CUR - '0') * mult;
7597 NEXT;
7598 }
Owen Taylor3473f882001-02-23 17:55:21 +00007599 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007600 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007601 NEXT;
7602 if (CUR == '-') {
7603 is_exponent_negative = 1;
7604 NEXT;
7605 }
7606 while ((CUR >= '0') && (CUR <= '9')) {
7607 exponent = exponent * 10 + (CUR - '0');
7608 NEXT;
7609 }
7610 if (is_exponent_negative)
7611 exponent = -exponent;
7612 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007613 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007614 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007615 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007616}
7617
7618/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007619 * xmlXPathParseLiteral:
7620 * @ctxt: the XPath Parser context
7621 *
7622 * Parse a Literal
7623 *
7624 * [29] Literal ::= '"' [^"]* '"'
7625 * | "'" [^']* "'"
7626 *
7627 * Returns the value found or NULL in case of error
7628 */
7629static xmlChar *
7630xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7631 const xmlChar *q;
7632 xmlChar *ret = NULL;
7633
7634 if (CUR == '"') {
7635 NEXT;
7636 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007637 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007638 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007639 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007640 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7641 } else {
7642 ret = xmlStrndup(q, CUR_PTR - q);
7643 NEXT;
7644 }
7645 } else if (CUR == '\'') {
7646 NEXT;
7647 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007648 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007649 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007650 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007651 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7652 } else {
7653 ret = xmlStrndup(q, CUR_PTR - q);
7654 NEXT;
7655 }
7656 } else {
7657 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7658 }
7659 return(ret);
7660}
7661
7662/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007663 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007664 * @ctxt: the XPath Parser context
7665 *
7666 * Parse a Literal and push it on the stack.
7667 *
7668 * [29] Literal ::= '"' [^"]* '"'
7669 * | "'" [^']* "'"
7670 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007671 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007672 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007673static void
7674xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007675 const xmlChar *q;
7676 xmlChar *ret = NULL;
7677
7678 if (CUR == '"') {
7679 NEXT;
7680 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007681 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007682 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007683 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007684 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7685 } else {
7686 ret = xmlStrndup(q, CUR_PTR - q);
7687 NEXT;
7688 }
7689 } else if (CUR == '\'') {
7690 NEXT;
7691 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007692 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007693 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007694 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007695 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7696 } else {
7697 ret = xmlStrndup(q, CUR_PTR - q);
7698 NEXT;
7699 }
7700 } else {
7701 XP_ERROR(XPATH_START_LITERAL_ERROR);
7702 }
7703 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007704 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7705 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007706 xmlFree(ret);
7707}
7708
7709/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007710 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007711 * @ctxt: the XPath Parser context
7712 *
7713 * Parse a VariableReference, evaluate it and push it on the stack.
7714 *
7715 * The variable bindings consist of a mapping from variable names
7716 * to variable values. The value of a variable is an object, which
7717 * of any of the types that are possible for the value of an expression,
7718 * and may also be of additional types not specified here.
7719 *
7720 * Early evaluation is possible since:
7721 * The variable bindings [...] used to evaluate a subexpression are
7722 * always the same as those used to evaluate the containing expression.
7723 *
7724 * [36] VariableReference ::= '$' QName
7725 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007726static void
7727xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007728 xmlChar *name;
7729 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007730
7731 SKIP_BLANKS;
7732 if (CUR != '$') {
7733 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7734 }
7735 NEXT;
7736 name = xmlXPathParseQName(ctxt, &prefix);
7737 if (name == NULL) {
7738 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7739 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007740 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007741 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7742 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007743 SKIP_BLANKS;
7744}
7745
7746/**
7747 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007748 * @name: a name string
7749 *
7750 * Is the name given a NodeType one.
7751 *
7752 * [38] NodeType ::= 'comment'
7753 * | 'text'
7754 * | 'processing-instruction'
7755 * | 'node'
7756 *
7757 * Returns 1 if true 0 otherwise
7758 */
7759int
7760xmlXPathIsNodeType(const xmlChar *name) {
7761 if (name == NULL)
7762 return(0);
7763
Daniel Veillard1971ee22002-01-31 20:29:19 +00007764 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007765 return(1);
7766 if (xmlStrEqual(name, BAD_CAST "text"))
7767 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007768 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007769 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007770 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007771 return(1);
7772 return(0);
7773}
7774
7775/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007776 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007777 * @ctxt: the XPath Parser context
7778 *
7779 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7780 * [17] Argument ::= Expr
7781 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007782 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007783 * pushed on the stack
7784 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007785static void
7786xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007787 xmlChar *name;
7788 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007789 int nbargs = 0;
7790
7791 name = xmlXPathParseQName(ctxt, &prefix);
7792 if (name == NULL) {
7793 XP_ERROR(XPATH_EXPR_ERROR);
7794 }
7795 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007796#ifdef DEBUG_EXPR
7797 if (prefix == NULL)
7798 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7799 name);
7800 else
7801 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7802 prefix, name);
7803#endif
7804
Owen Taylor3473f882001-02-23 17:55:21 +00007805 if (CUR != '(') {
7806 XP_ERROR(XPATH_EXPR_ERROR);
7807 }
7808 NEXT;
7809 SKIP_BLANKS;
7810
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007811 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007812 if (CUR != ')') {
7813 while (CUR != 0) {
7814 int op1 = ctxt->comp->last;
7815 ctxt->comp->last = -1;
7816 xmlXPathCompileExpr(ctxt);
7817 CHECK_ERROR;
7818 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7819 nbargs++;
7820 if (CUR == ')') break;
7821 if (CUR != ',') {
7822 XP_ERROR(XPATH_EXPR_ERROR);
7823 }
7824 NEXT;
7825 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007826 }
Owen Taylor3473f882001-02-23 17:55:21 +00007827 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007828 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7829 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007830 NEXT;
7831 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007832}
7833
7834/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007835 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007836 * @ctxt: the XPath Parser context
7837 *
7838 * [15] PrimaryExpr ::= VariableReference
7839 * | '(' Expr ')'
7840 * | Literal
7841 * | Number
7842 * | FunctionCall
7843 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007844 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007845 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007846static void
7847xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007848 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007849 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007850 else if (CUR == '(') {
7851 NEXT;
7852 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007853 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007854 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007855 if (CUR != ')') {
7856 XP_ERROR(XPATH_EXPR_ERROR);
7857 }
7858 NEXT;
7859 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007860 } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007861 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007862 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007863 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007864 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007865 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007866 }
7867 SKIP_BLANKS;
7868}
7869
7870/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007871 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007872 * @ctxt: the XPath Parser context
7873 *
7874 * [20] FilterExpr ::= PrimaryExpr
7875 * | FilterExpr Predicate
7876 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007877 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007878 * Square brackets are used to filter expressions in the same way that
7879 * they are used in location paths. It is an error if the expression to
7880 * be filtered does not evaluate to a node-set. The context node list
7881 * used for evaluating the expression in square brackets is the node-set
7882 * to be filtered listed in document order.
7883 */
7884
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007885static void
7886xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7887 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007888 CHECK_ERROR;
7889 SKIP_BLANKS;
7890
7891 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007892 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007893 SKIP_BLANKS;
7894 }
7895
7896
7897}
7898
7899/**
7900 * xmlXPathScanName:
7901 * @ctxt: the XPath Parser context
7902 *
7903 * Trickery: parse an XML name but without consuming the input flow
7904 * Needed to avoid insanity in the parser state.
7905 *
7906 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7907 * CombiningChar | Extender
7908 *
7909 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7910 *
7911 * [6] Names ::= Name (S Name)*
7912 *
7913 * Returns the Name parsed or NULL
7914 */
7915
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007916static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007917xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7918 xmlChar buf[XML_MAX_NAMELEN];
7919 int len = 0;
7920
7921 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007922 if (!IS_LETTER_CH(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00007923 (CUR != ':')) {
7924 return(NULL);
7925 }
7926
William M. Brack76e95df2003-10-18 16:20:14 +00007927 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007928 (NXT(len) == '.') || (NXT(len) == '-') ||
7929 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007930 (IS_COMBINING_CH(NXT(len))) ||
7931 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007932 buf[len] = NXT(len);
7933 len++;
7934 if (len >= XML_MAX_NAMELEN) {
7935 xmlGenericError(xmlGenericErrorContext,
7936 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brack76e95df2003-10-18 16:20:14 +00007937 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007938 (NXT(len) == '.') || (NXT(len) == '-') ||
7939 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007940 (IS_COMBINING_CH(NXT(len))) ||
7941 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00007942 len++;
7943 break;
7944 }
7945 }
7946 return(xmlStrndup(buf, len));
7947}
7948
7949/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007950 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007951 * @ctxt: the XPath Parser context
7952 *
7953 * [19] PathExpr ::= LocationPath
7954 * | FilterExpr
7955 * | FilterExpr '/' RelativeLocationPath
7956 * | FilterExpr '//' RelativeLocationPath
7957 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007958 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007959 * The / operator and // operators combine an arbitrary expression
7960 * and a relative location path. It is an error if the expression
7961 * does not evaluate to a node-set.
7962 * The / operator does composition in the same way as when / is
7963 * used in a location path. As in location paths, // is short for
7964 * /descendant-or-self::node()/.
7965 */
7966
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007967static void
7968xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007969 int lc = 1; /* Should we branch to LocationPath ? */
7970 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7971
7972 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007973 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
7974 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007975 lc = 0;
7976 } else if (CUR == '*') {
7977 /* relative or absolute location path */
7978 lc = 1;
7979 } else if (CUR == '/') {
7980 /* relative or absolute location path */
7981 lc = 1;
7982 } else if (CUR == '@') {
7983 /* relative abbreviated attribute location path */
7984 lc = 1;
7985 } else if (CUR == '.') {
7986 /* relative abbreviated attribute location path */
7987 lc = 1;
7988 } else {
7989 /*
7990 * Problem is finding if we have a name here whether it's:
7991 * - a nodetype
7992 * - a function call in which case it's followed by '('
7993 * - an axis in which case it's followed by ':'
7994 * - a element name
7995 * We do an a priori analysis here rather than having to
7996 * maintain parsed token content through the recursive function
7997 * calls. This looks uglier but makes the code quite easier to
7998 * read/write/debug.
7999 */
8000 SKIP_BLANKS;
8001 name = xmlXPathScanName(ctxt);
8002 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8003#ifdef DEBUG_STEP
8004 xmlGenericError(xmlGenericErrorContext,
8005 "PathExpr: Axis\n");
8006#endif
8007 lc = 1;
8008 xmlFree(name);
8009 } else if (name != NULL) {
8010 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008011
8012
8013 while (NXT(len) != 0) {
8014 if (NXT(len) == '/') {
8015 /* element name */
8016#ifdef DEBUG_STEP
8017 xmlGenericError(xmlGenericErrorContext,
8018 "PathExpr: AbbrRelLocation\n");
8019#endif
8020 lc = 1;
8021 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008022 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008023 /* ignore blanks */
8024 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008025 } else if (NXT(len) == ':') {
8026#ifdef DEBUG_STEP
8027 xmlGenericError(xmlGenericErrorContext,
8028 "PathExpr: AbbrRelLocation\n");
8029#endif
8030 lc = 1;
8031 break;
8032 } else if ((NXT(len) == '(')) {
8033 /* Note Type or Function */
8034 if (xmlXPathIsNodeType(name)) {
8035#ifdef DEBUG_STEP
8036 xmlGenericError(xmlGenericErrorContext,
8037 "PathExpr: Type search\n");
8038#endif
8039 lc = 1;
8040 } else {
8041#ifdef DEBUG_STEP
8042 xmlGenericError(xmlGenericErrorContext,
8043 "PathExpr: function call\n");
8044#endif
8045 lc = 0;
8046 }
8047 break;
8048 } else if ((NXT(len) == '[')) {
8049 /* element name */
8050#ifdef DEBUG_STEP
8051 xmlGenericError(xmlGenericErrorContext,
8052 "PathExpr: AbbrRelLocation\n");
8053#endif
8054 lc = 1;
8055 break;
8056 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8057 (NXT(len) == '=')) {
8058 lc = 1;
8059 break;
8060 } else {
8061 lc = 1;
8062 break;
8063 }
8064 len++;
8065 }
8066 if (NXT(len) == 0) {
8067#ifdef DEBUG_STEP
8068 xmlGenericError(xmlGenericErrorContext,
8069 "PathExpr: AbbrRelLocation\n");
8070#endif
8071 /* element name */
8072 lc = 1;
8073 }
8074 xmlFree(name);
8075 } else {
8076 /* make sure all cases are covered explicitely */
8077 XP_ERROR(XPATH_EXPR_ERROR);
8078 }
8079 }
8080
8081 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008082 if (CUR == '/') {
8083 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8084 } else {
8085 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008086 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008087 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008088 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008089 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008090 CHECK_ERROR;
8091 if ((CUR == '/') && (NXT(1) == '/')) {
8092 SKIP(2);
8093 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008094
8095 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8096 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8097 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8098
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008099 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008100 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008101 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008102 }
8103 }
8104 SKIP_BLANKS;
8105}
8106
8107/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008108 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008109 * @ctxt: the XPath Parser context
8110 *
8111 * [18] UnionExpr ::= PathExpr
8112 * | UnionExpr '|' PathExpr
8113 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008114 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008115 */
8116
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008117static void
8118xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8119 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008120 CHECK_ERROR;
8121 SKIP_BLANKS;
8122 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008123 int op1 = ctxt->comp->last;
8124 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008125
8126 NEXT;
8127 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008128 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008129
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008130 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8131
Owen Taylor3473f882001-02-23 17:55:21 +00008132 SKIP_BLANKS;
8133 }
Owen Taylor3473f882001-02-23 17:55:21 +00008134}
8135
8136/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008137 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008138 * @ctxt: the XPath Parser context
8139 *
8140 * [27] UnaryExpr ::= UnionExpr
8141 * | '-' UnaryExpr
8142 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008143 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008144 */
8145
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008146static void
8147xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008148 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008149 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008150
8151 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008152 while (CUR == '-') {
8153 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008154 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008155 NEXT;
8156 SKIP_BLANKS;
8157 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008158
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008159 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008160 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008161 if (found) {
8162 if (minus)
8163 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8164 else
8165 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008166 }
8167}
8168
8169/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008170 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008171 * @ctxt: the XPath Parser context
8172 *
8173 * [26] MultiplicativeExpr ::= UnaryExpr
8174 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8175 * | MultiplicativeExpr 'div' UnaryExpr
8176 * | MultiplicativeExpr 'mod' UnaryExpr
8177 * [34] MultiplyOperator ::= '*'
8178 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008179 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008180 */
8181
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008182static void
8183xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8184 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008185 CHECK_ERROR;
8186 SKIP_BLANKS;
8187 while ((CUR == '*') ||
8188 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8189 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8190 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008191 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008192
8193 if (CUR == '*') {
8194 op = 0;
8195 NEXT;
8196 } else if (CUR == 'd') {
8197 op = 1;
8198 SKIP(3);
8199 } else if (CUR == 'm') {
8200 op = 2;
8201 SKIP(3);
8202 }
8203 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008204 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008205 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008206 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008207 SKIP_BLANKS;
8208 }
8209}
8210
8211/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008212 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008213 * @ctxt: the XPath Parser context
8214 *
8215 * [25] AdditiveExpr ::= MultiplicativeExpr
8216 * | AdditiveExpr '+' MultiplicativeExpr
8217 * | AdditiveExpr '-' MultiplicativeExpr
8218 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008219 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008220 */
8221
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008222static void
8223xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008224
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008225 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008226 CHECK_ERROR;
8227 SKIP_BLANKS;
8228 while ((CUR == '+') || (CUR == '-')) {
8229 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008230 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008231
8232 if (CUR == '+') plus = 1;
8233 else plus = 0;
8234 NEXT;
8235 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008236 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008237 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008238 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008239 SKIP_BLANKS;
8240 }
8241}
8242
8243/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008244 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008245 * @ctxt: the XPath Parser context
8246 *
8247 * [24] RelationalExpr ::= AdditiveExpr
8248 * | RelationalExpr '<' AdditiveExpr
8249 * | RelationalExpr '>' AdditiveExpr
8250 * | RelationalExpr '<=' AdditiveExpr
8251 * | RelationalExpr '>=' AdditiveExpr
8252 *
8253 * A <= B > C is allowed ? Answer from James, yes with
8254 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8255 * which is basically what got implemented.
8256 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008257 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008258 * on the stack
8259 */
8260
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008261static void
8262xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8263 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008264 CHECK_ERROR;
8265 SKIP_BLANKS;
8266 while ((CUR == '<') ||
8267 (CUR == '>') ||
8268 ((CUR == '<') && (NXT(1) == '=')) ||
8269 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008270 int inf, strict;
8271 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008272
8273 if (CUR == '<') inf = 1;
8274 else inf = 0;
8275 if (NXT(1) == '=') strict = 0;
8276 else strict = 1;
8277 NEXT;
8278 if (!strict) NEXT;
8279 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008280 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008281 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008282 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008283 SKIP_BLANKS;
8284 }
8285}
8286
8287/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008288 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008289 * @ctxt: the XPath Parser context
8290 *
8291 * [23] EqualityExpr ::= RelationalExpr
8292 * | EqualityExpr '=' RelationalExpr
8293 * | EqualityExpr '!=' RelationalExpr
8294 *
8295 * A != B != C is allowed ? Answer from James, yes with
8296 * (RelationalExpr = RelationalExpr) = RelationalExpr
8297 * (RelationalExpr != RelationalExpr) != RelationalExpr
8298 * which is basically what got implemented.
8299 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008300 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008301 *
8302 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008303static void
8304xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8305 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008306 CHECK_ERROR;
8307 SKIP_BLANKS;
8308 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008309 int eq;
8310 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008311
8312 if (CUR == '=') eq = 1;
8313 else eq = 0;
8314 NEXT;
8315 if (!eq) NEXT;
8316 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008317 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008318 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008319 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008320 SKIP_BLANKS;
8321 }
8322}
8323
8324/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008325 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008326 * @ctxt: the XPath Parser context
8327 *
8328 * [22] AndExpr ::= EqualityExpr
8329 * | AndExpr 'and' EqualityExpr
8330 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008331 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008332 *
8333 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008334static void
8335xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8336 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008337 CHECK_ERROR;
8338 SKIP_BLANKS;
8339 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008340 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008341 SKIP(3);
8342 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008343 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008344 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008345 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008346 SKIP_BLANKS;
8347 }
8348}
8349
8350/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008351 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008352 * @ctxt: the XPath Parser context
8353 *
8354 * [14] Expr ::= OrExpr
8355 * [21] OrExpr ::= AndExpr
8356 * | OrExpr 'or' AndExpr
8357 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008358 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008359 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008360static void
8361xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8362 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008363 CHECK_ERROR;
8364 SKIP_BLANKS;
8365 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008366 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008367 SKIP(2);
8368 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008369 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008370 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008371 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8372 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008373 SKIP_BLANKS;
8374 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008375 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8376 /* more ops could be optimized too */
8377 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8378 }
Owen Taylor3473f882001-02-23 17:55:21 +00008379}
8380
8381/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008382 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008383 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008384 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008385 *
8386 * [8] Predicate ::= '[' PredicateExpr ']'
8387 * [9] PredicateExpr ::= Expr
8388 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008389 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008390 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008391static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008392xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008393 int op1 = ctxt->comp->last;
8394
8395 SKIP_BLANKS;
8396 if (CUR != '[') {
8397 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8398 }
8399 NEXT;
8400 SKIP_BLANKS;
8401
8402 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008403 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008404 CHECK_ERROR;
8405
8406 if (CUR != ']') {
8407 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8408 }
8409
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008410 if (filter)
8411 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8412 else
8413 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008414
8415 NEXT;
8416 SKIP_BLANKS;
8417}
8418
8419/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008420 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008421 * @ctxt: the XPath Parser context
8422 * @test: pointer to a xmlXPathTestVal
8423 * @type: pointer to a xmlXPathTypeVal
8424 * @prefix: placeholder for a possible name prefix
8425 *
8426 * [7] NodeTest ::= NameTest
8427 * | NodeType '(' ')'
8428 * | 'processing-instruction' '(' Literal ')'
8429 *
8430 * [37] NameTest ::= '*'
8431 * | NCName ':' '*'
8432 * | QName
8433 * [38] NodeType ::= 'comment'
8434 * | 'text'
8435 * | 'processing-instruction'
8436 * | 'node'
8437 *
8438 * Returns the name found and update @test, @type and @prefix appropriately
8439 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008440static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008441xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8442 xmlXPathTypeVal *type, const xmlChar **prefix,
8443 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008444 int blanks;
8445
8446 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8447 STRANGE;
8448 return(NULL);
8449 }
William M. Brack78637da2003-07-31 14:47:38 +00008450 *type = (xmlXPathTypeVal) 0;
8451 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008452 *prefix = NULL;
8453 SKIP_BLANKS;
8454
8455 if ((name == NULL) && (CUR == '*')) {
8456 /*
8457 * All elements
8458 */
8459 NEXT;
8460 *test = NODE_TEST_ALL;
8461 return(NULL);
8462 }
8463
8464 if (name == NULL)
8465 name = xmlXPathParseNCName(ctxt);
8466 if (name == NULL) {
8467 XP_ERROR0(XPATH_EXPR_ERROR);
8468 }
8469
William M. Brack76e95df2003-10-18 16:20:14 +00008470 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008471 SKIP_BLANKS;
8472 if (CUR == '(') {
8473 NEXT;
8474 /*
8475 * NodeType or PI search
8476 */
8477 if (xmlStrEqual(name, BAD_CAST "comment"))
8478 *type = NODE_TYPE_COMMENT;
8479 else if (xmlStrEqual(name, BAD_CAST "node"))
8480 *type = NODE_TYPE_NODE;
8481 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8482 *type = NODE_TYPE_PI;
8483 else if (xmlStrEqual(name, BAD_CAST "text"))
8484 *type = NODE_TYPE_TEXT;
8485 else {
8486 if (name != NULL)
8487 xmlFree(name);
8488 XP_ERROR0(XPATH_EXPR_ERROR);
8489 }
8490
8491 *test = NODE_TEST_TYPE;
8492
8493 SKIP_BLANKS;
8494 if (*type == NODE_TYPE_PI) {
8495 /*
8496 * Specific case: search a PI by name.
8497 */
Owen Taylor3473f882001-02-23 17:55:21 +00008498 if (name != NULL)
8499 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008500 name = NULL;
8501 if (CUR != ')') {
8502 name = xmlXPathParseLiteral(ctxt);
8503 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008504 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008505 SKIP_BLANKS;
8506 }
Owen Taylor3473f882001-02-23 17:55:21 +00008507 }
8508 if (CUR != ')') {
8509 if (name != NULL)
8510 xmlFree(name);
8511 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8512 }
8513 NEXT;
8514 return(name);
8515 }
8516 *test = NODE_TEST_NAME;
8517 if ((!blanks) && (CUR == ':')) {
8518 NEXT;
8519
8520 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008521 * Since currently the parser context don't have a
8522 * namespace list associated:
8523 * The namespace name for this prefix can be computed
8524 * only at evaluation time. The compilation is done
8525 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008526 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008527#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008528 *prefix = xmlXPathNsLookup(ctxt->context, name);
8529 if (name != NULL)
8530 xmlFree(name);
8531 if (*prefix == NULL) {
8532 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8533 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008534#else
8535 *prefix = name;
8536#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008537
8538 if (CUR == '*') {
8539 /*
8540 * All elements
8541 */
8542 NEXT;
8543 *test = NODE_TEST_ALL;
8544 return(NULL);
8545 }
8546
8547 name = xmlXPathParseNCName(ctxt);
8548 if (name == NULL) {
8549 XP_ERROR0(XPATH_EXPR_ERROR);
8550 }
8551 }
8552 return(name);
8553}
8554
8555/**
8556 * xmlXPathIsAxisName:
8557 * @name: a preparsed name token
8558 *
8559 * [6] AxisName ::= 'ancestor'
8560 * | 'ancestor-or-self'
8561 * | 'attribute'
8562 * | 'child'
8563 * | 'descendant'
8564 * | 'descendant-or-self'
8565 * | 'following'
8566 * | 'following-sibling'
8567 * | 'namespace'
8568 * | 'parent'
8569 * | 'preceding'
8570 * | 'preceding-sibling'
8571 * | 'self'
8572 *
8573 * Returns the axis or 0
8574 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008575static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008576xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008577 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008578 switch (name[0]) {
8579 case 'a':
8580 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8581 ret = AXIS_ANCESTOR;
8582 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8583 ret = AXIS_ANCESTOR_OR_SELF;
8584 if (xmlStrEqual(name, BAD_CAST "attribute"))
8585 ret = AXIS_ATTRIBUTE;
8586 break;
8587 case 'c':
8588 if (xmlStrEqual(name, BAD_CAST "child"))
8589 ret = AXIS_CHILD;
8590 break;
8591 case 'd':
8592 if (xmlStrEqual(name, BAD_CAST "descendant"))
8593 ret = AXIS_DESCENDANT;
8594 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8595 ret = AXIS_DESCENDANT_OR_SELF;
8596 break;
8597 case 'f':
8598 if (xmlStrEqual(name, BAD_CAST "following"))
8599 ret = AXIS_FOLLOWING;
8600 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8601 ret = AXIS_FOLLOWING_SIBLING;
8602 break;
8603 case 'n':
8604 if (xmlStrEqual(name, BAD_CAST "namespace"))
8605 ret = AXIS_NAMESPACE;
8606 break;
8607 case 'p':
8608 if (xmlStrEqual(name, BAD_CAST "parent"))
8609 ret = AXIS_PARENT;
8610 if (xmlStrEqual(name, BAD_CAST "preceding"))
8611 ret = AXIS_PRECEDING;
8612 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8613 ret = AXIS_PRECEDING_SIBLING;
8614 break;
8615 case 's':
8616 if (xmlStrEqual(name, BAD_CAST "self"))
8617 ret = AXIS_SELF;
8618 break;
8619 }
8620 return(ret);
8621}
8622
8623/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008624 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008625 * @ctxt: the XPath Parser context
8626 *
8627 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8628 * | AbbreviatedStep
8629 *
8630 * [12] AbbreviatedStep ::= '.' | '..'
8631 *
8632 * [5] AxisSpecifier ::= AxisName '::'
8633 * | AbbreviatedAxisSpecifier
8634 *
8635 * [13] AbbreviatedAxisSpecifier ::= '@'?
8636 *
8637 * Modified for XPtr range support as:
8638 *
8639 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8640 * | AbbreviatedStep
8641 * | 'range-to' '(' Expr ')' Predicate*
8642 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008643 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008644 * A location step of . is short for self::node(). This is
8645 * particularly useful in conjunction with //. For example, the
8646 * location path .//para is short for
8647 * self::node()/descendant-or-self::node()/child::para
8648 * and so will select all para descendant elements of the context
8649 * node.
8650 * Similarly, a location step of .. is short for parent::node().
8651 * For example, ../title is short for parent::node()/child::title
8652 * and so will select the title children of the parent of the context
8653 * node.
8654 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008655static void
8656xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008657#ifdef LIBXML_XPTR_ENABLED
8658 int rangeto = 0;
8659 int op2 = -1;
8660#endif
8661
Owen Taylor3473f882001-02-23 17:55:21 +00008662 SKIP_BLANKS;
8663 if ((CUR == '.') && (NXT(1) == '.')) {
8664 SKIP(2);
8665 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008666 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8667 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008668 } else if (CUR == '.') {
8669 NEXT;
8670 SKIP_BLANKS;
8671 } else {
8672 xmlChar *name = NULL;
8673 const xmlChar *prefix = NULL;
8674 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008675 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008676 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008677 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008678
8679 /*
8680 * The modification needed for XPointer change to the production
8681 */
8682#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008683 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008684 name = xmlXPathParseNCName(ctxt);
8685 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008686 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008687 xmlFree(name);
8688 SKIP_BLANKS;
8689 if (CUR != '(') {
8690 XP_ERROR(XPATH_EXPR_ERROR);
8691 }
8692 NEXT;
8693 SKIP_BLANKS;
8694
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008695 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008696 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008697 CHECK_ERROR;
8698
8699 SKIP_BLANKS;
8700 if (CUR != ')') {
8701 XP_ERROR(XPATH_EXPR_ERROR);
8702 }
8703 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008704 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008705 goto eval_predicates;
8706 }
8707 }
8708#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008709 if (CUR == '*') {
8710 axis = AXIS_CHILD;
8711 } else {
8712 if (name == NULL)
8713 name = xmlXPathParseNCName(ctxt);
8714 if (name != NULL) {
8715 axis = xmlXPathIsAxisName(name);
8716 if (axis != 0) {
8717 SKIP_BLANKS;
8718 if ((CUR == ':') && (NXT(1) == ':')) {
8719 SKIP(2);
8720 xmlFree(name);
8721 name = NULL;
8722 } else {
8723 /* an element name can conflict with an axis one :-\ */
8724 axis = AXIS_CHILD;
8725 }
Owen Taylor3473f882001-02-23 17:55:21 +00008726 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008727 axis = AXIS_CHILD;
8728 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008729 } else if (CUR == '@') {
8730 NEXT;
8731 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008732 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008733 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008734 }
Owen Taylor3473f882001-02-23 17:55:21 +00008735 }
8736
8737 CHECK_ERROR;
8738
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008739 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008740 if (test == 0)
8741 return;
8742
8743#ifdef DEBUG_STEP
8744 xmlGenericError(xmlGenericErrorContext,
8745 "Basis : computing new set\n");
8746#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008747
Owen Taylor3473f882001-02-23 17:55:21 +00008748#ifdef DEBUG_STEP
8749 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008750 if (ctxt->value == NULL)
8751 xmlGenericError(xmlGenericErrorContext, "no value\n");
8752 else if (ctxt->value->nodesetval == NULL)
8753 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8754 else
8755 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008756#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008757
8758eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008759 op1 = ctxt->comp->last;
8760 ctxt->comp->last = -1;
8761
Owen Taylor3473f882001-02-23 17:55:21 +00008762 SKIP_BLANKS;
8763 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008764 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008765 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008766
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008767#ifdef LIBXML_XPTR_ENABLED
8768 if (rangeto) {
8769 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8770 } else
8771#endif
8772 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8773 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008774
Owen Taylor3473f882001-02-23 17:55:21 +00008775 }
8776#ifdef DEBUG_STEP
8777 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008778 if (ctxt->value == NULL)
8779 xmlGenericError(xmlGenericErrorContext, "no value\n");
8780 else if (ctxt->value->nodesetval == NULL)
8781 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8782 else
8783 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8784 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008785#endif
8786}
8787
8788/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008789 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008790 * @ctxt: the XPath Parser context
8791 *
8792 * [3] RelativeLocationPath ::= Step
8793 * | RelativeLocationPath '/' Step
8794 * | AbbreviatedRelativeLocationPath
8795 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8796 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008797 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008798 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008799static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008800xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008801(xmlXPathParserContextPtr ctxt) {
8802 SKIP_BLANKS;
8803 if ((CUR == '/') && (NXT(1) == '/')) {
8804 SKIP(2);
8805 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008806 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8807 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008808 } else if (CUR == '/') {
8809 NEXT;
8810 SKIP_BLANKS;
8811 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008812 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008813 SKIP_BLANKS;
8814 while (CUR == '/') {
8815 if ((CUR == '/') && (NXT(1) == '/')) {
8816 SKIP(2);
8817 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008818 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008819 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008820 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008821 } else if (CUR == '/') {
8822 NEXT;
8823 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008824 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008825 }
8826 SKIP_BLANKS;
8827 }
8828}
8829
8830/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008831 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008832 * @ctxt: the XPath Parser context
8833 *
8834 * [1] LocationPath ::= RelativeLocationPath
8835 * | AbsoluteLocationPath
8836 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8837 * | AbbreviatedAbsoluteLocationPath
8838 * [10] AbbreviatedAbsoluteLocationPath ::=
8839 * '//' RelativeLocationPath
8840 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008841 * Compile a location path
8842 *
Owen Taylor3473f882001-02-23 17:55:21 +00008843 * // is short for /descendant-or-self::node()/. For example,
8844 * //para is short for /descendant-or-self::node()/child::para and
8845 * so will select any para element in the document (even a para element
8846 * that is a document element will be selected by //para since the
8847 * document element node is a child of the root node); div//para is
8848 * short for div/descendant-or-self::node()/child::para and so will
8849 * select all para descendants of div children.
8850 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008851static void
8852xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008853 SKIP_BLANKS;
8854 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008855 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008856 } else {
8857 while (CUR == '/') {
8858 if ((CUR == '/') && (NXT(1) == '/')) {
8859 SKIP(2);
8860 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008861 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8862 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008863 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008864 } else if (CUR == '/') {
8865 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008866 SKIP_BLANKS;
8867 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008868 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008869 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008870 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008871 }
8872 }
8873 }
8874}
8875
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008876/************************************************************************
8877 * *
8878 * XPath precompiled expression evaluation *
8879 * *
8880 ************************************************************************/
8881
Daniel Veillardf06307e2001-07-03 10:35:50 +00008882static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008883xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8884
8885/**
8886 * xmlXPathNodeCollectAndTest:
8887 * @ctxt: the XPath Parser context
8888 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008889 * @first: pointer to the first element in document order
8890 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008891 *
8892 * This is the function implementing a step: based on the current list
8893 * of nodes, it builds up a new list, looking at all nodes under that
8894 * axis and selecting them it also do the predicate filtering
8895 *
8896 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008897 *
8898 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008899 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008900static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008901xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 xmlXPathStepOpPtr op,
8903 xmlNodePtr * first, xmlNodePtr * last)
8904{
William M. Brack78637da2003-07-31 14:47:38 +00008905 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8906 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8907 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008908 const xmlChar *prefix = op->value4;
8909 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008910 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008911
8912#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008913 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008914#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008915 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008916 xmlNodeSetPtr ret, list;
8917 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008918 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008919 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008920 xmlNodePtr cur = NULL;
8921 xmlXPathObjectPtr obj;
8922 xmlNodeSetPtr nodelist;
8923 xmlNodePtr tmp;
8924
Daniel Veillardf06307e2001-07-03 10:35:50 +00008925 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926 obj = valuePop(ctxt);
8927 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008928 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008929 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008930 URI = xmlXPathNsLookup(ctxt->context, prefix);
8931 if (URI == NULL)
8932 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008933 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008934#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008935 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008936#endif
8937 switch (axis) {
8938 case AXIS_ANCESTOR:
8939#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008940 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008941#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008942 first = NULL;
8943 next = xmlXPathNextAncestor;
8944 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008945 case AXIS_ANCESTOR_OR_SELF:
8946#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008947 xmlGenericError(xmlGenericErrorContext,
8948 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008949#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008950 first = NULL;
8951 next = xmlXPathNextAncestorOrSelf;
8952 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008953 case AXIS_ATTRIBUTE:
8954#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008956#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008957 first = NULL;
8958 last = NULL;
8959 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008960 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008961 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008962 case AXIS_CHILD:
8963#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008964 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008965#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008966 last = NULL;
8967 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008968 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970 case AXIS_DESCENDANT:
8971#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974 last = NULL;
8975 next = xmlXPathNextDescendant;
8976 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977 case AXIS_DESCENDANT_OR_SELF:
8978#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008979 xmlGenericError(xmlGenericErrorContext,
8980 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008981#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982 last = NULL;
8983 next = xmlXPathNextDescendantOrSelf;
8984 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985 case AXIS_FOLLOWING:
8986#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008987 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008988#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008989 last = NULL;
8990 next = xmlXPathNextFollowing;
8991 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008992 case AXIS_FOLLOWING_SIBLING:
8993#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008994 xmlGenericError(xmlGenericErrorContext,
8995 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008996#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008997 last = NULL;
8998 next = xmlXPathNextFollowingSibling;
8999 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009000 case AXIS_NAMESPACE:
9001#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009002 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009003#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009004 first = NULL;
9005 last = NULL;
9006 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009007 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009008 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009009 case AXIS_PARENT:
9010#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009012#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009013 first = NULL;
9014 next = xmlXPathNextParent;
9015 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009016 case AXIS_PRECEDING:
9017#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009018 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009019#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009020 first = NULL;
9021 next = xmlXPathNextPrecedingInternal;
9022 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009023 case AXIS_PRECEDING_SIBLING:
9024#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009025 xmlGenericError(xmlGenericErrorContext,
9026 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009027#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 first = NULL;
9029 next = xmlXPathNextPrecedingSibling;
9030 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009031 case AXIS_SELF:
9032#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009033 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009034#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009035 first = NULL;
9036 last = NULL;
9037 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009038 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009039 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009040 }
9041 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009042 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009043
9044 nodelist = obj->nodesetval;
9045 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009046 xmlXPathFreeObject(obj);
9047 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9048 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009049 }
9050 addNode = xmlXPathNodeSetAddUnique;
9051 ret = NULL;
9052#ifdef DEBUG_STEP
9053 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009054 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009055 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009056 case NODE_TEST_NONE:
9057 xmlGenericError(xmlGenericErrorContext,
9058 " searching for none !!!\n");
9059 break;
9060 case NODE_TEST_TYPE:
9061 xmlGenericError(xmlGenericErrorContext,
9062 " searching for type %d\n", type);
9063 break;
9064 case NODE_TEST_PI:
9065 xmlGenericError(xmlGenericErrorContext,
9066 " searching for PI !!!\n");
9067 break;
9068 case NODE_TEST_ALL:
9069 xmlGenericError(xmlGenericErrorContext,
9070 " searching for *\n");
9071 break;
9072 case NODE_TEST_NS:
9073 xmlGenericError(xmlGenericErrorContext,
9074 " searching for namespace %s\n",
9075 prefix);
9076 break;
9077 case NODE_TEST_NAME:
9078 xmlGenericError(xmlGenericErrorContext,
9079 " searching for name %s\n", name);
9080 if (prefix != NULL)
9081 xmlGenericError(xmlGenericErrorContext,
9082 " with namespace %s\n", prefix);
9083 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009084 }
9085 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9086#endif
9087 /*
9088 * 2.3 Node Tests
9089 * - For the attribute axis, the principal node type is attribute.
9090 * - For the namespace axis, the principal node type is namespace.
9091 * - For other axes, the principal node type is element.
9092 *
9093 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009094 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009095 * select all element children of the context node
9096 */
9097 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009099 ctxt->context->node = nodelist->nodeTab[i];
9100
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 cur = NULL;
9102 list = xmlXPathNodeSetCreate(NULL);
9103 do {
9104 cur = next(ctxt, cur);
9105 if (cur == NULL)
9106 break;
9107 if ((first != NULL) && (*first == cur))
9108 break;
9109 if (((t % 256) == 0) &&
9110 (first != NULL) && (*first != NULL) &&
9111 (xmlXPathCmpNodes(*first, cur) >= 0))
9112 break;
9113 if ((last != NULL) && (*last == cur))
9114 break;
9115 if (((t % 256) == 0) &&
9116 (last != NULL) && (*last != NULL) &&
9117 (xmlXPathCmpNodes(cur, *last) >= 0))
9118 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009119 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009121 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9122#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009124 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009125 ctxt->context->node = tmp;
9126 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009127 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009128 if ((cur->type == type) ||
9129 ((type == NODE_TYPE_NODE) &&
9130 ((cur->type == XML_DOCUMENT_NODE) ||
9131 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9132 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009133 (cur->type == XML_NAMESPACE_DECL) ||
9134 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009135 (cur->type == XML_PI_NODE) ||
9136 (cur->type == XML_COMMENT_NODE) ||
9137 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009138 (cur->type == XML_TEXT_NODE))) ||
9139 ((type == NODE_TYPE_TEXT) &&
9140 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009141#ifdef DEBUG_STEP
9142 n++;
9143#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009144 addNode(list, cur);
9145 }
9146 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009147 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 if (cur->type == XML_PI_NODE) {
9149 if ((name != NULL) &&
9150 (!xmlStrEqual(name, cur->name)))
9151 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009152#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009153 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009154#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009155 addNode(list, cur);
9156 }
9157 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009158 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009159 if (axis == AXIS_ATTRIBUTE) {
9160 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009161#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009162 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009163#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009164 addNode(list, cur);
9165 }
9166 } else if (axis == AXIS_NAMESPACE) {
9167 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009168#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009169 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009170#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009171 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9172 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009173 }
9174 } else {
9175 if (cur->type == XML_ELEMENT_NODE) {
9176 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009177#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009178 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009179#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009180 addNode(list, cur);
9181 } else if ((cur->ns != NULL) &&
9182 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009183#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009184 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009185#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009186 addNode(list, cur);
9187 }
9188 }
9189 }
9190 break;
9191 case NODE_TEST_NS:{
9192 TODO;
9193 break;
9194 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009195 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009196 switch (cur->type) {
9197 case XML_ELEMENT_NODE:
9198 if (xmlStrEqual(name, cur->name)) {
9199 if (prefix == NULL) {
9200 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009201#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009202 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009203#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009204 addNode(list, cur);
9205 }
9206 } else {
9207 if ((cur->ns != NULL) &&
9208 (xmlStrEqual(URI,
9209 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009210#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009211 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009212#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009213 addNode(list, cur);
9214 }
9215 }
9216 }
9217 break;
9218 case XML_ATTRIBUTE_NODE:{
9219 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009220
Daniel Veillardf06307e2001-07-03 10:35:50 +00009221 if (xmlStrEqual(name, attr->name)) {
9222 if (prefix == NULL) {
9223 if ((attr->ns == NULL) ||
9224 (attr->ns->prefix == NULL)) {
9225#ifdef DEBUG_STEP
9226 n++;
9227#endif
9228 addNode(list,
9229 (xmlNodePtr) attr);
9230 }
9231 } else {
9232 if ((attr->ns != NULL) &&
9233 (xmlStrEqual(URI,
9234 attr->ns->
9235 href))) {
9236#ifdef DEBUG_STEP
9237 n++;
9238#endif
9239 addNode(list,
9240 (xmlNodePtr) attr);
9241 }
9242 }
9243 }
9244 break;
9245 }
9246 case XML_NAMESPACE_DECL:
9247 if (cur->type == XML_NAMESPACE_DECL) {
9248 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009249
Daniel Veillardf06307e2001-07-03 10:35:50 +00009250 if ((ns->prefix != NULL) && (name != NULL)
9251 && (xmlStrEqual(ns->prefix, name))) {
9252#ifdef DEBUG_STEP
9253 n++;
9254#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009255 xmlXPathNodeSetAddNs(list,
9256 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009257 }
9258 }
9259 break;
9260 default:
9261 break;
9262 }
9263 break;
9264 break;
9265 }
9266 } while (cur != NULL);
9267
9268 /*
9269 * If there is some predicate filtering do it now
9270 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009271 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009272 xmlXPathObjectPtr obj2;
9273
9274 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9275 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9276 CHECK_TYPE0(XPATH_NODESET);
9277 obj2 = valuePop(ctxt);
9278 list = obj2->nodesetval;
9279 obj2->nodesetval = NULL;
9280 xmlXPathFreeObject(obj2);
9281 }
9282 if (ret == NULL) {
9283 ret = list;
9284 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009285 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009286 xmlXPathFreeNodeSet(list);
9287 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009288 }
9289 ctxt->context->node = tmp;
9290#ifdef DEBUG_STEP
9291 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009292 "\nExamined %d nodes, found %d nodes at that step\n",
9293 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009294#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009295 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009296 if ((obj->boolval) && (obj->user != NULL)) {
9297 ctxt->value->boolval = 1;
9298 ctxt->value->user = obj->user;
9299 obj->user = NULL;
9300 obj->boolval = 0;
9301 }
9302 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009303 return(t);
9304}
9305
9306/**
9307 * xmlXPathNodeCollectAndTestNth:
9308 * @ctxt: the XPath Parser context
9309 * @op: the XPath precompiled step operation
9310 * @indx: the index to collect
9311 * @first: pointer to the first element in document order
9312 * @last: pointer to the last element in document order
9313 *
9314 * This is the function implementing a step: based on the current list
9315 * of nodes, it builds up a new list, looking at all nodes under that
9316 * axis and selecting them it also do the predicate filtering
9317 *
9318 * Pushes the new NodeSet resulting from the search.
9319 * Returns the number of node traversed
9320 */
9321static int
9322xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9323 xmlXPathStepOpPtr op, int indx,
9324 xmlNodePtr * first, xmlNodePtr * last)
9325{
William M. Brack78637da2003-07-31 14:47:38 +00009326 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9327 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9328 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009329 const xmlChar *prefix = op->value4;
9330 const xmlChar *name = op->value5;
9331 const xmlChar *URI = NULL;
9332 int n = 0, t = 0;
9333
9334 int i;
9335 xmlNodeSetPtr list;
9336 xmlXPathTraversalFunction next = NULL;
9337 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9338 xmlNodePtr cur = NULL;
9339 xmlXPathObjectPtr obj;
9340 xmlNodeSetPtr nodelist;
9341 xmlNodePtr tmp;
9342
9343 CHECK_TYPE0(XPATH_NODESET);
9344 obj = valuePop(ctxt);
9345 addNode = xmlXPathNodeSetAdd;
9346 if (prefix != NULL) {
9347 URI = xmlXPathNsLookup(ctxt->context, prefix);
9348 if (URI == NULL)
9349 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9350 }
9351#ifdef DEBUG_STEP_NTH
9352 xmlGenericError(xmlGenericErrorContext, "new step : ");
9353 if (first != NULL) {
9354 if (*first != NULL)
9355 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9356 (*first)->name);
9357 else
9358 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9359 }
9360 if (last != NULL) {
9361 if (*last != NULL)
9362 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9363 (*last)->name);
9364 else
9365 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9366 }
9367#endif
9368 switch (axis) {
9369 case AXIS_ANCESTOR:
9370#ifdef DEBUG_STEP_NTH
9371 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9372#endif
9373 first = NULL;
9374 next = xmlXPathNextAncestor;
9375 break;
9376 case AXIS_ANCESTOR_OR_SELF:
9377#ifdef DEBUG_STEP_NTH
9378 xmlGenericError(xmlGenericErrorContext,
9379 "axis 'ancestors-or-self' ");
9380#endif
9381 first = NULL;
9382 next = xmlXPathNextAncestorOrSelf;
9383 break;
9384 case AXIS_ATTRIBUTE:
9385#ifdef DEBUG_STEP_NTH
9386 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9387#endif
9388 first = NULL;
9389 last = NULL;
9390 next = xmlXPathNextAttribute;
9391 break;
9392 case AXIS_CHILD:
9393#ifdef DEBUG_STEP_NTH
9394 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9395#endif
9396 last = NULL;
9397 next = xmlXPathNextChild;
9398 break;
9399 case AXIS_DESCENDANT:
9400#ifdef DEBUG_STEP_NTH
9401 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9402#endif
9403 last = NULL;
9404 next = xmlXPathNextDescendant;
9405 break;
9406 case AXIS_DESCENDANT_OR_SELF:
9407#ifdef DEBUG_STEP_NTH
9408 xmlGenericError(xmlGenericErrorContext,
9409 "axis 'descendant-or-self' ");
9410#endif
9411 last = NULL;
9412 next = xmlXPathNextDescendantOrSelf;
9413 break;
9414 case AXIS_FOLLOWING:
9415#ifdef DEBUG_STEP_NTH
9416 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9417#endif
9418 last = NULL;
9419 next = xmlXPathNextFollowing;
9420 break;
9421 case AXIS_FOLLOWING_SIBLING:
9422#ifdef DEBUG_STEP_NTH
9423 xmlGenericError(xmlGenericErrorContext,
9424 "axis 'following-siblings' ");
9425#endif
9426 last = NULL;
9427 next = xmlXPathNextFollowingSibling;
9428 break;
9429 case AXIS_NAMESPACE:
9430#ifdef DEBUG_STEP_NTH
9431 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9432#endif
9433 last = NULL;
9434 first = NULL;
9435 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9436 break;
9437 case AXIS_PARENT:
9438#ifdef DEBUG_STEP_NTH
9439 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9440#endif
9441 first = NULL;
9442 next = xmlXPathNextParent;
9443 break;
9444 case AXIS_PRECEDING:
9445#ifdef DEBUG_STEP_NTH
9446 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9447#endif
9448 first = NULL;
9449 next = xmlXPathNextPrecedingInternal;
9450 break;
9451 case AXIS_PRECEDING_SIBLING:
9452#ifdef DEBUG_STEP_NTH
9453 xmlGenericError(xmlGenericErrorContext,
9454 "axis 'preceding-sibling' ");
9455#endif
9456 first = NULL;
9457 next = xmlXPathNextPrecedingSibling;
9458 break;
9459 case AXIS_SELF:
9460#ifdef DEBUG_STEP_NTH
9461 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9462#endif
9463 first = NULL;
9464 last = NULL;
9465 next = xmlXPathNextSelf;
9466 break;
9467 }
9468 if (next == NULL)
9469 return(0);
9470
9471 nodelist = obj->nodesetval;
9472 if (nodelist == NULL) {
9473 xmlXPathFreeObject(obj);
9474 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9475 return(0);
9476 }
9477 addNode = xmlXPathNodeSetAddUnique;
9478#ifdef DEBUG_STEP_NTH
9479 xmlGenericError(xmlGenericErrorContext,
9480 " context contains %d nodes\n", nodelist->nodeNr);
9481 switch (test) {
9482 case NODE_TEST_NONE:
9483 xmlGenericError(xmlGenericErrorContext,
9484 " searching for none !!!\n");
9485 break;
9486 case NODE_TEST_TYPE:
9487 xmlGenericError(xmlGenericErrorContext,
9488 " searching for type %d\n", type);
9489 break;
9490 case NODE_TEST_PI:
9491 xmlGenericError(xmlGenericErrorContext,
9492 " searching for PI !!!\n");
9493 break;
9494 case NODE_TEST_ALL:
9495 xmlGenericError(xmlGenericErrorContext,
9496 " searching for *\n");
9497 break;
9498 case NODE_TEST_NS:
9499 xmlGenericError(xmlGenericErrorContext,
9500 " searching for namespace %s\n",
9501 prefix);
9502 break;
9503 case NODE_TEST_NAME:
9504 xmlGenericError(xmlGenericErrorContext,
9505 " searching for name %s\n", name);
9506 if (prefix != NULL)
9507 xmlGenericError(xmlGenericErrorContext,
9508 " with namespace %s\n", prefix);
9509 break;
9510 }
9511 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9512#endif
9513 /*
9514 * 2.3 Node Tests
9515 * - For the attribute axis, the principal node type is attribute.
9516 * - For the namespace axis, the principal node type is namespace.
9517 * - For other axes, the principal node type is element.
9518 *
9519 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009520 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009521 * select all element children of the context node
9522 */
9523 tmp = ctxt->context->node;
9524 list = xmlXPathNodeSetCreate(NULL);
9525 for (i = 0; i < nodelist->nodeNr; i++) {
9526 ctxt->context->node = nodelist->nodeTab[i];
9527
9528 cur = NULL;
9529 n = 0;
9530 do {
9531 cur = next(ctxt, cur);
9532 if (cur == NULL)
9533 break;
9534 if ((first != NULL) && (*first == cur))
9535 break;
9536 if (((t % 256) == 0) &&
9537 (first != NULL) && (*first != NULL) &&
9538 (xmlXPathCmpNodes(*first, cur) >= 0))
9539 break;
9540 if ((last != NULL) && (*last == cur))
9541 break;
9542 if (((t % 256) == 0) &&
9543 (last != NULL) && (*last != NULL) &&
9544 (xmlXPathCmpNodes(cur, *last) >= 0))
9545 break;
9546 t++;
9547 switch (test) {
9548 case NODE_TEST_NONE:
9549 ctxt->context->node = tmp;
9550 STRANGE return(0);
9551 case NODE_TEST_TYPE:
9552 if ((cur->type == type) ||
9553 ((type == NODE_TYPE_NODE) &&
9554 ((cur->type == XML_DOCUMENT_NODE) ||
9555 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9556 (cur->type == XML_ELEMENT_NODE) ||
9557 (cur->type == XML_PI_NODE) ||
9558 (cur->type == XML_COMMENT_NODE) ||
9559 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009560 (cur->type == XML_TEXT_NODE))) ||
9561 ((type == NODE_TYPE_TEXT) &&
9562 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009563 n++;
9564 if (n == indx)
9565 addNode(list, cur);
9566 }
9567 break;
9568 case NODE_TEST_PI:
9569 if (cur->type == XML_PI_NODE) {
9570 if ((name != NULL) &&
9571 (!xmlStrEqual(name, cur->name)))
9572 break;
9573 n++;
9574 if (n == indx)
9575 addNode(list, cur);
9576 }
9577 break;
9578 case NODE_TEST_ALL:
9579 if (axis == AXIS_ATTRIBUTE) {
9580 if (cur->type == XML_ATTRIBUTE_NODE) {
9581 n++;
9582 if (n == indx)
9583 addNode(list, cur);
9584 }
9585 } else if (axis == AXIS_NAMESPACE) {
9586 if (cur->type == XML_NAMESPACE_DECL) {
9587 n++;
9588 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009589 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9590 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009591 }
9592 } else {
9593 if (cur->type == XML_ELEMENT_NODE) {
9594 if (prefix == NULL) {
9595 n++;
9596 if (n == indx)
9597 addNode(list, cur);
9598 } else if ((cur->ns != NULL) &&
9599 (xmlStrEqual(URI, cur->ns->href))) {
9600 n++;
9601 if (n == indx)
9602 addNode(list, cur);
9603 }
9604 }
9605 }
9606 break;
9607 case NODE_TEST_NS:{
9608 TODO;
9609 break;
9610 }
9611 case NODE_TEST_NAME:
9612 switch (cur->type) {
9613 case XML_ELEMENT_NODE:
9614 if (xmlStrEqual(name, cur->name)) {
9615 if (prefix == NULL) {
9616 if (cur->ns == NULL) {
9617 n++;
9618 if (n == indx)
9619 addNode(list, cur);
9620 }
9621 } else {
9622 if ((cur->ns != NULL) &&
9623 (xmlStrEqual(URI,
9624 cur->ns->href))) {
9625 n++;
9626 if (n == indx)
9627 addNode(list, cur);
9628 }
9629 }
9630 }
9631 break;
9632 case XML_ATTRIBUTE_NODE:{
9633 xmlAttrPtr attr = (xmlAttrPtr) cur;
9634
9635 if (xmlStrEqual(name, attr->name)) {
9636 if (prefix == NULL) {
9637 if ((attr->ns == NULL) ||
9638 (attr->ns->prefix == NULL)) {
9639 n++;
9640 if (n == indx)
9641 addNode(list, cur);
9642 }
9643 } else {
9644 if ((attr->ns != NULL) &&
9645 (xmlStrEqual(URI,
9646 attr->ns->
9647 href))) {
9648 n++;
9649 if (n == indx)
9650 addNode(list, cur);
9651 }
9652 }
9653 }
9654 break;
9655 }
9656 case XML_NAMESPACE_DECL:
9657 if (cur->type == XML_NAMESPACE_DECL) {
9658 xmlNsPtr ns = (xmlNsPtr) cur;
9659
9660 if ((ns->prefix != NULL) && (name != NULL)
9661 && (xmlStrEqual(ns->prefix, name))) {
9662 n++;
9663 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009664 xmlXPathNodeSetAddNs(list,
9665 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009666 }
9667 }
9668 break;
9669 default:
9670 break;
9671 }
9672 break;
9673 break;
9674 }
9675 } while (n < indx);
9676 }
9677 ctxt->context->node = tmp;
9678#ifdef DEBUG_STEP_NTH
9679 xmlGenericError(xmlGenericErrorContext,
9680 "\nExamined %d nodes, found %d nodes at that step\n",
9681 t, list->nodeNr);
9682#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009683 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009684 if ((obj->boolval) && (obj->user != NULL)) {
9685 ctxt->value->boolval = 1;
9686 ctxt->value->user = obj->user;
9687 obj->user = NULL;
9688 obj->boolval = 0;
9689 }
9690 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009691 return(t);
9692}
9693
9694/**
9695 * xmlXPathCompOpEvalFirst:
9696 * @ctxt: the XPath parser context with the compiled expression
9697 * @op: an XPath compiled operation
9698 * @first: the first elem found so far
9699 *
9700 * Evaluate the Precompiled XPath operation searching only the first
9701 * element in document order
9702 *
9703 * Returns the number of examined objects.
9704 */
9705static int
9706xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9707 xmlXPathStepOpPtr op, xmlNodePtr * first)
9708{
9709 int total = 0, cur;
9710 xmlXPathCompExprPtr comp;
9711 xmlXPathObjectPtr arg1, arg2;
9712
Daniel Veillard556c6682001-10-06 09:59:51 +00009713 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009714 comp = ctxt->comp;
9715 switch (op->op) {
9716 case XPATH_OP_END:
9717 return (0);
9718 case XPATH_OP_UNION:
9719 total =
9720 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9721 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009722 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009723 if ((ctxt->value != NULL)
9724 && (ctxt->value->type == XPATH_NODESET)
9725 && (ctxt->value->nodesetval != NULL)
9726 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9727 /*
9728 * limit tree traversing to first node in the result
9729 */
9730 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9731 *first = ctxt->value->nodesetval->nodeTab[0];
9732 }
9733 cur =
9734 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9735 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009736 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009737 CHECK_TYPE0(XPATH_NODESET);
9738 arg2 = valuePop(ctxt);
9739
9740 CHECK_TYPE0(XPATH_NODESET);
9741 arg1 = valuePop(ctxt);
9742
9743 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9744 arg2->nodesetval);
9745 valuePush(ctxt, arg1);
9746 xmlXPathFreeObject(arg2);
9747 /* optimizer */
9748 if (total > cur)
9749 xmlXPathCompSwap(op);
9750 return (total + cur);
9751 case XPATH_OP_ROOT:
9752 xmlXPathRoot(ctxt);
9753 return (0);
9754 case XPATH_OP_NODE:
9755 if (op->ch1 != -1)
9756 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009757 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009758 if (op->ch2 != -1)
9759 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009760 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009761 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9762 return (total);
9763 case XPATH_OP_RESET:
9764 if (op->ch1 != -1)
9765 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009766 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009767 if (op->ch2 != -1)
9768 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009769 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009770 ctxt->context->node = NULL;
9771 return (total);
9772 case XPATH_OP_COLLECT:{
9773 if (op->ch1 == -1)
9774 return (total);
9775
9776 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009777 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009778
9779 /*
9780 * Optimization for [n] selection where n is a number
9781 */
9782 if ((op->ch2 != -1) &&
9783 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9784 (comp->steps[op->ch2].ch1 == -1) &&
9785 (comp->steps[op->ch2].ch2 != -1) &&
9786 (comp->steps[comp->steps[op->ch2].ch2].op ==
9787 XPATH_OP_VALUE)) {
9788 xmlXPathObjectPtr val;
9789
9790 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9791 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9792 int indx = (int) val->floatval;
9793
9794 if (val->floatval == (float) indx) {
9795 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9796 first, NULL);
9797 return (total);
9798 }
9799 }
9800 }
9801 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9802 return (total);
9803 }
9804 case XPATH_OP_VALUE:
9805 valuePush(ctxt,
9806 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9807 return (0);
9808 case XPATH_OP_SORT:
9809 if (op->ch1 != -1)
9810 total +=
9811 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9812 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009813 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009814 if ((ctxt->value != NULL)
9815 && (ctxt->value->type == XPATH_NODESET)
9816 && (ctxt->value->nodesetval != NULL))
9817 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9818 return (total);
9819 default:
9820 return (xmlXPathCompOpEval(ctxt, op));
9821 }
9822}
9823
9824/**
9825 * xmlXPathCompOpEvalLast:
9826 * @ctxt: the XPath parser context with the compiled expression
9827 * @op: an XPath compiled operation
9828 * @last: the last elem found so far
9829 *
9830 * Evaluate the Precompiled XPath operation searching only the last
9831 * element in document order
9832 *
9833 * Returns the number of node traversed
9834 */
9835static int
9836xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9837 xmlNodePtr * last)
9838{
9839 int total = 0, cur;
9840 xmlXPathCompExprPtr comp;
9841 xmlXPathObjectPtr arg1, arg2;
9842
Daniel Veillard556c6682001-10-06 09:59:51 +00009843 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009844 comp = ctxt->comp;
9845 switch (op->op) {
9846 case XPATH_OP_END:
9847 return (0);
9848 case XPATH_OP_UNION:
9849 total =
9850 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009851 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009852 if ((ctxt->value != NULL)
9853 && (ctxt->value->type == XPATH_NODESET)
9854 && (ctxt->value->nodesetval != NULL)
9855 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9856 /*
9857 * limit tree traversing to first node in the result
9858 */
9859 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9860 *last =
9861 ctxt->value->nodesetval->nodeTab[ctxt->value->
9862 nodesetval->nodeNr -
9863 1];
9864 }
9865 cur =
9866 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009867 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009868 if ((ctxt->value != NULL)
9869 && (ctxt->value->type == XPATH_NODESET)
9870 && (ctxt->value->nodesetval != NULL)
9871 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9872 }
9873 CHECK_TYPE0(XPATH_NODESET);
9874 arg2 = valuePop(ctxt);
9875
9876 CHECK_TYPE0(XPATH_NODESET);
9877 arg1 = valuePop(ctxt);
9878
9879 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9880 arg2->nodesetval);
9881 valuePush(ctxt, arg1);
9882 xmlXPathFreeObject(arg2);
9883 /* optimizer */
9884 if (total > cur)
9885 xmlXPathCompSwap(op);
9886 return (total + cur);
9887 case XPATH_OP_ROOT:
9888 xmlXPathRoot(ctxt);
9889 return (0);
9890 case XPATH_OP_NODE:
9891 if (op->ch1 != -1)
9892 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009893 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009894 if (op->ch2 != -1)
9895 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009896 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009897 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9898 return (total);
9899 case XPATH_OP_RESET:
9900 if (op->ch1 != -1)
9901 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009902 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009903 if (op->ch2 != -1)
9904 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009905 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009906 ctxt->context->node = NULL;
9907 return (total);
9908 case XPATH_OP_COLLECT:{
9909 if (op->ch1 == -1)
9910 return (0);
9911
9912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009913 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009914
9915 /*
9916 * Optimization for [n] selection where n is a number
9917 */
9918 if ((op->ch2 != -1) &&
9919 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9920 (comp->steps[op->ch2].ch1 == -1) &&
9921 (comp->steps[op->ch2].ch2 != -1) &&
9922 (comp->steps[comp->steps[op->ch2].ch2].op ==
9923 XPATH_OP_VALUE)) {
9924 xmlXPathObjectPtr val;
9925
9926 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9927 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9928 int indx = (int) val->floatval;
9929
9930 if (val->floatval == (float) indx) {
9931 total +=
9932 xmlXPathNodeCollectAndTestNth(ctxt, op,
9933 indx, NULL,
9934 last);
9935 return (total);
9936 }
9937 }
9938 }
9939 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9940 return (total);
9941 }
9942 case XPATH_OP_VALUE:
9943 valuePush(ctxt,
9944 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9945 return (0);
9946 case XPATH_OP_SORT:
9947 if (op->ch1 != -1)
9948 total +=
9949 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9950 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009951 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009952 if ((ctxt->value != NULL)
9953 && (ctxt->value->type == XPATH_NODESET)
9954 && (ctxt->value->nodesetval != NULL))
9955 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9956 return (total);
9957 default:
9958 return (xmlXPathCompOpEval(ctxt, op));
9959 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009960}
9961
Owen Taylor3473f882001-02-23 17:55:21 +00009962/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009963 * xmlXPathCompOpEval:
9964 * @ctxt: the XPath parser context with the compiled expression
9965 * @op: an XPath compiled operation
9966 *
9967 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009968 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009969 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009970static int
9971xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9972{
9973 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009974 int equal, ret;
9975 xmlXPathCompExprPtr comp;
9976 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009977 xmlNodePtr bak;
9978 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009979 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009980 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009981
Daniel Veillard556c6682001-10-06 09:59:51 +00009982 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009983 comp = ctxt->comp;
9984 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009985 case XPATH_OP_END:
9986 return (0);
9987 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009988 bakd = ctxt->context->doc;
9989 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009990 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009991 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009992 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009993 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009994 xmlXPathBooleanFunction(ctxt, 1);
9995 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9996 return (total);
9997 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009998 ctxt->context->doc = bakd;
9999 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010000 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010001 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010002 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010003 if (ctxt->error) {
10004 xmlXPathFreeObject(arg2);
10005 return(0);
10006 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010007 xmlXPathBooleanFunction(ctxt, 1);
10008 arg1 = valuePop(ctxt);
10009 arg1->boolval &= arg2->boolval;
10010 valuePush(ctxt, arg1);
10011 xmlXPathFreeObject(arg2);
10012 return (total);
10013 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010014 bakd = ctxt->context->doc;
10015 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010016 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010017 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010018 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010019 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010020 xmlXPathBooleanFunction(ctxt, 1);
10021 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10022 return (total);
10023 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010024 ctxt->context->doc = bakd;
10025 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010026 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010027 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010028 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010029 if (ctxt->error) {
10030 xmlXPathFreeObject(arg2);
10031 return(0);
10032 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010033 xmlXPathBooleanFunction(ctxt, 1);
10034 arg1 = valuePop(ctxt);
10035 arg1->boolval |= arg2->boolval;
10036 valuePush(ctxt, arg1);
10037 xmlXPathFreeObject(arg2);
10038 return (total);
10039 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010040 bakd = ctxt->context->doc;
10041 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010042 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010043 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010044 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010045 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010046 ctxt->context->doc = bakd;
10047 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010048 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010049 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010050 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010051 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010052 if (op->value)
10053 equal = xmlXPathEqualValues(ctxt);
10054 else
10055 equal = xmlXPathNotEqualValues(ctxt);
10056 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010057 return (total);
10058 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010059 bakd = ctxt->context->doc;
10060 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010061 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010062 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010063 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010064 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010065 ctxt->context->doc = bakd;
10066 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010067 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010068 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010069 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010070 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010071 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10072 valuePush(ctxt, xmlXPathNewBoolean(ret));
10073 return (total);
10074 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010075 bakd = ctxt->context->doc;
10076 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010077 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010078 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010080 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010081 if (op->ch2 != -1) {
10082 ctxt->context->doc = bakd;
10083 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010084 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010085 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010086 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010087 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010088 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010089 if (op->value == 0)
10090 xmlXPathSubValues(ctxt);
10091 else if (op->value == 1)
10092 xmlXPathAddValues(ctxt);
10093 else if (op->value == 2)
10094 xmlXPathValueFlipSign(ctxt);
10095 else if (op->value == 3) {
10096 CAST_TO_NUMBER;
10097 CHECK_TYPE0(XPATH_NUMBER);
10098 }
10099 return (total);
10100 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010101 bakd = ctxt->context->doc;
10102 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010103 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010104 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010105 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010106 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010107 ctxt->context->doc = bakd;
10108 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010109 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010110 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010111 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010112 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010113 if (op->value == 0)
10114 xmlXPathMultValues(ctxt);
10115 else if (op->value == 1)
10116 xmlXPathDivValues(ctxt);
10117 else if (op->value == 2)
10118 xmlXPathModValues(ctxt);
10119 return (total);
10120 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010121 bakd = ctxt->context->doc;
10122 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010123 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010124 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010125 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010126 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010127 ctxt->context->doc = bakd;
10128 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010129 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010130 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010131 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010132 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010133 CHECK_TYPE0(XPATH_NODESET);
10134 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010135
Daniel Veillardf06307e2001-07-03 10:35:50 +000010136 CHECK_TYPE0(XPATH_NODESET);
10137 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010138
Daniel Veillardf06307e2001-07-03 10:35:50 +000010139 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10140 arg2->nodesetval);
10141 valuePush(ctxt, arg1);
10142 xmlXPathFreeObject(arg2);
10143 return (total);
10144 case XPATH_OP_ROOT:
10145 xmlXPathRoot(ctxt);
10146 return (total);
10147 case XPATH_OP_NODE:
10148 if (op->ch1 != -1)
10149 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010150 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010151 if (op->ch2 != -1)
10152 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010153 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010154 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10155 return (total);
10156 case XPATH_OP_RESET:
10157 if (op->ch1 != -1)
10158 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010159 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010160 if (op->ch2 != -1)
10161 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010162 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010163 ctxt->context->node = NULL;
10164 return (total);
10165 case XPATH_OP_COLLECT:{
10166 if (op->ch1 == -1)
10167 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010168
Daniel Veillardf06307e2001-07-03 10:35:50 +000010169 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010170 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010171
Daniel Veillardf06307e2001-07-03 10:35:50 +000010172 /*
10173 * Optimization for [n] selection where n is a number
10174 */
10175 if ((op->ch2 != -1) &&
10176 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10177 (comp->steps[op->ch2].ch1 == -1) &&
10178 (comp->steps[op->ch2].ch2 != -1) &&
10179 (comp->steps[comp->steps[op->ch2].ch2].op ==
10180 XPATH_OP_VALUE)) {
10181 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010182
Daniel Veillardf06307e2001-07-03 10:35:50 +000010183 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10184 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10185 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010186
Daniel Veillardf06307e2001-07-03 10:35:50 +000010187 if (val->floatval == (float) indx) {
10188 total +=
10189 xmlXPathNodeCollectAndTestNth(ctxt, op,
10190 indx, NULL,
10191 NULL);
10192 return (total);
10193 }
10194 }
10195 }
10196 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10197 return (total);
10198 }
10199 case XPATH_OP_VALUE:
10200 valuePush(ctxt,
10201 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10202 return (total);
10203 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010204 xmlXPathObjectPtr val;
10205
Daniel Veillardf06307e2001-07-03 10:35:50 +000010206 if (op->ch1 != -1)
10207 total +=
10208 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010209 if (op->value5 == NULL) {
10210 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10211 if (val == NULL) {
10212 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10213 return(0);
10214 }
10215 valuePush(ctxt, val);
10216 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010217 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010218
Daniel Veillardf06307e2001-07-03 10:35:50 +000010219 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10220 if (URI == NULL) {
10221 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010222 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010223 op->value4, op->value5);
10224 return (total);
10225 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010226 val = xmlXPathVariableLookupNS(ctxt->context,
10227 op->value4, URI);
10228 if (val == NULL) {
10229 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10230 return(0);
10231 }
10232 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010233 }
10234 return (total);
10235 }
10236 case XPATH_OP_FUNCTION:{
10237 xmlXPathFunction func;
10238 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010239 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010240
10241 if (op->ch1 != -1)
10242 total +=
10243 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010244 if (ctxt->valueNr < op->value) {
10245 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010246 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010247 ctxt->error = XPATH_INVALID_OPERAND;
10248 return (total);
10249 }
10250 for (i = 0; i < op->value; i++)
10251 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10252 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010253 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010254 ctxt->error = XPATH_INVALID_OPERAND;
10255 return (total);
10256 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010257 if (op->cache != NULL)
10258 func = (xmlXPathFunction) op->cache;
10259 else {
10260 const xmlChar *URI = NULL;
10261
10262 if (op->value5 == NULL)
10263 func =
10264 xmlXPathFunctionLookup(ctxt->context,
10265 op->value4);
10266 else {
10267 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10268 if (URI == NULL) {
10269 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010270 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010271 op->value4, op->value5);
10272 return (total);
10273 }
10274 func = xmlXPathFunctionLookupNS(ctxt->context,
10275 op->value4, URI);
10276 }
10277 if (func == NULL) {
10278 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010279 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010280 op->value4);
10281 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010282 }
10283 op->cache = (void *) func;
10284 op->cacheURI = (void *) URI;
10285 }
10286 oldFunc = ctxt->context->function;
10287 oldFuncURI = ctxt->context->functionURI;
10288 ctxt->context->function = op->value4;
10289 ctxt->context->functionURI = op->cacheURI;
10290 func(ctxt, op->value);
10291 ctxt->context->function = oldFunc;
10292 ctxt->context->functionURI = oldFuncURI;
10293 return (total);
10294 }
10295 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010296 bakd = ctxt->context->doc;
10297 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010298 if (op->ch1 != -1)
10299 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010300 ctxt->context->doc = bakd;
10301 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010302 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010303 if (op->ch2 != -1)
10304 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010305 ctxt->context->doc = bakd;
10306 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010307 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010308 return (total);
10309 case XPATH_OP_PREDICATE:
10310 case XPATH_OP_FILTER:{
10311 xmlXPathObjectPtr res;
10312 xmlXPathObjectPtr obj, tmp;
10313 xmlNodeSetPtr newset = NULL;
10314 xmlNodeSetPtr oldset;
10315 xmlNodePtr oldnode;
10316 int i;
10317
10318 /*
10319 * Optimization for ()[1] selection i.e. the first elem
10320 */
10321 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10322 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10323 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10324 xmlXPathObjectPtr val;
10325
10326 val = comp->steps[op->ch2].value4;
10327 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10328 (val->floatval == 1.0)) {
10329 xmlNodePtr first = NULL;
10330
10331 total +=
10332 xmlXPathCompOpEvalFirst(ctxt,
10333 &comp->steps[op->ch1],
10334 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010335 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010336 /*
10337 * The nodeset should be in document order,
10338 * Keep only the first value
10339 */
10340 if ((ctxt->value != NULL) &&
10341 (ctxt->value->type == XPATH_NODESET) &&
10342 (ctxt->value->nodesetval != NULL) &&
10343 (ctxt->value->nodesetval->nodeNr > 1))
10344 ctxt->value->nodesetval->nodeNr = 1;
10345 return (total);
10346 }
10347 }
10348 /*
10349 * Optimization for ()[last()] selection i.e. the last elem
10350 */
10351 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10352 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10353 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10354 int f = comp->steps[op->ch2].ch1;
10355
10356 if ((f != -1) &&
10357 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10358 (comp->steps[f].value5 == NULL) &&
10359 (comp->steps[f].value == 0) &&
10360 (comp->steps[f].value4 != NULL) &&
10361 (xmlStrEqual
10362 (comp->steps[f].value4, BAD_CAST "last"))) {
10363 xmlNodePtr last = NULL;
10364
10365 total +=
10366 xmlXPathCompOpEvalLast(ctxt,
10367 &comp->steps[op->ch1],
10368 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010369 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010370 /*
10371 * The nodeset should be in document order,
10372 * Keep only the last value
10373 */
10374 if ((ctxt->value != NULL) &&
10375 (ctxt->value->type == XPATH_NODESET) &&
10376 (ctxt->value->nodesetval != NULL) &&
10377 (ctxt->value->nodesetval->nodeTab != NULL) &&
10378 (ctxt->value->nodesetval->nodeNr > 1)) {
10379 ctxt->value->nodesetval->nodeTab[0] =
10380 ctxt->value->nodesetval->nodeTab[ctxt->
10381 value->
10382 nodesetval->
10383 nodeNr -
10384 1];
10385 ctxt->value->nodesetval->nodeNr = 1;
10386 }
10387 return (total);
10388 }
10389 }
10390
10391 if (op->ch1 != -1)
10392 total +=
10393 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010394 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010395 if (op->ch2 == -1)
10396 return (total);
10397 if (ctxt->value == NULL)
10398 return (total);
10399
10400 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010401
10402#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010403 /*
10404 * Hum are we filtering the result of an XPointer expression
10405 */
10406 if (ctxt->value->type == XPATH_LOCATIONSET) {
10407 xmlLocationSetPtr newlocset = NULL;
10408 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010409
Daniel Veillardf06307e2001-07-03 10:35:50 +000010410 /*
10411 * Extract the old locset, and then evaluate the result of the
10412 * expression for all the element in the locset. use it to grow
10413 * up a new locset.
10414 */
10415 CHECK_TYPE0(XPATH_LOCATIONSET);
10416 obj = valuePop(ctxt);
10417 oldlocset = obj->user;
10418 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010419
Daniel Veillardf06307e2001-07-03 10:35:50 +000010420 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10421 ctxt->context->contextSize = 0;
10422 ctxt->context->proximityPosition = 0;
10423 if (op->ch2 != -1)
10424 total +=
10425 xmlXPathCompOpEval(ctxt,
10426 &comp->steps[op->ch2]);
10427 res = valuePop(ctxt);
10428 if (res != NULL)
10429 xmlXPathFreeObject(res);
10430 valuePush(ctxt, obj);
10431 CHECK_ERROR0;
10432 return (total);
10433 }
10434 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010435
Daniel Veillardf06307e2001-07-03 10:35:50 +000010436 for (i = 0; i < oldlocset->locNr; i++) {
10437 /*
10438 * Run the evaluation with a node list made of a
10439 * single item in the nodelocset.
10440 */
10441 ctxt->context->node = oldlocset->locTab[i]->user;
10442 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10443 valuePush(ctxt, tmp);
10444 ctxt->context->contextSize = oldlocset->locNr;
10445 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010446
Daniel Veillardf06307e2001-07-03 10:35:50 +000010447 if (op->ch2 != -1)
10448 total +=
10449 xmlXPathCompOpEval(ctxt,
10450 &comp->steps[op->ch2]);
10451 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010452
Daniel Veillardf06307e2001-07-03 10:35:50 +000010453 /*
10454 * The result of the evaluation need to be tested to
10455 * decided whether the filter succeeded or not
10456 */
10457 res = valuePop(ctxt);
10458 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10459 xmlXPtrLocationSetAdd(newlocset,
10460 xmlXPathObjectCopy
10461 (oldlocset->locTab[i]));
10462 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010463
Daniel Veillardf06307e2001-07-03 10:35:50 +000010464 /*
10465 * Cleanup
10466 */
10467 if (res != NULL)
10468 xmlXPathFreeObject(res);
10469 if (ctxt->value == tmp) {
10470 res = valuePop(ctxt);
10471 xmlXPathFreeObject(res);
10472 }
10473
10474 ctxt->context->node = NULL;
10475 }
10476
10477 /*
10478 * The result is used as the new evaluation locset.
10479 */
10480 xmlXPathFreeObject(obj);
10481 ctxt->context->node = NULL;
10482 ctxt->context->contextSize = -1;
10483 ctxt->context->proximityPosition = -1;
10484 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10485 ctxt->context->node = oldnode;
10486 return (total);
10487 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010488#endif /* LIBXML_XPTR_ENABLED */
10489
Daniel Veillardf06307e2001-07-03 10:35:50 +000010490 /*
10491 * Extract the old set, and then evaluate the result of the
10492 * expression for all the element in the set. use it to grow
10493 * up a new set.
10494 */
10495 CHECK_TYPE0(XPATH_NODESET);
10496 obj = valuePop(ctxt);
10497 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010498
Daniel Veillardf06307e2001-07-03 10:35:50 +000010499 oldnode = ctxt->context->node;
10500 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010501
Daniel Veillardf06307e2001-07-03 10:35:50 +000010502 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10503 ctxt->context->contextSize = 0;
10504 ctxt->context->proximityPosition = 0;
10505 if (op->ch2 != -1)
10506 total +=
10507 xmlXPathCompOpEval(ctxt,
10508 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010509 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010510 res = valuePop(ctxt);
10511 if (res != NULL)
10512 xmlXPathFreeObject(res);
10513 valuePush(ctxt, obj);
10514 ctxt->context->node = oldnode;
10515 CHECK_ERROR0;
10516 } else {
10517 /*
10518 * Initialize the new set.
10519 */
10520 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010521
Daniel Veillardf06307e2001-07-03 10:35:50 +000010522 for (i = 0; i < oldset->nodeNr; i++) {
10523 /*
10524 * Run the evaluation with a node list made of
10525 * a single item in the nodeset.
10526 */
10527 ctxt->context->node = oldset->nodeTab[i];
10528 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10529 valuePush(ctxt, tmp);
10530 ctxt->context->contextSize = oldset->nodeNr;
10531 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010532
Daniel Veillardf06307e2001-07-03 10:35:50 +000010533 if (op->ch2 != -1)
10534 total +=
10535 xmlXPathCompOpEval(ctxt,
10536 &comp->steps[op->ch2]);
10537 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010538
Daniel Veillardf06307e2001-07-03 10:35:50 +000010539 /*
10540 * The result of the evaluation need to be tested to
10541 * decided whether the filter succeeded or not
10542 */
10543 res = valuePop(ctxt);
10544 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10545 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10546 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010547
Daniel Veillardf06307e2001-07-03 10:35:50 +000010548 /*
10549 * Cleanup
10550 */
10551 if (res != NULL)
10552 xmlXPathFreeObject(res);
10553 if (ctxt->value == tmp) {
10554 res = valuePop(ctxt);
10555 xmlXPathFreeObject(res);
10556 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010557
Daniel Veillardf06307e2001-07-03 10:35:50 +000010558 ctxt->context->node = NULL;
10559 }
10560
10561 /*
10562 * The result is used as the new evaluation set.
10563 */
10564 xmlXPathFreeObject(obj);
10565 ctxt->context->node = NULL;
10566 ctxt->context->contextSize = -1;
10567 ctxt->context->proximityPosition = -1;
10568 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10569 }
10570 ctxt->context->node = oldnode;
10571 return (total);
10572 }
10573 case XPATH_OP_SORT:
10574 if (op->ch1 != -1)
10575 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010576 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010577 if ((ctxt->value != NULL) &&
10578 (ctxt->value->type == XPATH_NODESET) &&
10579 (ctxt->value->nodesetval != NULL))
10580 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10581 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010582#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010583 case XPATH_OP_RANGETO:{
10584 xmlXPathObjectPtr range;
10585 xmlXPathObjectPtr res, obj;
10586 xmlXPathObjectPtr tmp;
10587 xmlLocationSetPtr newset = NULL;
10588 xmlNodeSetPtr oldset;
10589 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010590
Daniel Veillardf06307e2001-07-03 10:35:50 +000010591 if (op->ch1 != -1)
10592 total +=
10593 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10594 if (op->ch2 == -1)
10595 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010596
Daniel Veillardf06307e2001-07-03 10:35:50 +000010597 CHECK_TYPE0(XPATH_NODESET);
10598 obj = valuePop(ctxt);
10599 oldset = obj->nodesetval;
10600 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010601
Daniel Veillardf06307e2001-07-03 10:35:50 +000010602 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010603
Daniel Veillardf06307e2001-07-03 10:35:50 +000010604 if (oldset != NULL) {
10605 for (i = 0; i < oldset->nodeNr; i++) {
10606 /*
10607 * Run the evaluation with a node list made of a single item
10608 * in the nodeset.
10609 */
10610 ctxt->context->node = oldset->nodeTab[i];
10611 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10612 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010613
Daniel Veillardf06307e2001-07-03 10:35:50 +000010614 if (op->ch2 != -1)
10615 total +=
10616 xmlXPathCompOpEval(ctxt,
10617 &comp->steps[op->ch2]);
10618 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010619
Daniel Veillardf06307e2001-07-03 10:35:50 +000010620 /*
10621 * The result of the evaluation need to be tested to
10622 * decided whether the filter succeeded or not
10623 */
10624 res = valuePop(ctxt);
10625 range =
10626 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10627 res);
10628 if (range != NULL) {
10629 xmlXPtrLocationSetAdd(newset, range);
10630 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010631
Daniel Veillardf06307e2001-07-03 10:35:50 +000010632 /*
10633 * Cleanup
10634 */
10635 if (res != NULL)
10636 xmlXPathFreeObject(res);
10637 if (ctxt->value == tmp) {
10638 res = valuePop(ctxt);
10639 xmlXPathFreeObject(res);
10640 }
10641
10642 ctxt->context->node = NULL;
10643 }
10644 }
10645
10646 /*
10647 * The result is used as the new evaluation set.
10648 */
10649 xmlXPathFreeObject(obj);
10650 ctxt->context->node = NULL;
10651 ctxt->context->contextSize = -1;
10652 ctxt->context->proximityPosition = -1;
10653 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10654 return (total);
10655 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010656#endif /* LIBXML_XPTR_ENABLED */
10657 }
10658 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010659 "XPath: unknown precompiled operation %d\n", op->op);
10660 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010661}
10662
10663/**
10664 * xmlXPathRunEval:
10665 * @ctxt: the XPath parser context with the compiled expression
10666 *
10667 * Evaluate the Precompiled XPath expression in the given context.
10668 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010669static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010670xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10671 xmlXPathCompExprPtr comp;
10672
10673 if ((ctxt == NULL) || (ctxt->comp == NULL))
10674 return;
10675
10676 if (ctxt->valueTab == NULL) {
10677 /* Allocate the value stack */
10678 ctxt->valueTab = (xmlXPathObjectPtr *)
10679 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10680 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010681 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010682 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683 }
10684 ctxt->valueNr = 0;
10685 ctxt->valueMax = 10;
10686 ctxt->value = NULL;
10687 }
10688 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010689 if(comp->last < 0) {
10690 xmlGenericError(xmlGenericErrorContext,
10691 "xmlXPathRunEval: last is less than zero\n");
10692 return;
10693 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010694 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10695}
10696
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010697/************************************************************************
10698 * *
10699 * Public interfaces *
10700 * *
10701 ************************************************************************/
10702
10703/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010704 * xmlXPathEvalPredicate:
10705 * @ctxt: the XPath context
10706 * @res: the Predicate Expression evaluation result
10707 *
10708 * Evaluate a predicate result for the current node.
10709 * A PredicateExpr is evaluated by evaluating the Expr and converting
10710 * the result to a boolean. If the result is a number, the result will
10711 * be converted to true if the number is equal to the position of the
10712 * context node in the context node list (as returned by the position
10713 * function) and will be converted to false otherwise; if the result
10714 * is not a number, then the result will be converted as if by a call
10715 * to the boolean function.
10716 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010717 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010718 */
10719int
10720xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10721 if (res == NULL) return(0);
10722 switch (res->type) {
10723 case XPATH_BOOLEAN:
10724 return(res->boolval);
10725 case XPATH_NUMBER:
10726 return(res->floatval == ctxt->proximityPosition);
10727 case XPATH_NODESET:
10728 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010729 if (res->nodesetval == NULL)
10730 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010731 return(res->nodesetval->nodeNr != 0);
10732 case XPATH_STRING:
10733 return((res->stringval != NULL) &&
10734 (xmlStrlen(res->stringval) != 0));
10735 default:
10736 STRANGE
10737 }
10738 return(0);
10739}
10740
10741/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010742 * xmlXPathEvaluatePredicateResult:
10743 * @ctxt: the XPath Parser context
10744 * @res: the Predicate Expression evaluation result
10745 *
10746 * Evaluate a predicate result for the current node.
10747 * A PredicateExpr is evaluated by evaluating the Expr and converting
10748 * the result to a boolean. If the result is a number, the result will
10749 * be converted to true if the number is equal to the position of the
10750 * context node in the context node list (as returned by the position
10751 * function) and will be converted to false otherwise; if the result
10752 * is not a number, then the result will be converted as if by a call
10753 * to the boolean function.
10754 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010755 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010756 */
10757int
10758xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10759 xmlXPathObjectPtr res) {
10760 if (res == NULL) return(0);
10761 switch (res->type) {
10762 case XPATH_BOOLEAN:
10763 return(res->boolval);
10764 case XPATH_NUMBER:
10765 return(res->floatval == ctxt->context->proximityPosition);
10766 case XPATH_NODESET:
10767 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010768 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010769 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010770 return(res->nodesetval->nodeNr != 0);
10771 case XPATH_STRING:
10772 return((res->stringval != NULL) &&
10773 (xmlStrlen(res->stringval) != 0));
10774 default:
10775 STRANGE
10776 }
10777 return(0);
10778}
10779
10780/**
10781 * xmlXPathCompile:
10782 * @str: the XPath expression
10783 *
10784 * Compile an XPath expression
10785 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010786 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010787 * the caller has to free the object.
10788 */
10789xmlXPathCompExprPtr
10790xmlXPathCompile(const xmlChar *str) {
10791 xmlXPathParserContextPtr ctxt;
10792 xmlXPathCompExprPtr comp;
10793
10794 xmlXPathInit();
10795
10796 ctxt = xmlXPathNewParserContext(str, NULL);
10797 xmlXPathCompileExpr(ctxt);
Daniel Veillardae9733a2003-10-28 19:02:21 +000010798
10799 if( ctxt->error != XPATH_EXPRESSION_OK )
10800 {
10801 xmlXPathFreeParserContext(ctxt);
10802 return (0);
10803 }
10804
Daniel Veillard40af6492001-04-22 08:50:55 +000010805 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010806 /*
10807 * aleksey: in some cases this line prints *second* error message
10808 * (see bug #78858) and probably this should be fixed.
10809 * However, we are not sure that all error messages are printed
10810 * out in other places. It's not critical so we leave it as-is for now
10811 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010812 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10813 comp = NULL;
10814 } else {
10815 comp = ctxt->comp;
10816 ctxt->comp = NULL;
10817 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010818 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010819 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010820 comp->expr = xmlStrdup(str);
10821#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010822 comp->string = xmlStrdup(str);
10823 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010824#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010825 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010826 return(comp);
10827}
10828
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010829/**
10830 * xmlXPathCompiledEval:
10831 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010832 * @ctx: the XPath context
10833 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010834 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010835 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010836 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010837 * the caller has to free the object.
10838 */
10839xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010840xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010841 xmlXPathParserContextPtr ctxt;
10842 xmlXPathObjectPtr res, tmp, init = NULL;
10843 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010844#ifndef LIBXML_THREAD_ENABLED
10845 static int reentance = 0;
10846#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010847
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010848 if ((comp == NULL) || (ctx == NULL))
10849 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010850 xmlXPathInit();
10851
10852 CHECK_CONTEXT(ctx)
10853
Daniel Veillard81463942001-10-16 12:34:39 +000010854#ifndef LIBXML_THREAD_ENABLED
10855 reentance++;
10856 if (reentance > 1)
10857 xmlXPathDisableOptimizer = 1;
10858#endif
10859
Daniel Veillardf06307e2001-07-03 10:35:50 +000010860#ifdef DEBUG_EVAL_COUNTS
10861 comp->nb++;
10862 if ((comp->string != NULL) && (comp->nb > 100)) {
10863 fprintf(stderr, "100 x %s\n", comp->string);
10864 comp->nb = 0;
10865 }
10866#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010867 ctxt = xmlXPathCompParserContext(comp, ctx);
10868 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010869
10870 if (ctxt->value == NULL) {
10871 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010872 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010873 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010874 } else {
10875 res = valuePop(ctxt);
10876 }
10877
Daniel Veillardf06307e2001-07-03 10:35:50 +000010878
Owen Taylor3473f882001-02-23 17:55:21 +000010879 do {
10880 tmp = valuePop(ctxt);
10881 if (tmp != NULL) {
10882 if (tmp != init)
10883 stack++;
10884 xmlXPathFreeObject(tmp);
10885 }
10886 } while (tmp != NULL);
10887 if ((stack != 0) && (res != NULL)) {
10888 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010889 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010890 stack);
10891 }
10892 if (ctxt->error != XPATH_EXPRESSION_OK) {
10893 xmlXPathFreeObject(res);
10894 res = NULL;
10895 }
10896
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010897
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010898 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010899 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010900#ifndef LIBXML_THREAD_ENABLED
10901 reentance--;
10902#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010903 return(res);
10904}
10905
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010906/**
10907 * xmlXPathEvalExpr:
10908 * @ctxt: the XPath Parser context
10909 *
10910 * Parse and evaluate an XPath expression in the given context,
10911 * then push the result on the context stack
10912 */
10913void
10914xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10915 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010916 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010917 xmlXPathRunEval(ctxt);
10918}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010919
10920/**
10921 * xmlXPathEval:
10922 * @str: the XPath expression
10923 * @ctx: the XPath context
10924 *
10925 * Evaluate the XPath Location Path in the given context.
10926 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010927 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010928 * the caller has to free the object.
10929 */
10930xmlXPathObjectPtr
10931xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10932 xmlXPathParserContextPtr ctxt;
10933 xmlXPathObjectPtr res, tmp, init = NULL;
10934 int stack = 0;
10935
10936 xmlXPathInit();
10937
10938 CHECK_CONTEXT(ctx)
10939
10940 ctxt = xmlXPathNewParserContext(str, ctx);
10941 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010942
10943 if (ctxt->value == NULL) {
10944 xmlGenericError(xmlGenericErrorContext,
10945 "xmlXPathEval: evaluation failed\n");
10946 res = NULL;
10947 } else if (*ctxt->cur != 0) {
10948 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10949 res = NULL;
10950 } else {
10951 res = valuePop(ctxt);
10952 }
10953
10954 do {
10955 tmp = valuePop(ctxt);
10956 if (tmp != NULL) {
10957 if (tmp != init)
10958 stack++;
10959 xmlXPathFreeObject(tmp);
10960 }
10961 } while (tmp != NULL);
10962 if ((stack != 0) && (res != NULL)) {
10963 xmlGenericError(xmlGenericErrorContext,
10964 "xmlXPathEval: %d object left on the stack\n",
10965 stack);
10966 }
10967 if (ctxt->error != XPATH_EXPRESSION_OK) {
10968 xmlXPathFreeObject(res);
10969 res = NULL;
10970 }
10971
Owen Taylor3473f882001-02-23 17:55:21 +000010972 xmlXPathFreeParserContext(ctxt);
10973 return(res);
10974}
10975
10976/**
10977 * xmlXPathEvalExpression:
10978 * @str: the XPath expression
10979 * @ctxt: the XPath context
10980 *
10981 * Evaluate the XPath expression in the given context.
10982 *
10983 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10984 * the caller has to free the object.
10985 */
10986xmlXPathObjectPtr
10987xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10988 xmlXPathParserContextPtr pctxt;
10989 xmlXPathObjectPtr res, tmp;
10990 int stack = 0;
10991
10992 xmlXPathInit();
10993
10994 CHECK_CONTEXT(ctxt)
10995
10996 pctxt = xmlXPathNewParserContext(str, ctxt);
10997 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010998
10999 if (*pctxt->cur != 0) {
11000 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11001 res = NULL;
11002 } else {
11003 res = valuePop(pctxt);
11004 }
11005 do {
11006 tmp = valuePop(pctxt);
11007 if (tmp != NULL) {
11008 xmlXPathFreeObject(tmp);
11009 stack++;
11010 }
11011 } while (tmp != NULL);
11012 if ((stack != 0) && (res != NULL)) {
11013 xmlGenericError(xmlGenericErrorContext,
11014 "xmlXPathEvalExpression: %d object left on the stack\n",
11015 stack);
11016 }
11017 xmlXPathFreeParserContext(pctxt);
11018 return(res);
11019}
11020
Daniel Veillard42766c02002-08-22 20:52:17 +000011021/************************************************************************
11022 * *
11023 * Extra functions not pertaining to the XPath spec *
11024 * *
11025 ************************************************************************/
11026/**
11027 * xmlXPathEscapeUriFunction:
11028 * @ctxt: the XPath Parser context
11029 * @nargs: the number of arguments
11030 *
11031 * Implement the escape-uri() XPath function
11032 * string escape-uri(string $str, bool $escape-reserved)
11033 *
11034 * This function applies the URI escaping rules defined in section 2 of [RFC
11035 * 2396] to the string supplied as $uri-part, which typically represents all
11036 * or part of a URI. The effect of the function is to replace any special
11037 * character in the string by an escape sequence of the form %xx%yy...,
11038 * where xxyy... is the hexadecimal representation of the octets used to
11039 * represent the character in UTF-8.
11040 *
11041 * The set of characters that are escaped depends on the setting of the
11042 * boolean argument $escape-reserved.
11043 *
11044 * If $escape-reserved is true, all characters are escaped other than lower
11045 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11046 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11047 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11048 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11049 * A-F).
11050 *
11051 * If $escape-reserved is false, the behavior differs in that characters
11052 * referred to in [RFC 2396] as reserved characters are not escaped. These
11053 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11054 *
11055 * [RFC 2396] does not define whether escaped URIs should use lower case or
11056 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11057 * compared using string comparison functions, this function must always use
11058 * the upper-case letters A-F.
11059 *
11060 * Generally, $escape-reserved should be set to true when escaping a string
11061 * that is to form a single part of a URI, and to false when escaping an
11062 * entire URI or URI reference.
11063 *
11064 * In the case of non-ascii characters, the string is encoded according to
11065 * utf-8 and then converted according to RFC 2396.
11066 *
11067 * Examples
11068 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11069 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11070 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11071 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11072 *
11073 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011074static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011075xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11076 xmlXPathObjectPtr str;
11077 int escape_reserved;
11078 xmlBufferPtr target;
11079 xmlChar *cptr;
11080 xmlChar escape[4];
11081
11082 CHECK_ARITY(2);
11083
11084 escape_reserved = xmlXPathPopBoolean(ctxt);
11085
11086 CAST_TO_STRING;
11087 str = valuePop(ctxt);
11088
11089 target = xmlBufferCreate();
11090
11091 escape[0] = '%';
11092 escape[3] = 0;
11093
11094 if (target) {
11095 for (cptr = str->stringval; *cptr; cptr++) {
11096 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11097 (*cptr >= 'a' && *cptr <= 'z') ||
11098 (*cptr >= '0' && *cptr <= '9') ||
11099 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11100 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11101 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11102 (*cptr == '%' &&
11103 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11104 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11105 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11106 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11107 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11108 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11109 (!escape_reserved &&
11110 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11111 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11112 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11113 *cptr == ','))) {
11114 xmlBufferAdd(target, cptr, 1);
11115 } else {
11116 if ((*cptr >> 4) < 10)
11117 escape[1] = '0' + (*cptr >> 4);
11118 else
11119 escape[1] = 'A' - 10 + (*cptr >> 4);
11120 if ((*cptr & 0xF) < 10)
11121 escape[2] = '0' + (*cptr & 0xF);
11122 else
11123 escape[2] = 'A' - 10 + (*cptr & 0xF);
11124
11125 xmlBufferAdd(target, &escape[0], 3);
11126 }
11127 }
11128 }
11129 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11130 xmlBufferFree(target);
11131 xmlXPathFreeObject(str);
11132}
11133
Owen Taylor3473f882001-02-23 17:55:21 +000011134/**
11135 * xmlXPathRegisterAllFunctions:
11136 * @ctxt: the XPath context
11137 *
11138 * Registers all default XPath functions in this context
11139 */
11140void
11141xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11142{
11143 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11144 xmlXPathBooleanFunction);
11145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11146 xmlXPathCeilingFunction);
11147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11148 xmlXPathCountFunction);
11149 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11150 xmlXPathConcatFunction);
11151 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11152 xmlXPathContainsFunction);
11153 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11154 xmlXPathIdFunction);
11155 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11156 xmlXPathFalseFunction);
11157 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11158 xmlXPathFloorFunction);
11159 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11160 xmlXPathLastFunction);
11161 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11162 xmlXPathLangFunction);
11163 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11164 xmlXPathLocalNameFunction);
11165 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11166 xmlXPathNotFunction);
11167 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11168 xmlXPathNameFunction);
11169 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11170 xmlXPathNamespaceURIFunction);
11171 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11172 xmlXPathNormalizeFunction);
11173 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11174 xmlXPathNumberFunction);
11175 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11176 xmlXPathPositionFunction);
11177 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11178 xmlXPathRoundFunction);
11179 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11180 xmlXPathStringFunction);
11181 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11182 xmlXPathStringLengthFunction);
11183 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11184 xmlXPathStartsWithFunction);
11185 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11186 xmlXPathSubstringFunction);
11187 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11188 xmlXPathSubstringBeforeFunction);
11189 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11190 xmlXPathSubstringAfterFunction);
11191 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11192 xmlXPathSumFunction);
11193 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11194 xmlXPathTrueFunction);
11195 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11196 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011197
11198 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11199 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11200 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011201}
11202
11203#endif /* LIBXML_XPATH_ENABLED */