blob: 1284100fed7a0a4fe4ef46cb7ba084c7f2f2f2b1 [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{
274 if (ctxt != NULL)
275 ctxt->error = error;
276 if ((ctxt == NULL) || (ctxt->context == NULL)) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000277 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000278 NULL, NULL, XML_FROM_XPATH,
279 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
280 XML_ERR_ERROR, NULL, 0,
281 NULL, NULL, NULL, 0, 0,
282 xmlXPathErrorMessages[error]);
283 return;
284 }
285 ctxt->context->lastError.domain = XML_FROM_XPATH;
286 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
287 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000288 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000289 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
290 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
291 ctxt->context->lastError.node = ctxt->context->debugNode;
292 if (ctxt->context->error != NULL) {
293 ctxt->context->error(ctxt->context->userData,
294 &ctxt->context->lastError);
295 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000296 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000297 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
298 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
299 XML_ERR_ERROR, NULL, 0,
300 (const char *) ctxt->base, NULL, NULL,
301 ctxt->cur - ctxt->base, 0,
302 xmlXPathErrorMessages[error]);
303 }
304
305}
306
307/**
308 * xmlXPatherror:
309 * @ctxt: the XPath Parser context
310 * @file: the file name
311 * @line: the line number
312 * @no: the error number
313 *
314 * Formats an error message.
315 */
316void
317xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
318 int line ATTRIBUTE_UNUSED, int no) {
319 xmlXPathErr(ctxt, no);
320}
321
322
323/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000324 * *
325 * Parser Types *
326 * *
327 ************************************************************************/
328
329/*
330 * Types are private:
331 */
332
333typedef enum {
334 XPATH_OP_END=0,
335 XPATH_OP_AND,
336 XPATH_OP_OR,
337 XPATH_OP_EQUAL,
338 XPATH_OP_CMP,
339 XPATH_OP_PLUS,
340 XPATH_OP_MULT,
341 XPATH_OP_UNION,
342 XPATH_OP_ROOT,
343 XPATH_OP_NODE,
344 XPATH_OP_RESET,
345 XPATH_OP_COLLECT,
346 XPATH_OP_VALUE,
347 XPATH_OP_VARIABLE,
348 XPATH_OP_FUNCTION,
349 XPATH_OP_ARG,
350 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000351 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000352 XPATH_OP_SORT
353#ifdef LIBXML_XPTR_ENABLED
354 ,XPATH_OP_RANGETO
355#endif
356} xmlXPathOp;
357
358typedef enum {
359 AXIS_ANCESTOR = 1,
360 AXIS_ANCESTOR_OR_SELF,
361 AXIS_ATTRIBUTE,
362 AXIS_CHILD,
363 AXIS_DESCENDANT,
364 AXIS_DESCENDANT_OR_SELF,
365 AXIS_FOLLOWING,
366 AXIS_FOLLOWING_SIBLING,
367 AXIS_NAMESPACE,
368 AXIS_PARENT,
369 AXIS_PRECEDING,
370 AXIS_PRECEDING_SIBLING,
371 AXIS_SELF
372} xmlXPathAxisVal;
373
374typedef enum {
375 NODE_TEST_NONE = 0,
376 NODE_TEST_TYPE = 1,
377 NODE_TEST_PI = 2,
378 NODE_TEST_ALL = 3,
379 NODE_TEST_NS = 4,
380 NODE_TEST_NAME = 5
381} xmlXPathTestVal;
382
383typedef enum {
384 NODE_TYPE_NODE = 0,
385 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
386 NODE_TYPE_TEXT = XML_TEXT_NODE,
387 NODE_TYPE_PI = XML_PI_NODE
388} xmlXPathTypeVal;
389
390
391typedef struct _xmlXPathStepOp xmlXPathStepOp;
392typedef xmlXPathStepOp *xmlXPathStepOpPtr;
393struct _xmlXPathStepOp {
394 xmlXPathOp op;
395 int ch1;
396 int ch2;
397 int value;
398 int value2;
399 int value3;
400 void *value4;
401 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000402 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000403 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000404};
405
406struct _xmlXPathCompExpr {
407 int nbStep;
408 int maxStep;
409 xmlXPathStepOp *steps; /* ops for computation */
410 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000411 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000412#ifdef DEBUG_EVAL_COUNTS
413 int nb;
414 xmlChar *string;
415#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000416};
417
418/************************************************************************
419 * *
420 * Parser Type functions *
421 * *
422 ************************************************************************/
423
424/**
425 * xmlXPathNewCompExpr:
426 *
427 * Create a new Xpath component
428 *
429 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
430 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000431static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000432xmlXPathNewCompExpr(void) {
433 xmlXPathCompExprPtr cur;
434
435 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
436 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000437 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000438 return(NULL);
439 }
440 memset(cur, 0, sizeof(xmlXPathCompExpr));
441 cur->maxStep = 10;
442 cur->nbStep = 0;
443 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
444 sizeof(xmlXPathStepOp));
445 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000446 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000447 xmlFree(cur);
448 return(NULL);
449 }
450 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
451 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000452#ifdef DEBUG_EVAL_COUNTS
453 cur->nb = 0;
454#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000455 return(cur);
456}
457
458/**
459 * xmlXPathFreeCompExpr:
460 * @comp: an XPATH comp
461 *
462 * Free up the memory allocated by @comp
463 */
464void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000465xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
466{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000467 xmlXPathStepOpPtr op;
468 int i;
469
470 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000471 return;
472 for (i = 0; i < comp->nbStep; i++) {
473 op = &comp->steps[i];
474 if (op->value4 != NULL) {
475 if (op->op == XPATH_OP_VALUE)
476 xmlXPathFreeObject(op->value4);
477 else
478 xmlFree(op->value4);
479 }
480 if (op->value5 != NULL)
481 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000482 }
483 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000484 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000485 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000486#ifdef DEBUG_EVAL_COUNTS
487 if (comp->string != NULL) {
488 xmlFree(comp->string);
489 }
490#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000491 if (comp->expr != NULL) {
492 xmlFree(comp->expr);
493 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000494
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000495 xmlFree(comp);
496}
497
498/**
499 * xmlXPathCompExprAdd:
500 * @comp: the compiled expression
501 * @ch1: first child index
502 * @ch2: second child index
503 * @op: an op
504 * @value: the first int value
505 * @value2: the second int value
506 * @value3: the third int value
507 * @value4: the first string value
508 * @value5: the second string value
509 *
510 * Add an step to an XPath Compiled Expression
511 *
512 * Returns -1 in case of failure, the index otherwise
513 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000514static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000515xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
516 xmlXPathOp op, int value,
517 int value2, int value3, void *value4, void *value5) {
518 if (comp->nbStep >= comp->maxStep) {
519 xmlXPathStepOp *real;
520
521 comp->maxStep *= 2;
522 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
523 comp->maxStep * sizeof(xmlXPathStepOp));
524 if (real == NULL) {
525 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000526 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000527 return(-1);
528 }
529 comp->steps = real;
530 }
531 comp->last = comp->nbStep;
532 comp->steps[comp->nbStep].ch1 = ch1;
533 comp->steps[comp->nbStep].ch2 = ch2;
534 comp->steps[comp->nbStep].op = op;
535 comp->steps[comp->nbStep].value = value;
536 comp->steps[comp->nbStep].value2 = value2;
537 comp->steps[comp->nbStep].value3 = value3;
538 comp->steps[comp->nbStep].value4 = value4;
539 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000540 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000541 return(comp->nbStep++);
542}
543
Daniel Veillardf06307e2001-07-03 10:35:50 +0000544/**
545 * xmlXPathCompSwap:
546 * @comp: the compiled expression
547 * @op: operation index
548 *
549 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000550 */
551static void
552xmlXPathCompSwap(xmlXPathStepOpPtr op) {
553 int tmp;
554
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000555#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000556 /*
557 * Since this manipulates possibly shared variables, this is
558 * disable if one detects that the library is used in a multithreaded
559 * application
560 */
561 if (xmlXPathDisableOptimizer)
562 return;
563#endif
564
Daniel Veillardf06307e2001-07-03 10:35:50 +0000565 tmp = op->ch1;
566 op->ch1 = op->ch2;
567 op->ch2 = tmp;
568}
569
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000570#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
571 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
572 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000573#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
574 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
575 (op), (val), (val2), (val3), (val4), (val5))
576
577#define PUSH_LEAVE_EXPR(op, val, val2) \
578xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
579
580#define PUSH_UNARY_EXPR(op, ch, val, val2) \
581xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
582
583#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
584xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
585
586/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000587 * *
588 * Debugging related functions *
589 * *
590 ************************************************************************/
591
Owen Taylor3473f882001-02-23 17:55:21 +0000592#define STRANGE \
593 xmlGenericError(xmlGenericErrorContext, \
594 "Internal error at %s:%d\n", \
595 __FILE__, __LINE__);
596
597#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000598static void
599xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000600 int i;
601 char shift[100];
602
603 for (i = 0;((i < depth) && (i < 25));i++)
604 shift[2 * i] = shift[2 * i + 1] = ' ';
605 shift[2 * i] = shift[2 * i + 1] = 0;
606 if (cur == NULL) {
607 fprintf(output, shift);
608 fprintf(output, "Node is NULL !\n");
609 return;
610
611 }
612
613 if ((cur->type == XML_DOCUMENT_NODE) ||
614 (cur->type == XML_HTML_DOCUMENT_NODE)) {
615 fprintf(output, shift);
616 fprintf(output, " /\n");
617 } else if (cur->type == XML_ATTRIBUTE_NODE)
618 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
619 else
620 xmlDebugDumpOneNode(output, cur, depth);
621}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000622static void
623xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000624 xmlNodePtr tmp;
625 int i;
626 char shift[100];
627
628 for (i = 0;((i < depth) && (i < 25));i++)
629 shift[2 * i] = shift[2 * i + 1] = ' ';
630 shift[2 * i] = shift[2 * i + 1] = 0;
631 if (cur == NULL) {
632 fprintf(output, shift);
633 fprintf(output, "Node is NULL !\n");
634 return;
635
636 }
637
638 while (cur != NULL) {
639 tmp = cur;
640 cur = cur->next;
641 xmlDebugDumpOneNode(output, tmp, depth);
642 }
643}
Owen Taylor3473f882001-02-23 17:55:21 +0000644
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000645static void
646xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000647 int i;
648 char shift[100];
649
650 for (i = 0;((i < depth) && (i < 25));i++)
651 shift[2 * i] = shift[2 * i + 1] = ' ';
652 shift[2 * i] = shift[2 * i + 1] = 0;
653
654 if (cur == NULL) {
655 fprintf(output, shift);
656 fprintf(output, "NodeSet is NULL !\n");
657 return;
658
659 }
660
Daniel Veillard911f49a2001-04-07 15:39:35 +0000661 if (cur != NULL) {
662 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
663 for (i = 0;i < cur->nodeNr;i++) {
664 fprintf(output, shift);
665 fprintf(output, "%d", i + 1);
666 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
667 }
Owen Taylor3473f882001-02-23 17:55:21 +0000668 }
669}
670
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000671static void
672xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000673 int i;
674 char shift[100];
675
676 for (i = 0;((i < depth) && (i < 25));i++)
677 shift[2 * i] = shift[2 * i + 1] = ' ';
678 shift[2 * i] = shift[2 * i + 1] = 0;
679
680 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
681 fprintf(output, shift);
682 fprintf(output, "Value Tree is NULL !\n");
683 return;
684
685 }
686
687 fprintf(output, shift);
688 fprintf(output, "%d", i + 1);
689 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
690}
Owen Taylor3473f882001-02-23 17:55:21 +0000691#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000692static void
693xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000694 int i;
695 char shift[100];
696
697 for (i = 0;((i < depth) && (i < 25));i++)
698 shift[2 * i] = shift[2 * i + 1] = ' ';
699 shift[2 * i] = shift[2 * i + 1] = 0;
700
701 if (cur == NULL) {
702 fprintf(output, shift);
703 fprintf(output, "LocationSet is NULL !\n");
704 return;
705
706 }
707
708 for (i = 0;i < cur->locNr;i++) {
709 fprintf(output, shift);
710 fprintf(output, "%d : ", i + 1);
711 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
712 }
713}
Daniel Veillard017b1082001-06-21 11:20:21 +0000714#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000715
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000716/**
717 * xmlXPathDebugDumpObject:
718 * @output: the FILE * to dump the output
719 * @cur: the object to inspect
720 * @depth: indentation level
721 *
722 * Dump the content of the object for debugging purposes
723 */
724void
725xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000726 int i;
727 char shift[100];
728
729 for (i = 0;((i < depth) && (i < 25));i++)
730 shift[2 * i] = shift[2 * i + 1] = ' ';
731 shift[2 * i] = shift[2 * i + 1] = 0;
732
733 fprintf(output, shift);
734
735 if (cur == NULL) {
736 fprintf(output, "Object is empty (NULL)\n");
737 return;
738 }
739 switch(cur->type) {
740 case XPATH_UNDEFINED:
741 fprintf(output, "Object is uninitialized\n");
742 break;
743 case XPATH_NODESET:
744 fprintf(output, "Object is a Node Set :\n");
745 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
746 break;
747 case XPATH_XSLT_TREE:
748 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000749 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000750 break;
751 case XPATH_BOOLEAN:
752 fprintf(output, "Object is a Boolean : ");
753 if (cur->boolval) fprintf(output, "true\n");
754 else fprintf(output, "false\n");
755 break;
756 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000757 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000758 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000759 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000760 break;
761 case -1:
762 fprintf(output, "Object is a number : -Infinity\n");
763 break;
764 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000765 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000766 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000767 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
768 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000769 } else {
770 fprintf(output, "Object is a number : %0g\n", cur->floatval);
771 }
772 }
Owen Taylor3473f882001-02-23 17:55:21 +0000773 break;
774 case XPATH_STRING:
775 fprintf(output, "Object is a string : ");
776 xmlDebugDumpString(output, cur->stringval);
777 fprintf(output, "\n");
778 break;
779 case XPATH_POINT:
780 fprintf(output, "Object is a point : index %d in node", cur->index);
781 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
782 fprintf(output, "\n");
783 break;
784 case XPATH_RANGE:
785 if ((cur->user2 == NULL) ||
786 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
787 fprintf(output, "Object is a collapsed range :\n");
788 fprintf(output, shift);
789 if (cur->index >= 0)
790 fprintf(output, "index %d in ", cur->index);
791 fprintf(output, "node\n");
792 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
793 depth + 1);
794 } else {
795 fprintf(output, "Object is a range :\n");
796 fprintf(output, shift);
797 fprintf(output, "From ");
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 fprintf(output, shift);
804 fprintf(output, "To ");
805 if (cur->index2 >= 0)
806 fprintf(output, "index %d in ", cur->index2);
807 fprintf(output, "node\n");
808 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
809 depth + 1);
810 fprintf(output, "\n");
811 }
812 break;
813 case XPATH_LOCATIONSET:
814#if defined(LIBXML_XPTR_ENABLED)
815 fprintf(output, "Object is a Location Set:\n");
816 xmlXPathDebugDumpLocationSet(output,
817 (xmlLocationSetPtr) cur->user, depth);
818#endif
819 break;
820 case XPATH_USERS:
821 fprintf(output, "Object is user defined\n");
822 break;
823 }
824}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000825
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000826static void
827xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000828 xmlXPathStepOpPtr op, int depth) {
829 int i;
830 char shift[100];
831
832 for (i = 0;((i < depth) && (i < 25));i++)
833 shift[2 * i] = shift[2 * i + 1] = ' ';
834 shift[2 * i] = shift[2 * i + 1] = 0;
835
836 fprintf(output, shift);
837 if (op == NULL) {
838 fprintf(output, "Step is NULL\n");
839 return;
840 }
841 switch (op->op) {
842 case XPATH_OP_END:
843 fprintf(output, "END"); break;
844 case XPATH_OP_AND:
845 fprintf(output, "AND"); break;
846 case XPATH_OP_OR:
847 fprintf(output, "OR"); break;
848 case XPATH_OP_EQUAL:
849 if (op->value)
850 fprintf(output, "EQUAL =");
851 else
852 fprintf(output, "EQUAL !=");
853 break;
854 case XPATH_OP_CMP:
855 if (op->value)
856 fprintf(output, "CMP <");
857 else
858 fprintf(output, "CMP >");
859 if (!op->value2)
860 fprintf(output, "=");
861 break;
862 case XPATH_OP_PLUS:
863 if (op->value == 0)
864 fprintf(output, "PLUS -");
865 else if (op->value == 1)
866 fprintf(output, "PLUS +");
867 else if (op->value == 2)
868 fprintf(output, "PLUS unary -");
869 else if (op->value == 3)
870 fprintf(output, "PLUS unary - -");
871 break;
872 case XPATH_OP_MULT:
873 if (op->value == 0)
874 fprintf(output, "MULT *");
875 else if (op->value == 1)
876 fprintf(output, "MULT div");
877 else
878 fprintf(output, "MULT mod");
879 break;
880 case XPATH_OP_UNION:
881 fprintf(output, "UNION"); break;
882 case XPATH_OP_ROOT:
883 fprintf(output, "ROOT"); break;
884 case XPATH_OP_NODE:
885 fprintf(output, "NODE"); break;
886 case XPATH_OP_RESET:
887 fprintf(output, "RESET"); break;
888 case XPATH_OP_SORT:
889 fprintf(output, "SORT"); break;
890 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000891 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
892 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
893 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000894 const xmlChar *prefix = op->value4;
895 const xmlChar *name = op->value5;
896
897 fprintf(output, "COLLECT ");
898 switch (axis) {
899 case AXIS_ANCESTOR:
900 fprintf(output, " 'ancestors' "); break;
901 case AXIS_ANCESTOR_OR_SELF:
902 fprintf(output, " 'ancestors-or-self' "); break;
903 case AXIS_ATTRIBUTE:
904 fprintf(output, " 'attributes' "); break;
905 case AXIS_CHILD:
906 fprintf(output, " 'child' "); break;
907 case AXIS_DESCENDANT:
908 fprintf(output, " 'descendant' "); break;
909 case AXIS_DESCENDANT_OR_SELF:
910 fprintf(output, " 'descendant-or-self' "); break;
911 case AXIS_FOLLOWING:
912 fprintf(output, " 'following' "); break;
913 case AXIS_FOLLOWING_SIBLING:
914 fprintf(output, " 'following-siblings' "); break;
915 case AXIS_NAMESPACE:
916 fprintf(output, " 'namespace' "); break;
917 case AXIS_PARENT:
918 fprintf(output, " 'parent' "); break;
919 case AXIS_PRECEDING:
920 fprintf(output, " 'preceding' "); break;
921 case AXIS_PRECEDING_SIBLING:
922 fprintf(output, " 'preceding-sibling' "); break;
923 case AXIS_SELF:
924 fprintf(output, " 'self' "); break;
925 }
926 switch (test) {
927 case NODE_TEST_NONE:
928 fprintf(output, "'none' "); break;
929 case NODE_TEST_TYPE:
930 fprintf(output, "'type' "); break;
931 case NODE_TEST_PI:
932 fprintf(output, "'PI' "); break;
933 case NODE_TEST_ALL:
934 fprintf(output, "'all' "); break;
935 case NODE_TEST_NS:
936 fprintf(output, "'namespace' "); break;
937 case NODE_TEST_NAME:
938 fprintf(output, "'name' "); break;
939 }
940 switch (type) {
941 case NODE_TYPE_NODE:
942 fprintf(output, "'node' "); break;
943 case NODE_TYPE_COMMENT:
944 fprintf(output, "'comment' "); break;
945 case NODE_TYPE_TEXT:
946 fprintf(output, "'text' "); break;
947 case NODE_TYPE_PI:
948 fprintf(output, "'PI' "); break;
949 }
950 if (prefix != NULL)
951 fprintf(output, "%s:", prefix);
952 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000953 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000954 break;
955
956 }
957 case XPATH_OP_VALUE: {
958 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
959
960 fprintf(output, "ELEM ");
961 xmlXPathDebugDumpObject(output, object, 0);
962 goto finish;
963 }
964 case XPATH_OP_VARIABLE: {
965 const xmlChar *prefix = op->value5;
966 const xmlChar *name = op->value4;
967
968 if (prefix != NULL)
969 fprintf(output, "VARIABLE %s:%s", prefix, name);
970 else
971 fprintf(output, "VARIABLE %s", name);
972 break;
973 }
974 case XPATH_OP_FUNCTION: {
975 int nbargs = op->value;
976 const xmlChar *prefix = op->value5;
977 const xmlChar *name = op->value4;
978
979 if (prefix != NULL)
980 fprintf(output, "FUNCTION %s:%s(%d args)",
981 prefix, name, nbargs);
982 else
983 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
984 break;
985 }
986 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
987 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000988 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000989#ifdef LIBXML_XPTR_ENABLED
990 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
991#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000992 default:
993 fprintf(output, "UNKNOWN %d\n", op->op); return;
994 }
995 fprintf(output, "\n");
996finish:
997 if (op->ch1 >= 0)
998 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
999 if (op->ch2 >= 0)
1000 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1001}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001002
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001003/**
1004 * xmlXPathDebugDumpCompExpr:
1005 * @output: the FILE * for the output
1006 * @comp: the precompiled XPath expression
1007 * @depth: the indentation level.
1008 *
1009 * Dumps the tree of the compiled XPath expression.
1010 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001011void
1012xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1013 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001014 int i;
1015 char shift[100];
1016
1017 for (i = 0;((i < depth) && (i < 25));i++)
1018 shift[2 * i] = shift[2 * i + 1] = ' ';
1019 shift[2 * i] = shift[2 * i + 1] = 0;
1020
1021 fprintf(output, shift);
1022
1023 if (comp == NULL) {
1024 fprintf(output, "Compiled Expression is NULL\n");
1025 return;
1026 }
1027 fprintf(output, "Compiled Expression : %d elements\n",
1028 comp->nbStep);
1029 i = comp->last;
1030 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1031}
Daniel Veillard017b1082001-06-21 11:20:21 +00001032#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001033
1034/************************************************************************
1035 * *
1036 * Parser stacks related functions and macros *
1037 * *
1038 ************************************************************************/
1039
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001040/**
1041 * valuePop:
1042 * @ctxt: an XPath evaluation context
1043 *
1044 * Pops the top XPath object from the value stack
1045 *
1046 * Returns the XPath object just removed
1047 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001048extern xmlXPathObjectPtr
1049valuePop(xmlXPathParserContextPtr ctxt)
1050{
1051 xmlXPathObjectPtr ret;
1052
1053 if (ctxt->valueNr <= 0)
1054 return (0);
1055 ctxt->valueNr--;
1056 if (ctxt->valueNr > 0)
1057 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1058 else
1059 ctxt->value = NULL;
1060 ret = ctxt->valueTab[ctxt->valueNr];
1061 ctxt->valueTab[ctxt->valueNr] = 0;
1062 return (ret);
1063}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001064/**
1065 * valuePush:
1066 * @ctxt: an XPath evaluation context
1067 * @value: the XPath object
1068 *
1069 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001070 *
1071 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001072 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001073extern int
1074valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1075{
1076 if (ctxt->valueNr >= ctxt->valueMax) {
1077 ctxt->valueMax *= 2;
1078 ctxt->valueTab =
1079 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1080 ctxt->valueMax *
1081 sizeof(ctxt->valueTab[0]));
1082 if (ctxt->valueTab == NULL) {
1083 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1084 return (0);
1085 }
1086 }
1087 ctxt->valueTab[ctxt->valueNr] = value;
1088 ctxt->value = value;
1089 return (ctxt->valueNr++);
1090}
Owen Taylor3473f882001-02-23 17:55:21 +00001091
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001092/**
1093 * xmlXPathPopBoolean:
1094 * @ctxt: an XPath parser context
1095 *
1096 * Pops a boolean from the stack, handling conversion if needed.
1097 * Check error with #xmlXPathCheckError.
1098 *
1099 * Returns the boolean
1100 */
1101int
1102xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1103 xmlXPathObjectPtr obj;
1104 int ret;
1105
1106 obj = valuePop(ctxt);
1107 if (obj == NULL) {
1108 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1109 return(0);
1110 }
1111 ret = xmlXPathCastToBoolean(obj);
1112 xmlXPathFreeObject(obj);
1113 return(ret);
1114}
1115
1116/**
1117 * xmlXPathPopNumber:
1118 * @ctxt: an XPath parser context
1119 *
1120 * Pops a number from the stack, handling conversion if needed.
1121 * Check error with #xmlXPathCheckError.
1122 *
1123 * Returns the number
1124 */
1125double
1126xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1127 xmlXPathObjectPtr obj;
1128 double ret;
1129
1130 obj = valuePop(ctxt);
1131 if (obj == NULL) {
1132 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1133 return(0);
1134 }
1135 ret = xmlXPathCastToNumber(obj);
1136 xmlXPathFreeObject(obj);
1137 return(ret);
1138}
1139
1140/**
1141 * xmlXPathPopString:
1142 * @ctxt: an XPath parser context
1143 *
1144 * Pops a string from the stack, handling conversion if needed.
1145 * Check error with #xmlXPathCheckError.
1146 *
1147 * Returns the string
1148 */
1149xmlChar *
1150xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1151 xmlXPathObjectPtr obj;
1152 xmlChar * ret;
1153
1154 obj = valuePop(ctxt);
1155 if (obj == NULL) {
1156 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1157 return(NULL);
1158 }
1159 ret = xmlXPathCastToString(obj);
1160 /* TODO: needs refactoring somewhere else */
1161 if (obj->stringval == ret)
1162 obj->stringval = NULL;
1163 xmlXPathFreeObject(obj);
1164 return(ret);
1165}
1166
1167/**
1168 * xmlXPathPopNodeSet:
1169 * @ctxt: an XPath parser context
1170 *
1171 * Pops a node-set from the stack, handling conversion if needed.
1172 * Check error with #xmlXPathCheckError.
1173 *
1174 * Returns the node-set
1175 */
1176xmlNodeSetPtr
1177xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1178 xmlXPathObjectPtr obj;
1179 xmlNodeSetPtr ret;
1180
1181 if (ctxt->value == NULL) {
1182 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1183 return(NULL);
1184 }
1185 if (!xmlXPathStackIsNodeSet(ctxt)) {
1186 xmlXPathSetTypeError(ctxt);
1187 return(NULL);
1188 }
1189 obj = valuePop(ctxt);
1190 ret = obj->nodesetval;
Daniel Veillard9deb2422003-07-28 20:40:59 +00001191 /* to fix memory leak of not clearing obj->user */
1192 if (obj->boolval && obj->user != NULL)
1193 xmlFreeNodeList((xmlNodePtr) obj->user);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001194 xmlXPathFreeNodeSetList(obj);
1195 return(ret);
1196}
1197
1198/**
1199 * xmlXPathPopExternal:
1200 * @ctxt: an XPath parser context
1201 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001202 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001203 * Check error with #xmlXPathCheckError.
1204 *
1205 * Returns the object
1206 */
1207void *
1208xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1209 xmlXPathObjectPtr obj;
1210 void * ret;
1211
1212 if (ctxt->value == NULL) {
1213 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1214 return(NULL);
1215 }
1216 if (ctxt->value->type != XPATH_USERS) {
1217 xmlXPathSetTypeError(ctxt);
1218 return(NULL);
1219 }
1220 obj = valuePop(ctxt);
1221 ret = obj->user;
1222 xmlXPathFreeObject(obj);
1223 return(ret);
1224}
1225
Owen Taylor3473f882001-02-23 17:55:21 +00001226/*
1227 * Macros for accessing the content. Those should be used only by the parser,
1228 * and not exported.
1229 *
1230 * Dirty macros, i.e. one need to make assumption on the context to use them
1231 *
1232 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1233 * CUR returns the current xmlChar value, i.e. a 8 bit value
1234 * in ISO-Latin or UTF-8.
1235 * This should be used internally by the parser
1236 * only to compare to ASCII values otherwise it would break when
1237 * running with UTF-8 encoding.
1238 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1239 * to compare on ASCII based substring.
1240 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1241 * strings within the parser.
1242 * CURRENT Returns the current char value, with the full decoding of
1243 * UTF-8 if we are using this mode. It returns an int.
1244 * NEXT Skip to the next character, this does the proper decoding
1245 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1246 * It returns the pointer to the current xmlChar.
1247 */
1248
1249#define CUR (*ctxt->cur)
1250#define SKIP(val) ctxt->cur += (val)
1251#define NXT(val) ctxt->cur[(val)]
1252#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001253#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1254
1255#define COPY_BUF(l,b,i,v) \
1256 if (l == 1) b[i++] = (xmlChar) v; \
1257 else i += xmlCopyChar(l,&b[i],v)
1258
1259#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001260
1261#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001262 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001263
1264#define CURRENT (*ctxt->cur)
1265#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1266
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001267
1268#ifndef DBL_DIG
1269#define DBL_DIG 16
1270#endif
1271#ifndef DBL_EPSILON
1272#define DBL_EPSILON 1E-9
1273#endif
1274
1275#define UPPER_DOUBLE 1E9
1276#define LOWER_DOUBLE 1E-5
1277
1278#define INTEGER_DIGITS DBL_DIG
1279#define FRACTION_DIGITS (DBL_DIG + 1)
1280#define EXPONENT_DIGITS (3 + 2)
1281
1282/**
1283 * xmlXPathFormatNumber:
1284 * @number: number to format
1285 * @buffer: output buffer
1286 * @buffersize: size of output buffer
1287 *
1288 * Convert the number into a string representation.
1289 */
1290static void
1291xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1292{
Daniel Veillardcda96922001-08-21 10:56:31 +00001293 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001294 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001295 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001296 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001297 break;
1298 case -1:
1299 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001300 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001301 break;
1302 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001303 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001304 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001305 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001306 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001307 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001308 } else if (number == ((int) number)) {
1309 char work[30];
1310 char *ptr, *cur;
1311 int res, value = (int) number;
1312
1313 ptr = &buffer[0];
1314 if (value < 0) {
1315 *ptr++ = '-';
1316 value = -value;
1317 }
1318 if (value == 0) {
1319 *ptr++ = '0';
1320 } else {
1321 cur = &work[0];
1322 while (value != 0) {
1323 res = value % 10;
1324 value = value / 10;
1325 *cur++ = '0' + res;
1326 }
1327 cur--;
1328 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1329 *ptr++ = *cur--;
1330 }
1331 }
1332 if (ptr - buffer < buffersize) {
1333 *ptr = 0;
1334 } else if (buffersize > 0) {
1335 ptr--;
1336 *ptr = 0;
1337 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001338 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001339 /* 3 is sign, decimal point, and terminating zero */
1340 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1341 int integer_place, fraction_place;
1342 char *ptr;
1343 char *after_fraction;
1344 double absolute_value;
1345 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001346
Bjorn Reese70a9da52001-04-21 16:57:29 +00001347 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001348
Bjorn Reese70a9da52001-04-21 16:57:29 +00001349 /*
1350 * First choose format - scientific or regular floating point.
1351 * In either case, result is in work, and after_fraction points
1352 * just past the fractional part.
1353 */
1354 if ( ((absolute_value > UPPER_DOUBLE) ||
1355 (absolute_value < LOWER_DOUBLE)) &&
1356 (absolute_value != 0.0) ) {
1357 /* Use scientific notation */
1358 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1359 fraction_place = DBL_DIG - 1;
1360 snprintf(work, sizeof(work),"%*.*e",
1361 integer_place, fraction_place, number);
1362 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001363 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001364 else {
1365 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001366 if (absolute_value > 0.0)
1367 integer_place = 1 + (int)log10(absolute_value);
1368 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001369 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001370 fraction_place = (integer_place > 0)
1371 ? DBL_DIG - integer_place
1372 : DBL_DIG;
1373 size = snprintf(work, sizeof(work), "%0.*f",
1374 fraction_place, number);
1375 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001376 }
1377
Bjorn Reese70a9da52001-04-21 16:57:29 +00001378 /* Remove fractional trailing zeroes */
1379 ptr = after_fraction;
1380 while (*(--ptr) == '0')
1381 ;
1382 if (*ptr != '.')
1383 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001384 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001385
1386 /* Finally copy result back to caller */
1387 size = strlen(work) + 1;
1388 if (size > buffersize) {
1389 work[buffersize - 1] = 0;
1390 size = buffersize;
1391 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001392 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001393 }
1394 break;
1395 }
1396}
1397
Owen Taylor3473f882001-02-23 17:55:21 +00001398
1399/************************************************************************
1400 * *
1401 * Routines to handle NodeSets *
1402 * *
1403 ************************************************************************/
1404
1405/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001406 * xmlXPathOrderDocElems:
1407 * @doc: an input document
1408 *
1409 * Call this routine to speed up XPath computation on static documents.
1410 * This stamps all the element nodes with the document order
1411 * Like for line information, the order is kept in the element->content
1412 * field, the value stored is actually - the node number (startting at -1)
1413 * to be able to differenciate from line numbers.
1414 *
1415 * Returns the number of element found in the document or -1 in case
1416 * of error.
1417 */
1418long
1419xmlXPathOrderDocElems(xmlDocPtr doc) {
1420 long count = 0;
1421 xmlNodePtr cur;
1422
1423 if (doc == NULL)
1424 return(-1);
1425 cur = doc->children;
1426 while (cur != NULL) {
1427 if (cur->type == XML_ELEMENT_NODE) {
1428 cur->content = (void *) (-(++count));
1429 if (cur->children != NULL) {
1430 cur = cur->children;
1431 continue;
1432 }
1433 }
1434 if (cur->next != NULL) {
1435 cur = cur->next;
1436 continue;
1437 }
1438 do {
1439 cur = cur->parent;
1440 if (cur == NULL)
1441 break;
1442 if (cur == (xmlNodePtr) doc) {
1443 cur = NULL;
1444 break;
1445 }
1446 if (cur->next != NULL) {
1447 cur = cur->next;
1448 break;
1449 }
1450 } while (cur != NULL);
1451 }
1452 return(count);
1453}
1454
1455/**
Owen Taylor3473f882001-02-23 17:55:21 +00001456 * xmlXPathCmpNodes:
1457 * @node1: the first node
1458 * @node2: the second node
1459 *
1460 * Compare two nodes w.r.t document order
1461 *
1462 * Returns -2 in case of error 1 if first point < second point, 0 if
1463 * that's the same node, -1 otherwise
1464 */
1465int
1466xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1467 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001468 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001469 xmlNodePtr cur, root;
1470
1471 if ((node1 == NULL) || (node2 == NULL))
1472 return(-2);
1473 /*
1474 * a couple of optimizations which will avoid computations in most cases
1475 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001476 if (node1->type == XML_ATTRIBUTE_NODE) {
1477 attr1 = 1;
1478 node1 = node1->parent;
1479 }
1480 if (node2->type == XML_ATTRIBUTE_NODE) {
1481 attr2 = 1;
1482 node2 = node2->parent;
1483 }
1484 if (node1 == node2) {
1485 if (attr1 == attr2)
1486 return(0);
1487 if (attr2 == 1)
1488 return(1);
1489 return(-1);
1490 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001491 if ((node1->type == XML_NAMESPACE_DECL) ||
1492 (node2->type == XML_NAMESPACE_DECL))
1493 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001494 if (node1 == node2->prev)
1495 return(1);
1496 if (node1 == node2->next)
1497 return(-1);
1498
1499 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001500 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001501 */
1502 if ((node1->type == XML_ELEMENT_NODE) &&
1503 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001504 (0 > (long) node1->content) &&
1505 (0 > (long) node2->content) &&
1506 (node1->doc == node2->doc)) {
1507 long l1, l2;
1508
1509 l1 = -((long) node1->content);
1510 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001511 if (l1 < l2)
1512 return(1);
1513 if (l1 > l2)
1514 return(-1);
1515 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001516
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001517 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001518 * compute depth to root
1519 */
1520 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1521 if (cur == node1)
1522 return(1);
1523 depth2++;
1524 }
1525 root = cur;
1526 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1527 if (cur == node2)
1528 return(-1);
1529 depth1++;
1530 }
1531 /*
1532 * Distinct document (or distinct entities :-( ) case.
1533 */
1534 if (root != cur) {
1535 return(-2);
1536 }
1537 /*
1538 * get the nearest common ancestor.
1539 */
1540 while (depth1 > depth2) {
1541 depth1--;
1542 node1 = node1->parent;
1543 }
1544 while (depth2 > depth1) {
1545 depth2--;
1546 node2 = node2->parent;
1547 }
1548 while (node1->parent != node2->parent) {
1549 node1 = node1->parent;
1550 node2 = node2->parent;
1551 /* should not happen but just in case ... */
1552 if ((node1 == NULL) || (node2 == NULL))
1553 return(-2);
1554 }
1555 /*
1556 * Find who's first.
1557 */
1558 if (node1 == node2->next)
1559 return(-1);
1560 for (cur = node1->next;cur != NULL;cur = cur->next)
1561 if (cur == node2)
1562 return(1);
1563 return(-1); /* assume there is no sibling list corruption */
1564}
1565
1566/**
1567 * xmlXPathNodeSetSort:
1568 * @set: the node set
1569 *
1570 * Sort the node set in document order
1571 */
1572void
1573xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001574 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001575 xmlNodePtr tmp;
1576
1577 if (set == NULL)
1578 return;
1579
1580 /* Use Shell's sort to sort the node-set */
1581 len = set->nodeNr;
1582 for (incr = len / 2; incr > 0; incr /= 2) {
1583 for (i = incr; i < len; i++) {
1584 j = i - incr;
1585 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001586 if (xmlXPathCmpNodes(set->nodeTab[j],
1587 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001588 tmp = set->nodeTab[j];
1589 set->nodeTab[j] = set->nodeTab[j + incr];
1590 set->nodeTab[j + incr] = tmp;
1591 j -= incr;
1592 } else
1593 break;
1594 }
1595 }
1596 }
1597}
1598
1599#define XML_NODESET_DEFAULT 10
1600/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001601 * xmlXPathNodeSetDupNs:
1602 * @node: the parent node of the namespace XPath node
1603 * @ns: the libxml namespace declaration node.
1604 *
1605 * Namespace node in libxml don't match the XPath semantic. In a node set
1606 * the namespace nodes are duplicated and the next pointer is set to the
1607 * parent node in the XPath semantic.
1608 *
1609 * Returns the newly created object.
1610 */
1611static xmlNodePtr
1612xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1613 xmlNsPtr cur;
1614
1615 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1616 return(NULL);
1617 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1618 return((xmlNodePtr) ns);
1619
1620 /*
1621 * Allocate a new Namespace and fill the fields.
1622 */
1623 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1624 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001625 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001626 return(NULL);
1627 }
1628 memset(cur, 0, sizeof(xmlNs));
1629 cur->type = XML_NAMESPACE_DECL;
1630 if (ns->href != NULL)
1631 cur->href = xmlStrdup(ns->href);
1632 if (ns->prefix != NULL)
1633 cur->prefix = xmlStrdup(ns->prefix);
1634 cur->next = (xmlNsPtr) node;
1635 return((xmlNodePtr) cur);
1636}
1637
1638/**
1639 * xmlXPathNodeSetFreeNs:
1640 * @ns: the XPath namespace node found in a nodeset.
1641 *
1642 * Namespace node in libxml don't match the XPath semantic. In a node set
1643 * the namespace nodes are duplicated and the next pointer is set to the
1644 * parent node in the XPath semantic. Check if such a node need to be freed
1645 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001646void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001647xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1648 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1649 return;
1650
1651 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1652 if (ns->href != NULL)
1653 xmlFree((xmlChar *)ns->href);
1654 if (ns->prefix != NULL)
1655 xmlFree((xmlChar *)ns->prefix);
1656 xmlFree(ns);
1657 }
1658}
1659
1660/**
Owen Taylor3473f882001-02-23 17:55:21 +00001661 * xmlXPathNodeSetCreate:
1662 * @val: an initial xmlNodePtr, or NULL
1663 *
1664 * Create a new xmlNodeSetPtr of type double and of value @val
1665 *
1666 * Returns the newly created object.
1667 */
1668xmlNodeSetPtr
1669xmlXPathNodeSetCreate(xmlNodePtr val) {
1670 xmlNodeSetPtr ret;
1671
1672 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1673 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001674 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001675 return(NULL);
1676 }
1677 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1678 if (val != NULL) {
1679 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1680 sizeof(xmlNodePtr));
1681 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001682 xmlXPathErrMemory(NULL, "creating nodeset\n");
1683 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001684 return(NULL);
1685 }
1686 memset(ret->nodeTab, 0 ,
1687 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1688 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001689 if (val->type == XML_NAMESPACE_DECL) {
1690 xmlNsPtr ns = (xmlNsPtr) val;
1691
1692 ret->nodeTab[ret->nodeNr++] =
1693 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1694 } else
1695 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001696 }
1697 return(ret);
1698}
1699
1700/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001701 * xmlXPathNodeSetContains:
1702 * @cur: the node-set
1703 * @val: the node
1704 *
1705 * checks whether @cur contains @val
1706 *
1707 * Returns true (1) if @cur contains @val, false (0) otherwise
1708 */
1709int
1710xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1711 int i;
1712
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001713 if (val->type == XML_NAMESPACE_DECL) {
1714 for (i = 0; i < cur->nodeNr; i++) {
1715 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1716 xmlNsPtr ns1, ns2;
1717
1718 ns1 = (xmlNsPtr) val;
1719 ns2 = (xmlNsPtr) cur->nodeTab[i];
1720 if (ns1 == ns2)
1721 return(1);
1722 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1723 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1724 return(1);
1725 }
1726 }
1727 } else {
1728 for (i = 0; i < cur->nodeNr; i++) {
1729 if (cur->nodeTab[i] == val)
1730 return(1);
1731 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001732 }
1733 return(0);
1734}
1735
1736/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001737 * xmlXPathNodeSetAddNs:
1738 * @cur: the initial node set
1739 * @node: the hosting node
1740 * @ns: a the namespace node
1741 *
1742 * add a new namespace node to an existing NodeSet
1743 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001744void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001745xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1746 int i;
1747
1748 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1749 (node->type != XML_ELEMENT_NODE))
1750 return;
1751
1752 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1753 /*
1754 * check against doublons
1755 */
1756 for (i = 0;i < cur->nodeNr;i++) {
1757 if ((cur->nodeTab[i] != NULL) &&
1758 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001759 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001760 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1761 return;
1762 }
1763
1764 /*
1765 * grow the nodeTab if needed
1766 */
1767 if (cur->nodeMax == 0) {
1768 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1769 sizeof(xmlNodePtr));
1770 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001771 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001772 return;
1773 }
1774 memset(cur->nodeTab, 0 ,
1775 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1776 cur->nodeMax = XML_NODESET_DEFAULT;
1777 } else if (cur->nodeNr == cur->nodeMax) {
1778 xmlNodePtr *temp;
1779
1780 cur->nodeMax *= 2;
1781 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1782 sizeof(xmlNodePtr));
1783 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001784 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001785 return;
1786 }
1787 cur->nodeTab = temp;
1788 }
1789 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1790}
1791
1792/**
Owen Taylor3473f882001-02-23 17:55:21 +00001793 * xmlXPathNodeSetAdd:
1794 * @cur: the initial node set
1795 * @val: a new xmlNodePtr
1796 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001797 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001798 */
1799void
1800xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1801 int i;
1802
1803 if (val == NULL) return;
1804
Daniel Veillardef0b4502003-03-24 13:57:34 +00001805#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001806 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1807 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001808#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001809
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001810 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001811 /*
1812 * check against doublons
1813 */
1814 for (i = 0;i < cur->nodeNr;i++)
1815 if (cur->nodeTab[i] == val) return;
1816
1817 /*
1818 * grow the nodeTab if needed
1819 */
1820 if (cur->nodeMax == 0) {
1821 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1822 sizeof(xmlNodePtr));
1823 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001824 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001825 return;
1826 }
1827 memset(cur->nodeTab, 0 ,
1828 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1829 cur->nodeMax = XML_NODESET_DEFAULT;
1830 } else if (cur->nodeNr == cur->nodeMax) {
1831 xmlNodePtr *temp;
1832
1833 cur->nodeMax *= 2;
1834 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1835 sizeof(xmlNodePtr));
1836 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001837 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001838 return;
1839 }
1840 cur->nodeTab = temp;
1841 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001842 if (val->type == XML_NAMESPACE_DECL) {
1843 xmlNsPtr ns = (xmlNsPtr) val;
1844
1845 cur->nodeTab[cur->nodeNr++] =
1846 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1847 } else
1848 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001849}
1850
1851/**
1852 * xmlXPathNodeSetAddUnique:
1853 * @cur: the initial node set
1854 * @val: a new xmlNodePtr
1855 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001856 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001857 * when we are sure the node is not already in the set.
1858 */
1859void
1860xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1861 if (val == NULL) return;
1862
Daniel Veillardef0b4502003-03-24 13:57:34 +00001863#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001864 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1865 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001866#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001867
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001868 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001869 /*
1870 * grow the nodeTab if needed
1871 */
1872 if (cur->nodeMax == 0) {
1873 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1874 sizeof(xmlNodePtr));
1875 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001876 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001877 return;
1878 }
1879 memset(cur->nodeTab, 0 ,
1880 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1881 cur->nodeMax = XML_NODESET_DEFAULT;
1882 } else if (cur->nodeNr == cur->nodeMax) {
1883 xmlNodePtr *temp;
1884
1885 cur->nodeMax *= 2;
1886 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1887 sizeof(xmlNodePtr));
1888 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001889 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001890 return;
1891 }
1892 cur->nodeTab = temp;
1893 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001894 if (val->type == XML_NAMESPACE_DECL) {
1895 xmlNsPtr ns = (xmlNsPtr) val;
1896
1897 cur->nodeTab[cur->nodeNr++] =
1898 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1899 } else
1900 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001901}
1902
1903/**
1904 * xmlXPathNodeSetMerge:
1905 * @val1: the first NodeSet or NULL
1906 * @val2: the second NodeSet
1907 *
1908 * Merges two nodesets, all nodes from @val2 are added to @val1
1909 * if @val1 is NULL, a new set is created and copied from @val2
1910 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001911 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001912 */
1913xmlNodeSetPtr
1914xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001915 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001916
1917 if (val2 == NULL) return(val1);
1918 if (val1 == NULL) {
1919 val1 = xmlXPathNodeSetCreate(NULL);
1920 }
1921
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001922 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001923 initNr = val1->nodeNr;
1924
1925 for (i = 0;i < val2->nodeNr;i++) {
1926 /*
1927 * check against doublons
1928 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001929 skip = 0;
1930 for (j = 0; j < initNr; j++) {
1931 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1932 skip = 1;
1933 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001934 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1935 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1936 xmlNsPtr ns1, ns2;
1937 ns1 = (xmlNsPtr) val1->nodeTab[j];
1938 ns2 = (xmlNsPtr) val2->nodeTab[i];
1939 if ((ns1->next == ns2->next) &&
1940 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1941 skip = 1;
1942 break;
1943 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001944 }
1945 }
1946 if (skip)
1947 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001948
1949 /*
1950 * grow the nodeTab if needed
1951 */
1952 if (val1->nodeMax == 0) {
1953 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1954 sizeof(xmlNodePtr));
1955 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001956 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001957 return(NULL);
1958 }
1959 memset(val1->nodeTab, 0 ,
1960 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1961 val1->nodeMax = XML_NODESET_DEFAULT;
1962 } else if (val1->nodeNr == val1->nodeMax) {
1963 xmlNodePtr *temp;
1964
1965 val1->nodeMax *= 2;
1966 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1967 sizeof(xmlNodePtr));
1968 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001969 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001970 return(NULL);
1971 }
1972 val1->nodeTab = temp;
1973 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001974 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1975 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1976
1977 val1->nodeTab[val1->nodeNr++] =
1978 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1979 } else
1980 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001981 }
1982
1983 return(val1);
1984}
1985
1986/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001987 * xmlXPathNodeSetMergeUnique:
1988 * @val1: the first NodeSet or NULL
1989 * @val2: the second NodeSet
1990 *
1991 * Merges two nodesets, all nodes from @val2 are added to @val1
1992 * if @val1 is NULL, a new set is created and copied from @val2
1993 *
1994 * Returns @val1 once extended or NULL in case of error.
1995 */
1996static xmlNodeSetPtr
1997xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00001998 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00001999
2000 if (val2 == NULL) return(val1);
2001 if (val1 == NULL) {
2002 val1 = xmlXPathNodeSetCreate(NULL);
2003 }
2004
2005 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002006
2007 for (i = 0;i < val2->nodeNr;i++) {
2008 /*
2009 * grow the nodeTab if needed
2010 */
2011 if (val1->nodeMax == 0) {
2012 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2013 sizeof(xmlNodePtr));
2014 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002015 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002016 return(NULL);
2017 }
2018 memset(val1->nodeTab, 0 ,
2019 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2020 val1->nodeMax = XML_NODESET_DEFAULT;
2021 } else if (val1->nodeNr == val1->nodeMax) {
2022 xmlNodePtr *temp;
2023
2024 val1->nodeMax *= 2;
2025 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2026 sizeof(xmlNodePtr));
2027 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002028 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002029 return(NULL);
2030 }
2031 val1->nodeTab = temp;
2032 }
2033 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2034 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2035
2036 val1->nodeTab[val1->nodeNr++] =
2037 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2038 } else
2039 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2040 }
2041
2042 return(val1);
2043}
2044
2045/**
Owen Taylor3473f882001-02-23 17:55:21 +00002046 * xmlXPathNodeSetDel:
2047 * @cur: the initial node set
2048 * @val: an xmlNodePtr
2049 *
2050 * Removes an xmlNodePtr from an existing NodeSet
2051 */
2052void
2053xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2054 int i;
2055
2056 if (cur == NULL) return;
2057 if (val == NULL) return;
2058
2059 /*
2060 * check against doublons
2061 */
2062 for (i = 0;i < cur->nodeNr;i++)
2063 if (cur->nodeTab[i] == val) break;
2064
2065 if (i >= cur->nodeNr) {
2066#ifdef DEBUG
2067 xmlGenericError(xmlGenericErrorContext,
2068 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2069 val->name);
2070#endif
2071 return;
2072 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002073 if ((cur->nodeTab[i] != NULL) &&
2074 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2075 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002076 cur->nodeNr--;
2077 for (;i < cur->nodeNr;i++)
2078 cur->nodeTab[i] = cur->nodeTab[i + 1];
2079 cur->nodeTab[cur->nodeNr] = NULL;
2080}
2081
2082/**
2083 * xmlXPathNodeSetRemove:
2084 * @cur: the initial node set
2085 * @val: the index to remove
2086 *
2087 * Removes an entry from an existing NodeSet list.
2088 */
2089void
2090xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2091 if (cur == NULL) return;
2092 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002093 if ((cur->nodeTab[val] != NULL) &&
2094 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2095 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002096 cur->nodeNr--;
2097 for (;val < cur->nodeNr;val++)
2098 cur->nodeTab[val] = cur->nodeTab[val + 1];
2099 cur->nodeTab[cur->nodeNr] = NULL;
2100}
2101
2102/**
2103 * xmlXPathFreeNodeSet:
2104 * @obj: the xmlNodeSetPtr to free
2105 *
2106 * Free the NodeSet compound (not the actual nodes !).
2107 */
2108void
2109xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2110 if (obj == NULL) return;
2111 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002112 int i;
2113
2114 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2115 for (i = 0;i < obj->nodeNr;i++)
2116 if ((obj->nodeTab[i] != NULL) &&
2117 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2118 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002119 xmlFree(obj->nodeTab);
2120 }
Owen Taylor3473f882001-02-23 17:55:21 +00002121 xmlFree(obj);
2122}
2123
2124/**
2125 * xmlXPathFreeValueTree:
2126 * @obj: the xmlNodeSetPtr to free
2127 *
2128 * Free the NodeSet compound and the actual tree, this is different
2129 * from xmlXPathFreeNodeSet()
2130 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002131static void
Owen Taylor3473f882001-02-23 17:55:21 +00002132xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2133 int i;
2134
2135 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002136
2137 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002138 for (i = 0;i < obj->nodeNr;i++) {
2139 if (obj->nodeTab[i] != NULL) {
2140 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2141 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2142 } else {
2143 xmlFreeNodeList(obj->nodeTab[i]);
2144 }
2145 }
2146 }
Owen Taylor3473f882001-02-23 17:55:21 +00002147 xmlFree(obj->nodeTab);
2148 }
Owen Taylor3473f882001-02-23 17:55:21 +00002149 xmlFree(obj);
2150}
2151
2152#if defined(DEBUG) || defined(DEBUG_STEP)
2153/**
2154 * xmlGenericErrorContextNodeSet:
2155 * @output: a FILE * for the output
2156 * @obj: the xmlNodeSetPtr to free
2157 *
2158 * Quick display of a NodeSet
2159 */
2160void
2161xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2162 int i;
2163
2164 if (output == NULL) output = xmlGenericErrorContext;
2165 if (obj == NULL) {
2166 fprintf(output, "NodeSet == NULL !\n");
2167 return;
2168 }
2169 if (obj->nodeNr == 0) {
2170 fprintf(output, "NodeSet is empty\n");
2171 return;
2172 }
2173 if (obj->nodeTab == NULL) {
2174 fprintf(output, " nodeTab == NULL !\n");
2175 return;
2176 }
2177 for (i = 0; i < obj->nodeNr; i++) {
2178 if (obj->nodeTab[i] == NULL) {
2179 fprintf(output, " NULL !\n");
2180 return;
2181 }
2182 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2183 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2184 fprintf(output, " /");
2185 else if (obj->nodeTab[i]->name == NULL)
2186 fprintf(output, " noname!");
2187 else fprintf(output, " %s", obj->nodeTab[i]->name);
2188 }
2189 fprintf(output, "\n");
2190}
2191#endif
2192
2193/**
2194 * xmlXPathNewNodeSet:
2195 * @val: the NodePtr value
2196 *
2197 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2198 * it with the single Node @val
2199 *
2200 * Returns the newly created object.
2201 */
2202xmlXPathObjectPtr
2203xmlXPathNewNodeSet(xmlNodePtr val) {
2204 xmlXPathObjectPtr ret;
2205
2206 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2207 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002208 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002209 return(NULL);
2210 }
2211 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2212 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002213 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002214 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002215 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002216 return(ret);
2217}
2218
2219/**
2220 * xmlXPathNewValueTree:
2221 * @val: the NodePtr value
2222 *
2223 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2224 * it with the tree root @val
2225 *
2226 * Returns the newly created object.
2227 */
2228xmlXPathObjectPtr
2229xmlXPathNewValueTree(xmlNodePtr val) {
2230 xmlXPathObjectPtr ret;
2231
2232 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2233 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002234 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002235 return(NULL);
2236 }
2237 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2238 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002239 ret->boolval = 1;
2240 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002241 ret->nodesetval = xmlXPathNodeSetCreate(val);
2242 return(ret);
2243}
2244
2245/**
2246 * xmlXPathNewNodeSetList:
2247 * @val: an existing NodeSet
2248 *
2249 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2250 * it with the Nodeset @val
2251 *
2252 * Returns the newly created object.
2253 */
2254xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002255xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2256{
Owen Taylor3473f882001-02-23 17:55:21 +00002257 xmlXPathObjectPtr ret;
2258 int i;
2259
2260 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002261 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002262 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002263 ret = xmlXPathNewNodeSet(NULL);
2264 else {
2265 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2266 for (i = 1; i < val->nodeNr; ++i)
2267 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2268 }
Owen Taylor3473f882001-02-23 17:55:21 +00002269
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002270 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002271}
2272
2273/**
2274 * xmlXPathWrapNodeSet:
2275 * @val: the NodePtr value
2276 *
2277 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2278 *
2279 * Returns the newly created object.
2280 */
2281xmlXPathObjectPtr
2282xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2283 xmlXPathObjectPtr ret;
2284
2285 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2286 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002287 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002288 return(NULL);
2289 }
2290 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2291 ret->type = XPATH_NODESET;
2292 ret->nodesetval = val;
2293 return(ret);
2294}
2295
2296/**
2297 * xmlXPathFreeNodeSetList:
2298 * @obj: an existing NodeSetList object
2299 *
2300 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2301 * the list contrary to xmlXPathFreeObject().
2302 */
2303void
2304xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2305 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002306 xmlFree(obj);
2307}
2308
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002309/**
2310 * xmlXPathDifference:
2311 * @nodes1: a node-set
2312 * @nodes2: a node-set
2313 *
2314 * Implements the EXSLT - Sets difference() function:
2315 * node-set set:difference (node-set, node-set)
2316 *
2317 * Returns the difference between the two node sets, or nodes1 if
2318 * nodes2 is empty
2319 */
2320xmlNodeSetPtr
2321xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2322 xmlNodeSetPtr ret;
2323 int i, l1;
2324 xmlNodePtr cur;
2325
2326 if (xmlXPathNodeSetIsEmpty(nodes2))
2327 return(nodes1);
2328
2329 ret = xmlXPathNodeSetCreate(NULL);
2330 if (xmlXPathNodeSetIsEmpty(nodes1))
2331 return(ret);
2332
2333 l1 = xmlXPathNodeSetGetLength(nodes1);
2334
2335 for (i = 0; i < l1; i++) {
2336 cur = xmlXPathNodeSetItem(nodes1, i);
2337 if (!xmlXPathNodeSetContains(nodes2, cur))
2338 xmlXPathNodeSetAddUnique(ret, cur);
2339 }
2340 return(ret);
2341}
2342
2343/**
2344 * xmlXPathIntersection:
2345 * @nodes1: a node-set
2346 * @nodes2: a node-set
2347 *
2348 * Implements the EXSLT - Sets intersection() function:
2349 * node-set set:intersection (node-set, node-set)
2350 *
2351 * Returns a node set comprising the nodes that are within both the
2352 * node sets passed as arguments
2353 */
2354xmlNodeSetPtr
2355xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2356 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2357 int i, l1;
2358 xmlNodePtr cur;
2359
2360 if (xmlXPathNodeSetIsEmpty(nodes1))
2361 return(ret);
2362 if (xmlXPathNodeSetIsEmpty(nodes2))
2363 return(ret);
2364
2365 l1 = xmlXPathNodeSetGetLength(nodes1);
2366
2367 for (i = 0; i < l1; i++) {
2368 cur = xmlXPathNodeSetItem(nodes1, i);
2369 if (xmlXPathNodeSetContains(nodes2, cur))
2370 xmlXPathNodeSetAddUnique(ret, cur);
2371 }
2372 return(ret);
2373}
2374
2375/**
2376 * xmlXPathDistinctSorted:
2377 * @nodes: a node-set, sorted by document order
2378 *
2379 * Implements the EXSLT - Sets distinct() function:
2380 * node-set set:distinct (node-set)
2381 *
2382 * Returns a subset of the nodes contained in @nodes, or @nodes if
2383 * it is empty
2384 */
2385xmlNodeSetPtr
2386xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2387 xmlNodeSetPtr ret;
2388 xmlHashTablePtr hash;
2389 int i, l;
2390 xmlChar * strval;
2391 xmlNodePtr cur;
2392
2393 if (xmlXPathNodeSetIsEmpty(nodes))
2394 return(nodes);
2395
2396 ret = xmlXPathNodeSetCreate(NULL);
2397 l = xmlXPathNodeSetGetLength(nodes);
2398 hash = xmlHashCreate (l);
2399 for (i = 0; i < l; i++) {
2400 cur = xmlXPathNodeSetItem(nodes, i);
2401 strval = xmlXPathCastNodeToString(cur);
2402 if (xmlHashLookup(hash, strval) == NULL) {
2403 xmlHashAddEntry(hash, strval, strval);
2404 xmlXPathNodeSetAddUnique(ret, cur);
2405 } else {
2406 xmlFree(strval);
2407 }
2408 }
2409 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2410 return(ret);
2411}
2412
2413/**
2414 * xmlXPathDistinct:
2415 * @nodes: a node-set
2416 *
2417 * Implements the EXSLT - Sets distinct() function:
2418 * node-set set:distinct (node-set)
2419 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2420 * is called with the sorted node-set
2421 *
2422 * Returns a subset of the nodes contained in @nodes, or @nodes if
2423 * it is empty
2424 */
2425xmlNodeSetPtr
2426xmlXPathDistinct (xmlNodeSetPtr nodes) {
2427 if (xmlXPathNodeSetIsEmpty(nodes))
2428 return(nodes);
2429
2430 xmlXPathNodeSetSort(nodes);
2431 return(xmlXPathDistinctSorted(nodes));
2432}
2433
2434/**
2435 * xmlXPathHasSameNodes:
2436 * @nodes1: a node-set
2437 * @nodes2: a node-set
2438 *
2439 * Implements the EXSLT - Sets has-same-nodes function:
2440 * boolean set:has-same-node(node-set, node-set)
2441 *
2442 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2443 * otherwise
2444 */
2445int
2446xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2447 int i, l;
2448 xmlNodePtr cur;
2449
2450 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2451 xmlXPathNodeSetIsEmpty(nodes2))
2452 return(0);
2453
2454 l = xmlXPathNodeSetGetLength(nodes1);
2455 for (i = 0; i < l; i++) {
2456 cur = xmlXPathNodeSetItem(nodes1, i);
2457 if (xmlXPathNodeSetContains(nodes2, cur))
2458 return(1);
2459 }
2460 return(0);
2461}
2462
2463/**
2464 * xmlXPathNodeLeadingSorted:
2465 * @nodes: a node-set, sorted by document order
2466 * @node: a node
2467 *
2468 * Implements the EXSLT - Sets leading() function:
2469 * node-set set:leading (node-set, node-set)
2470 *
2471 * Returns the nodes in @nodes that precede @node in document order,
2472 * @nodes if @node is NULL or an empty node-set if @nodes
2473 * doesn't contain @node
2474 */
2475xmlNodeSetPtr
2476xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2477 int i, l;
2478 xmlNodePtr cur;
2479 xmlNodeSetPtr ret;
2480
2481 if (node == NULL)
2482 return(nodes);
2483
2484 ret = xmlXPathNodeSetCreate(NULL);
2485 if (xmlXPathNodeSetIsEmpty(nodes) ||
2486 (!xmlXPathNodeSetContains(nodes, node)))
2487 return(ret);
2488
2489 l = xmlXPathNodeSetGetLength(nodes);
2490 for (i = 0; i < l; i++) {
2491 cur = xmlXPathNodeSetItem(nodes, i);
2492 if (cur == node)
2493 break;
2494 xmlXPathNodeSetAddUnique(ret, cur);
2495 }
2496 return(ret);
2497}
2498
2499/**
2500 * xmlXPathNodeLeading:
2501 * @nodes: a node-set
2502 * @node: a node
2503 *
2504 * Implements the EXSLT - Sets leading() function:
2505 * node-set set:leading (node-set, node-set)
2506 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2507 * is called.
2508 *
2509 * Returns the nodes in @nodes that precede @node in document order,
2510 * @nodes if @node is NULL or an empty node-set if @nodes
2511 * doesn't contain @node
2512 */
2513xmlNodeSetPtr
2514xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2515 xmlXPathNodeSetSort(nodes);
2516 return(xmlXPathNodeLeadingSorted(nodes, node));
2517}
2518
2519/**
2520 * xmlXPathLeadingSorted:
2521 * @nodes1: a node-set, sorted by document order
2522 * @nodes2: a node-set, sorted by document order
2523 *
2524 * Implements the EXSLT - Sets leading() function:
2525 * node-set set:leading (node-set, node-set)
2526 *
2527 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2528 * in document order, @nodes1 if @nodes2 is NULL or empty or
2529 * an empty node-set if @nodes1 doesn't contain @nodes2
2530 */
2531xmlNodeSetPtr
2532xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2533 if (xmlXPathNodeSetIsEmpty(nodes2))
2534 return(nodes1);
2535 return(xmlXPathNodeLeadingSorted(nodes1,
2536 xmlXPathNodeSetItem(nodes2, 1)));
2537}
2538
2539/**
2540 * xmlXPathLeading:
2541 * @nodes1: a node-set
2542 * @nodes2: a node-set
2543 *
2544 * Implements the EXSLT - Sets leading() function:
2545 * node-set set:leading (node-set, node-set)
2546 * @nodes1 and @nodes2 are sorted by document order, then
2547 * #exslSetsLeadingSorted is called.
2548 *
2549 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2550 * in document order, @nodes1 if @nodes2 is NULL or empty or
2551 * an empty node-set if @nodes1 doesn't contain @nodes2
2552 */
2553xmlNodeSetPtr
2554xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2555 if (xmlXPathNodeSetIsEmpty(nodes2))
2556 return(nodes1);
2557 if (xmlXPathNodeSetIsEmpty(nodes1))
2558 return(xmlXPathNodeSetCreate(NULL));
2559 xmlXPathNodeSetSort(nodes1);
2560 xmlXPathNodeSetSort(nodes2);
2561 return(xmlXPathNodeLeadingSorted(nodes1,
2562 xmlXPathNodeSetItem(nodes2, 1)));
2563}
2564
2565/**
2566 * xmlXPathNodeTrailingSorted:
2567 * @nodes: a node-set, sorted by document order
2568 * @node: a node
2569 *
2570 * Implements the EXSLT - Sets trailing() function:
2571 * node-set set:trailing (node-set, node-set)
2572 *
2573 * Returns the nodes in @nodes that follow @node in document order,
2574 * @nodes if @node is NULL or an empty node-set if @nodes
2575 * doesn't contain @node
2576 */
2577xmlNodeSetPtr
2578xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2579 int i, l;
2580 xmlNodePtr cur;
2581 xmlNodeSetPtr ret;
2582
2583 if (node == NULL)
2584 return(nodes);
2585
2586 ret = xmlXPathNodeSetCreate(NULL);
2587 if (xmlXPathNodeSetIsEmpty(nodes) ||
2588 (!xmlXPathNodeSetContains(nodes, node)))
2589 return(ret);
2590
2591 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002592 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002593 cur = xmlXPathNodeSetItem(nodes, i);
2594 if (cur == node)
2595 break;
2596 xmlXPathNodeSetAddUnique(ret, cur);
2597 }
2598 return(ret);
2599}
2600
2601/**
2602 * xmlXPathNodeTrailing:
2603 * @nodes: a node-set
2604 * @node: a node
2605 *
2606 * Implements the EXSLT - Sets trailing() function:
2607 * node-set set:trailing (node-set, node-set)
2608 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2609 * is called.
2610 *
2611 * Returns the nodes in @nodes that follow @node in document order,
2612 * @nodes if @node is NULL or an empty node-set if @nodes
2613 * doesn't contain @node
2614 */
2615xmlNodeSetPtr
2616xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2617 xmlXPathNodeSetSort(nodes);
2618 return(xmlXPathNodeTrailingSorted(nodes, node));
2619}
2620
2621/**
2622 * xmlXPathTrailingSorted:
2623 * @nodes1: a node-set, sorted by document order
2624 * @nodes2: a node-set, sorted by document order
2625 *
2626 * Implements the EXSLT - Sets trailing() function:
2627 * node-set set:trailing (node-set, node-set)
2628 *
2629 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2630 * in document order, @nodes1 if @nodes2 is NULL or empty or
2631 * an empty node-set if @nodes1 doesn't contain @nodes2
2632 */
2633xmlNodeSetPtr
2634xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2635 if (xmlXPathNodeSetIsEmpty(nodes2))
2636 return(nodes1);
2637 return(xmlXPathNodeTrailingSorted(nodes1,
2638 xmlXPathNodeSetItem(nodes2, 0)));
2639}
2640
2641/**
2642 * xmlXPathTrailing:
2643 * @nodes1: a node-set
2644 * @nodes2: a node-set
2645 *
2646 * Implements the EXSLT - Sets trailing() function:
2647 * node-set set:trailing (node-set, node-set)
2648 * @nodes1 and @nodes2 are sorted by document order, then
2649 * #xmlXPathTrailingSorted is called.
2650 *
2651 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2652 * in document order, @nodes1 if @nodes2 is NULL or empty or
2653 * an empty node-set if @nodes1 doesn't contain @nodes2
2654 */
2655xmlNodeSetPtr
2656xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2657 if (xmlXPathNodeSetIsEmpty(nodes2))
2658 return(nodes1);
2659 if (xmlXPathNodeSetIsEmpty(nodes1))
2660 return(xmlXPathNodeSetCreate(NULL));
2661 xmlXPathNodeSetSort(nodes1);
2662 xmlXPathNodeSetSort(nodes2);
2663 return(xmlXPathNodeTrailingSorted(nodes1,
2664 xmlXPathNodeSetItem(nodes2, 0)));
2665}
2666
Owen Taylor3473f882001-02-23 17:55:21 +00002667/************************************************************************
2668 * *
2669 * Routines to handle extra functions *
2670 * *
2671 ************************************************************************/
2672
2673/**
2674 * xmlXPathRegisterFunc:
2675 * @ctxt: the XPath context
2676 * @name: the function name
2677 * @f: the function implementation or NULL
2678 *
2679 * Register a new function. If @f is NULL it unregisters the function
2680 *
2681 * Returns 0 in case of success, -1 in case of error
2682 */
2683int
2684xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2685 xmlXPathFunction f) {
2686 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2687}
2688
2689/**
2690 * xmlXPathRegisterFuncNS:
2691 * @ctxt: the XPath context
2692 * @name: the function name
2693 * @ns_uri: the function namespace URI
2694 * @f: the function implementation or NULL
2695 *
2696 * Register a new function. If @f is NULL it unregisters the function
2697 *
2698 * Returns 0 in case of success, -1 in case of error
2699 */
2700int
2701xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2702 const xmlChar *ns_uri, xmlXPathFunction f) {
2703 if (ctxt == NULL)
2704 return(-1);
2705 if (name == NULL)
2706 return(-1);
2707
2708 if (ctxt->funcHash == NULL)
2709 ctxt->funcHash = xmlHashCreate(0);
2710 if (ctxt->funcHash == NULL)
2711 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002712 if (f == NULL)
2713 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002714 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2715}
2716
2717/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002718 * xmlXPathRegisterFuncLookup:
2719 * @ctxt: the XPath context
2720 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002721 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002722 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002723 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002724 */
2725void
2726xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2727 xmlXPathFuncLookupFunc f,
2728 void *funcCtxt) {
2729 if (ctxt == NULL)
2730 return;
2731 ctxt->funcLookupFunc = (void *) f;
2732 ctxt->funcLookupData = funcCtxt;
2733}
2734
2735/**
Owen Taylor3473f882001-02-23 17:55:21 +00002736 * xmlXPathFunctionLookup:
2737 * @ctxt: the XPath context
2738 * @name: the function name
2739 *
2740 * Search in the Function array of the context for the given
2741 * function.
2742 *
2743 * Returns the xmlXPathFunction or NULL if not found
2744 */
2745xmlXPathFunction
2746xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002747 if (ctxt == NULL)
2748 return (NULL);
2749
2750 if (ctxt->funcLookupFunc != NULL) {
2751 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002752 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002753
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002754 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002755 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002756 if (ret != NULL)
2757 return(ret);
2758 }
Owen Taylor3473f882001-02-23 17:55:21 +00002759 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2760}
2761
2762/**
2763 * xmlXPathFunctionLookupNS:
2764 * @ctxt: the XPath context
2765 * @name: the function name
2766 * @ns_uri: the function namespace URI
2767 *
2768 * Search in the Function array of the context for the given
2769 * function.
2770 *
2771 * Returns the xmlXPathFunction or NULL if not found
2772 */
2773xmlXPathFunction
2774xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2775 const xmlChar *ns_uri) {
2776 if (ctxt == NULL)
2777 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002778 if (name == NULL)
2779 return(NULL);
2780
Thomas Broyerba4ad322001-07-26 16:55:21 +00002781 if (ctxt->funcLookupFunc != NULL) {
2782 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002783 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002784
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002785 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002786 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002787 if (ret != NULL)
2788 return(ret);
2789 }
2790
2791 if (ctxt->funcHash == NULL)
2792 return(NULL);
2793
Owen Taylor3473f882001-02-23 17:55:21 +00002794 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2795}
2796
2797/**
2798 * xmlXPathRegisteredFuncsCleanup:
2799 * @ctxt: the XPath context
2800 *
2801 * Cleanup the XPath context data associated to registered functions
2802 */
2803void
2804xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2805 if (ctxt == NULL)
2806 return;
2807
2808 xmlHashFree(ctxt->funcHash, NULL);
2809 ctxt->funcHash = NULL;
2810}
2811
2812/************************************************************************
2813 * *
2814 * Routines to handle Variable *
2815 * *
2816 ************************************************************************/
2817
2818/**
2819 * xmlXPathRegisterVariable:
2820 * @ctxt: the XPath context
2821 * @name: the variable name
2822 * @value: the variable value or NULL
2823 *
2824 * Register a new variable value. If @value is NULL it unregisters
2825 * the variable
2826 *
2827 * Returns 0 in case of success, -1 in case of error
2828 */
2829int
2830xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2831 xmlXPathObjectPtr value) {
2832 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2833}
2834
2835/**
2836 * xmlXPathRegisterVariableNS:
2837 * @ctxt: the XPath context
2838 * @name: the variable name
2839 * @ns_uri: the variable namespace URI
2840 * @value: the variable value or NULL
2841 *
2842 * Register a new variable value. If @value is NULL it unregisters
2843 * the variable
2844 *
2845 * Returns 0 in case of success, -1 in case of error
2846 */
2847int
2848xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2849 const xmlChar *ns_uri,
2850 xmlXPathObjectPtr value) {
2851 if (ctxt == NULL)
2852 return(-1);
2853 if (name == NULL)
2854 return(-1);
2855
2856 if (ctxt->varHash == NULL)
2857 ctxt->varHash = xmlHashCreate(0);
2858 if (ctxt->varHash == NULL)
2859 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002860 if (value == NULL)
2861 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2862 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002863 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2864 (void *) value,
2865 (xmlHashDeallocator)xmlXPathFreeObject));
2866}
2867
2868/**
2869 * xmlXPathRegisterVariableLookup:
2870 * @ctxt: the XPath context
2871 * @f: the lookup function
2872 * @data: the lookup data
2873 *
2874 * register an external mechanism to do variable lookup
2875 */
2876void
2877xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2878 xmlXPathVariableLookupFunc f, void *data) {
2879 if (ctxt == NULL)
2880 return;
2881 ctxt->varLookupFunc = (void *) f;
2882 ctxt->varLookupData = data;
2883}
2884
2885/**
2886 * xmlXPathVariableLookup:
2887 * @ctxt: the XPath context
2888 * @name: the variable name
2889 *
2890 * Search in the Variable array of the context for the given
2891 * variable value.
2892 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002893 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002894 */
2895xmlXPathObjectPtr
2896xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2897 if (ctxt == NULL)
2898 return(NULL);
2899
2900 if (ctxt->varLookupFunc != NULL) {
2901 xmlXPathObjectPtr ret;
2902
2903 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2904 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002905 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002906 }
2907 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2908}
2909
2910/**
2911 * xmlXPathVariableLookupNS:
2912 * @ctxt: the XPath context
2913 * @name: the variable name
2914 * @ns_uri: the variable namespace URI
2915 *
2916 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002917 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002918 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002919 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002920 */
2921xmlXPathObjectPtr
2922xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2923 const xmlChar *ns_uri) {
2924 if (ctxt == NULL)
2925 return(NULL);
2926
2927 if (ctxt->varLookupFunc != NULL) {
2928 xmlXPathObjectPtr ret;
2929
2930 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2931 (ctxt->varLookupData, name, ns_uri);
2932 if (ret != NULL) return(ret);
2933 }
2934
2935 if (ctxt->varHash == NULL)
2936 return(NULL);
2937 if (name == NULL)
2938 return(NULL);
2939
Daniel Veillard8c357d52001-07-03 23:43:33 +00002940 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2941 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002942}
2943
2944/**
2945 * xmlXPathRegisteredVariablesCleanup:
2946 * @ctxt: the XPath context
2947 *
2948 * Cleanup the XPath context data associated to registered variables
2949 */
2950void
2951xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2952 if (ctxt == NULL)
2953 return;
2954
Daniel Veillard76d66f42001-05-16 21:05:17 +00002955 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002956 ctxt->varHash = NULL;
2957}
2958
2959/**
2960 * xmlXPathRegisterNs:
2961 * @ctxt: the XPath context
2962 * @prefix: the namespace prefix
2963 * @ns_uri: the namespace name
2964 *
2965 * Register a new namespace. If @ns_uri is NULL it unregisters
2966 * the namespace
2967 *
2968 * Returns 0 in case of success, -1 in case of error
2969 */
2970int
2971xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2972 const xmlChar *ns_uri) {
2973 if (ctxt == NULL)
2974 return(-1);
2975 if (prefix == NULL)
2976 return(-1);
2977
2978 if (ctxt->nsHash == NULL)
2979 ctxt->nsHash = xmlHashCreate(10);
2980 if (ctxt->nsHash == NULL)
2981 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00002982 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00002983 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00002984 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00002985 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002986 (xmlHashDeallocator)xmlFree));
2987}
2988
2989/**
2990 * xmlXPathNsLookup:
2991 * @ctxt: the XPath context
2992 * @prefix: the namespace prefix value
2993 *
2994 * Search in the namespace declaration array of the context for the given
2995 * namespace name associated to the given prefix
2996 *
2997 * Returns the value or NULL if not found
2998 */
2999const xmlChar *
3000xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3001 if (ctxt == NULL)
3002 return(NULL);
3003 if (prefix == NULL)
3004 return(NULL);
3005
3006#ifdef XML_XML_NAMESPACE
3007 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3008 return(XML_XML_NAMESPACE);
3009#endif
3010
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003011 if (ctxt->namespaces != NULL) {
3012 int i;
3013
3014 for (i = 0;i < ctxt->nsNr;i++) {
3015 if ((ctxt->namespaces[i] != NULL) &&
3016 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3017 return(ctxt->namespaces[i]->href);
3018 }
3019 }
Owen Taylor3473f882001-02-23 17:55:21 +00003020
3021 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3022}
3023
3024/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003025 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003026 * @ctxt: the XPath context
3027 *
3028 * Cleanup the XPath context data associated to registered variables
3029 */
3030void
3031xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3032 if (ctxt == NULL)
3033 return;
3034
Daniel Veillard42766c02002-08-22 20:52:17 +00003035 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003036 ctxt->nsHash = NULL;
3037}
3038
3039/************************************************************************
3040 * *
3041 * Routines to handle Values *
3042 * *
3043 ************************************************************************/
3044
3045/* Allocations are terrible, one need to optimize all this !!! */
3046
3047/**
3048 * xmlXPathNewFloat:
3049 * @val: the double value
3050 *
3051 * Create a new xmlXPathObjectPtr of type double and of value @val
3052 *
3053 * Returns the newly created object.
3054 */
3055xmlXPathObjectPtr
3056xmlXPathNewFloat(double val) {
3057 xmlXPathObjectPtr ret;
3058
3059 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3060 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003061 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003062 return(NULL);
3063 }
3064 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3065 ret->type = XPATH_NUMBER;
3066 ret->floatval = val;
3067 return(ret);
3068}
3069
3070/**
3071 * xmlXPathNewBoolean:
3072 * @val: the boolean value
3073 *
3074 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3075 *
3076 * Returns the newly created object.
3077 */
3078xmlXPathObjectPtr
3079xmlXPathNewBoolean(int 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 boolean 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_BOOLEAN;
3089 ret->boolval = (val != 0);
3090 return(ret);
3091}
3092
3093/**
3094 * xmlXPathNewString:
3095 * @val: the xmlChar * value
3096 *
3097 * Create a new xmlXPathObjectPtr of type string and of value @val
3098 *
3099 * Returns the newly created object.
3100 */
3101xmlXPathObjectPtr
3102xmlXPathNewString(const xmlChar *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 string 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_STRING;
3112 if (val != NULL)
3113 ret->stringval = xmlStrdup(val);
3114 else
3115 ret->stringval = xmlStrdup((const xmlChar *)"");
3116 return(ret);
3117}
3118
3119/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003120 * xmlXPathWrapString:
3121 * @val: the xmlChar * value
3122 *
3123 * Wraps the @val string into an XPath object.
3124 *
3125 * Returns the newly created object.
3126 */
3127xmlXPathObjectPtr
3128xmlXPathWrapString (xmlChar *val) {
3129 xmlXPathObjectPtr ret;
3130
3131 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3132 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003133 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003134 return(NULL);
3135 }
3136 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3137 ret->type = XPATH_STRING;
3138 ret->stringval = val;
3139 return(ret);
3140}
3141
3142/**
Owen Taylor3473f882001-02-23 17:55:21 +00003143 * xmlXPathNewCString:
3144 * @val: the char * value
3145 *
3146 * Create a new xmlXPathObjectPtr of type string and of value @val
3147 *
3148 * Returns the newly created object.
3149 */
3150xmlXPathObjectPtr
3151xmlXPathNewCString(const char *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");
Owen Taylor3473f882001-02-23 17:55:21 +00003157 return(NULL);
3158 }
3159 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3160 ret->type = XPATH_STRING;
3161 ret->stringval = xmlStrdup(BAD_CAST val);
3162 return(ret);
3163}
3164
3165/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003166 * xmlXPathWrapCString:
3167 * @val: the char * value
3168 *
3169 * Wraps a string into an XPath object.
3170 *
3171 * Returns the newly created object.
3172 */
3173xmlXPathObjectPtr
3174xmlXPathWrapCString (char * val) {
3175 return(xmlXPathWrapString((xmlChar *)(val)));
3176}
3177
3178/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003179 * xmlXPathWrapExternal:
3180 * @val: the user data
3181 *
3182 * Wraps the @val data into an XPath object.
3183 *
3184 * Returns the newly created object.
3185 */
3186xmlXPathObjectPtr
3187xmlXPathWrapExternal (void *val) {
3188 xmlXPathObjectPtr ret;
3189
3190 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3191 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003192 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003193 return(NULL);
3194 }
3195 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3196 ret->type = XPATH_USERS;
3197 ret->user = val;
3198 return(ret);
3199}
3200
3201/**
Owen Taylor3473f882001-02-23 17:55:21 +00003202 * xmlXPathObjectCopy:
3203 * @val: the original object
3204 *
3205 * allocate a new copy of a given object
3206 *
3207 * Returns the newly created object.
3208 */
3209xmlXPathObjectPtr
3210xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3211 xmlXPathObjectPtr ret;
3212
3213 if (val == NULL)
3214 return(NULL);
3215
3216 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3217 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003218 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003219 return(NULL);
3220 }
3221 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3222 switch (val->type) {
3223 case XPATH_BOOLEAN:
3224 case XPATH_NUMBER:
3225 case XPATH_POINT:
3226 case XPATH_RANGE:
3227 break;
3228 case XPATH_STRING:
3229 ret->stringval = xmlStrdup(val->stringval);
3230 break;
3231 case XPATH_XSLT_TREE:
3232 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003233 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003234 xmlNodePtr cur, tmp;
3235 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003236
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003237 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003238 top = xmlNewDoc(NULL);
3239 top->name = (char *)
3240 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003241 ret->user = top;
3242 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003243 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003244 cur = val->nodesetval->nodeTab[0]->children;
3245 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003246 tmp = xmlDocCopyNode(cur, top, 1);
3247 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003248 cur = cur->next;
3249 }
3250 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003251 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003252 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003253 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003254 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003255 break;
3256 case XPATH_NODESET:
3257 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003258 /* Do not deallocate the copied tree value */
3259 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003260 break;
3261 case XPATH_LOCATIONSET:
3262#ifdef LIBXML_XPTR_ENABLED
3263 {
3264 xmlLocationSetPtr loc = val->user;
3265 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3266 break;
3267 }
3268#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003269 case XPATH_USERS:
3270 ret->user = val->user;
3271 break;
3272 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003273 xmlGenericError(xmlGenericErrorContext,
3274 "xmlXPathObjectCopy: unsupported type %d\n",
3275 val->type);
3276 break;
3277 }
3278 return(ret);
3279}
3280
3281/**
3282 * xmlXPathFreeObject:
3283 * @obj: the object to free
3284 *
3285 * Free up an xmlXPathObjectPtr object.
3286 */
3287void
3288xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3289 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003290 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003291 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003292 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003293 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003294 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003295 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003296 xmlXPathFreeValueTree(obj->nodesetval);
3297 } else {
3298 if (obj->nodesetval != NULL)
3299 xmlXPathFreeNodeSet(obj->nodesetval);
3300 }
Owen Taylor3473f882001-02-23 17:55:21 +00003301#ifdef LIBXML_XPTR_ENABLED
3302 } else if (obj->type == XPATH_LOCATIONSET) {
3303 if (obj->user != NULL)
3304 xmlXPtrFreeLocationSet(obj->user);
3305#endif
3306 } else if (obj->type == XPATH_STRING) {
3307 if (obj->stringval != NULL)
3308 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003309 }
3310
Owen Taylor3473f882001-02-23 17:55:21 +00003311 xmlFree(obj);
3312}
3313
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003314
3315/************************************************************************
3316 * *
3317 * Type Casting Routines *
3318 * *
3319 ************************************************************************/
3320
3321/**
3322 * xmlXPathCastBooleanToString:
3323 * @val: a boolean
3324 *
3325 * Converts a boolean to its string value.
3326 *
3327 * Returns a newly allocated string.
3328 */
3329xmlChar *
3330xmlXPathCastBooleanToString (int val) {
3331 xmlChar *ret;
3332 if (val)
3333 ret = xmlStrdup((const xmlChar *) "true");
3334 else
3335 ret = xmlStrdup((const xmlChar *) "false");
3336 return(ret);
3337}
3338
3339/**
3340 * xmlXPathCastNumberToString:
3341 * @val: a number
3342 *
3343 * Converts a number to its string value.
3344 *
3345 * Returns a newly allocated string.
3346 */
3347xmlChar *
3348xmlXPathCastNumberToString (double val) {
3349 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003350 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003351 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003352 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003353 break;
3354 case -1:
3355 ret = xmlStrdup((const xmlChar *) "-Infinity");
3356 break;
3357 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003358 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003359 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003360 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3361 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003362 } else {
3363 /* could be improved */
3364 char buf[100];
3365 xmlXPathFormatNumber(val, buf, 100);
3366 ret = xmlStrdup((const xmlChar *) buf);
3367 }
3368 }
3369 return(ret);
3370}
3371
3372/**
3373 * xmlXPathCastNodeToString:
3374 * @node: a node
3375 *
3376 * Converts a node to its string value.
3377 *
3378 * Returns a newly allocated string.
3379 */
3380xmlChar *
3381xmlXPathCastNodeToString (xmlNodePtr node) {
3382 return(xmlNodeGetContent(node));
3383}
3384
3385/**
3386 * xmlXPathCastNodeSetToString:
3387 * @ns: a node-set
3388 *
3389 * Converts a node-set to its string value.
3390 *
3391 * Returns a newly allocated string.
3392 */
3393xmlChar *
3394xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3395 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3396 return(xmlStrdup((const xmlChar *) ""));
3397
3398 xmlXPathNodeSetSort(ns);
3399 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3400}
3401
3402/**
3403 * xmlXPathCastToString:
3404 * @val: an XPath object
3405 *
3406 * Converts an existing object to its string() equivalent
3407 *
3408 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003409 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003410 * string object).
3411 */
3412xmlChar *
3413xmlXPathCastToString(xmlXPathObjectPtr val) {
3414 xmlChar *ret = NULL;
3415
3416 if (val == NULL)
3417 return(xmlStrdup((const xmlChar *) ""));
3418 switch (val->type) {
3419 case XPATH_UNDEFINED:
3420#ifdef DEBUG_EXPR
3421 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3422#endif
3423 ret = xmlStrdup((const xmlChar *) "");
3424 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003425 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003426 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003427 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3428 break;
3429 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003430 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003431 case XPATH_BOOLEAN:
3432 ret = xmlXPathCastBooleanToString(val->boolval);
3433 break;
3434 case XPATH_NUMBER: {
3435 ret = xmlXPathCastNumberToString(val->floatval);
3436 break;
3437 }
3438 case XPATH_USERS:
3439 case XPATH_POINT:
3440 case XPATH_RANGE:
3441 case XPATH_LOCATIONSET:
3442 TODO
3443 ret = xmlStrdup((const xmlChar *) "");
3444 break;
3445 }
3446 return(ret);
3447}
3448
3449/**
3450 * xmlXPathConvertString:
3451 * @val: an XPath object
3452 *
3453 * Converts an existing object to its string() equivalent
3454 *
3455 * Returns the new object, the old one is freed (or the operation
3456 * is done directly on @val)
3457 */
3458xmlXPathObjectPtr
3459xmlXPathConvertString(xmlXPathObjectPtr val) {
3460 xmlChar *res = NULL;
3461
3462 if (val == NULL)
3463 return(xmlXPathNewCString(""));
3464
3465 switch (val->type) {
3466 case XPATH_UNDEFINED:
3467#ifdef DEBUG_EXPR
3468 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3469#endif
3470 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003471 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003472 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003473 res = xmlXPathCastNodeSetToString(val->nodesetval);
3474 break;
3475 case XPATH_STRING:
3476 return(val);
3477 case XPATH_BOOLEAN:
3478 res = xmlXPathCastBooleanToString(val->boolval);
3479 break;
3480 case XPATH_NUMBER:
3481 res = xmlXPathCastNumberToString(val->floatval);
3482 break;
3483 case XPATH_USERS:
3484 case XPATH_POINT:
3485 case XPATH_RANGE:
3486 case XPATH_LOCATIONSET:
3487 TODO;
3488 break;
3489 }
3490 xmlXPathFreeObject(val);
3491 if (res == NULL)
3492 return(xmlXPathNewCString(""));
3493 return(xmlXPathWrapString(res));
3494}
3495
3496/**
3497 * xmlXPathCastBooleanToNumber:
3498 * @val: a boolean
3499 *
3500 * Converts a boolean to its number value
3501 *
3502 * Returns the number value
3503 */
3504double
3505xmlXPathCastBooleanToNumber(int val) {
3506 if (val)
3507 return(1.0);
3508 return(0.0);
3509}
3510
3511/**
3512 * xmlXPathCastStringToNumber:
3513 * @val: a string
3514 *
3515 * Converts a string to its number value
3516 *
3517 * Returns the number value
3518 */
3519double
3520xmlXPathCastStringToNumber(const xmlChar * val) {
3521 return(xmlXPathStringEvalNumber(val));
3522}
3523
3524/**
3525 * xmlXPathCastNodeToNumber:
3526 * @node: a node
3527 *
3528 * Converts a node to its number value
3529 *
3530 * Returns the number value
3531 */
3532double
3533xmlXPathCastNodeToNumber (xmlNodePtr node) {
3534 xmlChar *strval;
3535 double ret;
3536
3537 if (node == NULL)
3538 return(xmlXPathNAN);
3539 strval = xmlXPathCastNodeToString(node);
3540 if (strval == NULL)
3541 return(xmlXPathNAN);
3542 ret = xmlXPathCastStringToNumber(strval);
3543 xmlFree(strval);
3544
3545 return(ret);
3546}
3547
3548/**
3549 * xmlXPathCastNodeSetToNumber:
3550 * @ns: a node-set
3551 *
3552 * Converts a node-set to its number value
3553 *
3554 * Returns the number value
3555 */
3556double
3557xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3558 xmlChar *str;
3559 double ret;
3560
3561 if (ns == NULL)
3562 return(xmlXPathNAN);
3563 str = xmlXPathCastNodeSetToString(ns);
3564 ret = xmlXPathCastStringToNumber(str);
3565 xmlFree(str);
3566 return(ret);
3567}
3568
3569/**
3570 * xmlXPathCastToNumber:
3571 * @val: an XPath object
3572 *
3573 * Converts an XPath object to its number value
3574 *
3575 * Returns the number value
3576 */
3577double
3578xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3579 double ret = 0.0;
3580
3581 if (val == NULL)
3582 return(xmlXPathNAN);
3583 switch (val->type) {
3584 case XPATH_UNDEFINED:
3585#ifdef DEGUB_EXPR
3586 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3587#endif
3588 ret = xmlXPathNAN;
3589 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003590 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003591 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003592 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3593 break;
3594 case XPATH_STRING:
3595 ret = xmlXPathCastStringToNumber(val->stringval);
3596 break;
3597 case XPATH_NUMBER:
3598 ret = val->floatval;
3599 break;
3600 case XPATH_BOOLEAN:
3601 ret = xmlXPathCastBooleanToNumber(val->boolval);
3602 break;
3603 case XPATH_USERS:
3604 case XPATH_POINT:
3605 case XPATH_RANGE:
3606 case XPATH_LOCATIONSET:
3607 TODO;
3608 ret = xmlXPathNAN;
3609 break;
3610 }
3611 return(ret);
3612}
3613
3614/**
3615 * xmlXPathConvertNumber:
3616 * @val: an XPath object
3617 *
3618 * Converts an existing object to its number() equivalent
3619 *
3620 * Returns the new object, the old one is freed (or the operation
3621 * is done directly on @val)
3622 */
3623xmlXPathObjectPtr
3624xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3625 xmlXPathObjectPtr ret;
3626
3627 if (val == NULL)
3628 return(xmlXPathNewFloat(0.0));
3629 if (val->type == XPATH_NUMBER)
3630 return(val);
3631 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3632 xmlXPathFreeObject(val);
3633 return(ret);
3634}
3635
3636/**
3637 * xmlXPathCastNumberToBoolean:
3638 * @val: a number
3639 *
3640 * Converts a number to its boolean value
3641 *
3642 * Returns the boolean value
3643 */
3644int
3645xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003646 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003647 return(0);
3648 return(1);
3649}
3650
3651/**
3652 * xmlXPathCastStringToBoolean:
3653 * @val: a string
3654 *
3655 * Converts a string to its boolean value
3656 *
3657 * Returns the boolean value
3658 */
3659int
3660xmlXPathCastStringToBoolean (const xmlChar *val) {
3661 if ((val == NULL) || (xmlStrlen(val) == 0))
3662 return(0);
3663 return(1);
3664}
3665
3666/**
3667 * xmlXPathCastNodeSetToBoolean:
3668 * @ns: a node-set
3669 *
3670 * Converts a node-set to its boolean value
3671 *
3672 * Returns the boolean value
3673 */
3674int
3675xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3676 if ((ns == NULL) || (ns->nodeNr == 0))
3677 return(0);
3678 return(1);
3679}
3680
3681/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003682 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003683 * @val: an XPath object
3684 *
3685 * Converts an XPath object to its boolean value
3686 *
3687 * Returns the boolean value
3688 */
3689int
3690xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3691 int ret = 0;
3692
3693 if (val == NULL)
3694 return(0);
3695 switch (val->type) {
3696 case XPATH_UNDEFINED:
3697#ifdef DEBUG_EXPR
3698 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3699#endif
3700 ret = 0;
3701 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003702 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003703 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003704 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3705 break;
3706 case XPATH_STRING:
3707 ret = xmlXPathCastStringToBoolean(val->stringval);
3708 break;
3709 case XPATH_NUMBER:
3710 ret = xmlXPathCastNumberToBoolean(val->floatval);
3711 break;
3712 case XPATH_BOOLEAN:
3713 ret = val->boolval;
3714 break;
3715 case XPATH_USERS:
3716 case XPATH_POINT:
3717 case XPATH_RANGE:
3718 case XPATH_LOCATIONSET:
3719 TODO;
3720 ret = 0;
3721 break;
3722 }
3723 return(ret);
3724}
3725
3726
3727/**
3728 * xmlXPathConvertBoolean:
3729 * @val: an XPath object
3730 *
3731 * Converts an existing object to its boolean() equivalent
3732 *
3733 * Returns the new object, the old one is freed (or the operation
3734 * is done directly on @val)
3735 */
3736xmlXPathObjectPtr
3737xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3738 xmlXPathObjectPtr ret;
3739
3740 if (val == NULL)
3741 return(xmlXPathNewBoolean(0));
3742 if (val->type == XPATH_BOOLEAN)
3743 return(val);
3744 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3745 xmlXPathFreeObject(val);
3746 return(ret);
3747}
3748
Owen Taylor3473f882001-02-23 17:55:21 +00003749/************************************************************************
3750 * *
3751 * Routines to handle XPath contexts *
3752 * *
3753 ************************************************************************/
3754
3755/**
3756 * xmlXPathNewContext:
3757 * @doc: the XML document
3758 *
3759 * Create a new xmlXPathContext
3760 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003761 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003762 */
3763xmlXPathContextPtr
3764xmlXPathNewContext(xmlDocPtr doc) {
3765 xmlXPathContextPtr ret;
3766
3767 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3768 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003769 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003770 return(NULL);
3771 }
3772 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3773 ret->doc = doc;
3774 ret->node = NULL;
3775
3776 ret->varHash = NULL;
3777
3778 ret->nb_types = 0;
3779 ret->max_types = 0;
3780 ret->types = NULL;
3781
3782 ret->funcHash = xmlHashCreate(0);
3783
3784 ret->nb_axis = 0;
3785 ret->max_axis = 0;
3786 ret->axis = NULL;
3787
3788 ret->nsHash = NULL;
3789 ret->user = NULL;
3790
3791 ret->contextSize = -1;
3792 ret->proximityPosition = -1;
3793
3794 xmlXPathRegisterAllFunctions(ret);
3795
3796 return(ret);
3797}
3798
3799/**
3800 * xmlXPathFreeContext:
3801 * @ctxt: the context to free
3802 *
3803 * Free up an xmlXPathContext
3804 */
3805void
3806xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3807 xmlXPathRegisteredNsCleanup(ctxt);
3808 xmlXPathRegisteredFuncsCleanup(ctxt);
3809 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003810 xmlFree(ctxt);
3811}
3812
3813/************************************************************************
3814 * *
3815 * Routines to handle XPath parser contexts *
3816 * *
3817 ************************************************************************/
3818
3819#define CHECK_CTXT(ctxt) \
3820 if (ctxt == NULL) { \
3821 xmlGenericError(xmlGenericErrorContext, \
3822 "%s:%d Internal error: ctxt == NULL\n", \
3823 __FILE__, __LINE__); \
3824 } \
3825
3826
3827#define CHECK_CONTEXT(ctxt) \
3828 if (ctxt == NULL) { \
3829 xmlGenericError(xmlGenericErrorContext, \
3830 "%s:%d Internal error: no context\n", \
3831 __FILE__, __LINE__); \
3832 } \
3833 else if (ctxt->doc == NULL) { \
3834 xmlGenericError(xmlGenericErrorContext, \
3835 "%s:%d Internal error: no document\n", \
3836 __FILE__, __LINE__); \
3837 } \
3838 else if (ctxt->doc->children == NULL) { \
3839 xmlGenericError(xmlGenericErrorContext, \
3840 "%s:%d Internal error: document without root\n", \
3841 __FILE__, __LINE__); \
3842 } \
3843
3844
3845/**
3846 * xmlXPathNewParserContext:
3847 * @str: the XPath expression
3848 * @ctxt: the XPath context
3849 *
3850 * Create a new xmlXPathParserContext
3851 *
3852 * Returns the xmlXPathParserContext just allocated.
3853 */
3854xmlXPathParserContextPtr
3855xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3856 xmlXPathParserContextPtr ret;
3857
3858 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3859 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003860 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003861 return(NULL);
3862 }
3863 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3864 ret->cur = ret->base = str;
3865 ret->context = ctxt;
3866
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003867 ret->comp = xmlXPathNewCompExpr();
3868 if (ret->comp == NULL) {
3869 xmlFree(ret->valueTab);
3870 xmlFree(ret);
3871 return(NULL);
3872 }
3873
3874 return(ret);
3875}
3876
3877/**
3878 * xmlXPathCompParserContext:
3879 * @comp: the XPath compiled expression
3880 * @ctxt: the XPath context
3881 *
3882 * Create a new xmlXPathParserContext when processing a compiled expression
3883 *
3884 * Returns the xmlXPathParserContext just allocated.
3885 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003886static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003887xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3888 xmlXPathParserContextPtr ret;
3889
3890 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3891 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003892 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003893 return(NULL);
3894 }
3895 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3896
Owen Taylor3473f882001-02-23 17:55:21 +00003897 /* Allocate the value stack */
3898 ret->valueTab = (xmlXPathObjectPtr *)
3899 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003900 if (ret->valueTab == NULL) {
3901 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003902 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003903 return(NULL);
3904 }
Owen Taylor3473f882001-02-23 17:55:21 +00003905 ret->valueNr = 0;
3906 ret->valueMax = 10;
3907 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003908
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003909 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003910 ret->comp = comp;
3911
Owen Taylor3473f882001-02-23 17:55:21 +00003912 return(ret);
3913}
3914
3915/**
3916 * xmlXPathFreeParserContext:
3917 * @ctxt: the context to free
3918 *
3919 * Free up an xmlXPathParserContext
3920 */
3921void
3922xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3923 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003924 xmlFree(ctxt->valueTab);
3925 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003926 if (ctxt->comp)
3927 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003928 xmlFree(ctxt);
3929}
3930
3931/************************************************************************
3932 * *
3933 * The implicit core function library *
3934 * *
3935 ************************************************************************/
3936
Owen Taylor3473f882001-02-23 17:55:21 +00003937/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003938 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003939 * @node: a node pointer
3940 *
3941 * Function computing the beginning of the string value of the node,
3942 * used to speed up comparisons
3943 *
3944 * Returns an int usable as a hash
3945 */
3946static unsigned int
3947xmlXPathNodeValHash(xmlNodePtr node) {
3948 int len = 2;
3949 const xmlChar * string = NULL;
3950 xmlNodePtr tmp = NULL;
3951 unsigned int ret = 0;
3952
3953 if (node == NULL)
3954 return(0);
3955
Daniel Veillard9adc0462003-03-24 18:39:54 +00003956 if (node->type == XML_DOCUMENT_NODE) {
3957 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3958 if (tmp == NULL)
3959 node = node->children;
3960 else
3961 node = tmp;
3962
3963 if (node == NULL)
3964 return(0);
3965 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003966
3967 switch (node->type) {
3968 case XML_COMMENT_NODE:
3969 case XML_PI_NODE:
3970 case XML_CDATA_SECTION_NODE:
3971 case XML_TEXT_NODE:
3972 string = node->content;
3973 if (string == NULL)
3974 return(0);
3975 if (string[0] == 0)
3976 return(0);
3977 return(((unsigned int) string[0]) +
3978 (((unsigned int) string[1]) << 8));
3979 case XML_NAMESPACE_DECL:
3980 string = ((xmlNsPtr)node)->href;
3981 if (string == NULL)
3982 return(0);
3983 if (string[0] == 0)
3984 return(0);
3985 return(((unsigned int) string[0]) +
3986 (((unsigned int) string[1]) << 8));
3987 case XML_ATTRIBUTE_NODE:
3988 tmp = ((xmlAttrPtr) node)->children;
3989 break;
3990 case XML_ELEMENT_NODE:
3991 tmp = node->children;
3992 break;
3993 default:
3994 return(0);
3995 }
3996 while (tmp != NULL) {
3997 switch (tmp->type) {
3998 case XML_COMMENT_NODE:
3999 case XML_PI_NODE:
4000 case XML_CDATA_SECTION_NODE:
4001 case XML_TEXT_NODE:
4002 string = tmp->content;
4003 break;
4004 case XML_NAMESPACE_DECL:
4005 string = ((xmlNsPtr)tmp)->href;
4006 break;
4007 default:
4008 break;
4009 }
4010 if ((string != NULL) && (string[0] != 0)) {
4011 if (string[0] == 0)
4012 return(0);
4013 if (len == 1) {
4014 return(ret + (((unsigned int) string[0]) << 8));
4015 }
4016 if (string[1] == 0) {
4017 len = 1;
4018 ret = (unsigned int) string[0];
4019 } else {
4020 return(((unsigned int) string[0]) +
4021 (((unsigned int) string[1]) << 8));
4022 }
4023 }
4024 /*
4025 * Skip to next node
4026 */
4027 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4028 if (tmp->children->type != XML_ENTITY_DECL) {
4029 tmp = tmp->children;
4030 continue;
4031 }
4032 }
4033 if (tmp == node)
4034 break;
4035
4036 if (tmp->next != NULL) {
4037 tmp = tmp->next;
4038 continue;
4039 }
4040
4041 do {
4042 tmp = tmp->parent;
4043 if (tmp == NULL)
4044 break;
4045 if (tmp == node) {
4046 tmp = NULL;
4047 break;
4048 }
4049 if (tmp->next != NULL) {
4050 tmp = tmp->next;
4051 break;
4052 }
4053 } while (tmp != NULL);
4054 }
4055 return(ret);
4056}
4057
4058/**
4059 * xmlXPathStringHash:
4060 * @string: a string
4061 *
4062 * Function computing the beginning of the string value of the node,
4063 * used to speed up comparisons
4064 *
4065 * Returns an int usable as a hash
4066 */
4067static unsigned int
4068xmlXPathStringHash(const xmlChar * string) {
4069 if (string == NULL)
4070 return((unsigned int) 0);
4071 if (string[0] == 0)
4072 return(0);
4073 return(((unsigned int) string[0]) +
4074 (((unsigned int) string[1]) << 8));
4075}
4076
4077/**
Owen Taylor3473f882001-02-23 17:55:21 +00004078 * xmlXPathCompareNodeSetFloat:
4079 * @ctxt: the XPath Parser context
4080 * @inf: less than (1) or greater than (0)
4081 * @strict: is the comparison strict
4082 * @arg: the node set
4083 * @f: the value
4084 *
4085 * Implement the compare operation between a nodeset and a number
4086 * @ns < @val (1, 1, ...
4087 * @ns <= @val (1, 0, ...
4088 * @ns > @val (0, 1, ...
4089 * @ns >= @val (0, 0, ...
4090 *
4091 * If one object to be compared is a node-set and the other is a number,
4092 * then the comparison will be true if and only if there is a node in the
4093 * node-set such that the result of performing the comparison on the number
4094 * to be compared and on the result of converting the string-value of that
4095 * node to a number using the number function is true.
4096 *
4097 * Returns 0 or 1 depending on the results of the test.
4098 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004099static int
Owen Taylor3473f882001-02-23 17:55:21 +00004100xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4101 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4102 int i, ret = 0;
4103 xmlNodeSetPtr ns;
4104 xmlChar *str2;
4105
4106 if ((f == NULL) || (arg == NULL) ||
4107 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4108 xmlXPathFreeObject(arg);
4109 xmlXPathFreeObject(f);
4110 return(0);
4111 }
4112 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004113 if (ns != NULL) {
4114 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004115 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004116 if (str2 != NULL) {
4117 valuePush(ctxt,
4118 xmlXPathNewString(str2));
4119 xmlFree(str2);
4120 xmlXPathNumberFunction(ctxt, 1);
4121 valuePush(ctxt, xmlXPathObjectCopy(f));
4122 ret = xmlXPathCompareValues(ctxt, inf, strict);
4123 if (ret)
4124 break;
4125 }
4126 }
Owen Taylor3473f882001-02-23 17:55:21 +00004127 }
4128 xmlXPathFreeObject(arg);
4129 xmlXPathFreeObject(f);
4130 return(ret);
4131}
4132
4133/**
4134 * xmlXPathCompareNodeSetString:
4135 * @ctxt: the XPath Parser context
4136 * @inf: less than (1) or greater than (0)
4137 * @strict: is the comparison strict
4138 * @arg: the node set
4139 * @s: the value
4140 *
4141 * Implement the compare operation between a nodeset and a string
4142 * @ns < @val (1, 1, ...
4143 * @ns <= @val (1, 0, ...
4144 * @ns > @val (0, 1, ...
4145 * @ns >= @val (0, 0, ...
4146 *
4147 * If one object to be compared is a node-set and the other is a string,
4148 * then the comparison will be true if and only if there is a node in
4149 * the node-set such that the result of performing the comparison on the
4150 * string-value of the node and the other string is true.
4151 *
4152 * Returns 0 or 1 depending on the results of the test.
4153 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004154static int
Owen Taylor3473f882001-02-23 17:55:21 +00004155xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4156 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4157 int i, ret = 0;
4158 xmlNodeSetPtr ns;
4159 xmlChar *str2;
4160
4161 if ((s == NULL) || (arg == NULL) ||
4162 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4163 xmlXPathFreeObject(arg);
4164 xmlXPathFreeObject(s);
4165 return(0);
4166 }
4167 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004168 if (ns != NULL) {
4169 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004170 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004171 if (str2 != NULL) {
4172 valuePush(ctxt,
4173 xmlXPathNewString(str2));
4174 xmlFree(str2);
4175 valuePush(ctxt, xmlXPathObjectCopy(s));
4176 ret = xmlXPathCompareValues(ctxt, inf, strict);
4177 if (ret)
4178 break;
4179 }
4180 }
Owen Taylor3473f882001-02-23 17:55:21 +00004181 }
4182 xmlXPathFreeObject(arg);
4183 xmlXPathFreeObject(s);
4184 return(ret);
4185}
4186
4187/**
4188 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004189 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004190 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004191 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004192 * @arg2: the second node set object
4193 *
4194 * Implement the compare operation on nodesets:
4195 *
4196 * If both objects to be compared are node-sets, then the comparison
4197 * will be true if and only if there is a node in the first node-set
4198 * and a node in the second node-set such that the result of performing
4199 * the comparison on the string-values of the two nodes is true.
4200 * ....
4201 * When neither object to be compared is a node-set and the operator
4202 * is <=, <, >= or >, then the objects are compared by converting both
4203 * objects to numbers and comparing the numbers according to IEEE 754.
4204 * ....
4205 * The number function converts its argument to a number as follows:
4206 * - a string that consists of optional whitespace followed by an
4207 * optional minus sign followed by a Number followed by whitespace
4208 * is converted to the IEEE 754 number that is nearest (according
4209 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4210 * represented by the string; any other string is converted to NaN
4211 *
4212 * Conclusion all nodes need to be converted first to their string value
4213 * and then the comparison must be done when possible
4214 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004215static int
4216xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004217 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4218 int i, j, init = 0;
4219 double val1;
4220 double *values2;
4221 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004222 xmlNodeSetPtr ns1;
4223 xmlNodeSetPtr ns2;
4224
4225 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004226 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4227 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004228 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004229 }
Owen Taylor3473f882001-02-23 17:55:21 +00004230 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004231 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4232 xmlXPathFreeObject(arg1);
4233 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004234 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004235 }
Owen Taylor3473f882001-02-23 17:55:21 +00004236
4237 ns1 = arg1->nodesetval;
4238 ns2 = arg2->nodesetval;
4239
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004240 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004241 xmlXPathFreeObject(arg1);
4242 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004243 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004244 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004245 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004246 xmlXPathFreeObject(arg1);
4247 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004248 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004249 }
Owen Taylor3473f882001-02-23 17:55:21 +00004250
4251 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4252 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004253 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004254 xmlXPathFreeObject(arg1);
4255 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004256 return(0);
4257 }
4258 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004259 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004260 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004261 continue;
4262 for (j = 0;j < ns2->nodeNr;j++) {
4263 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004264 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004265 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004266 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004267 continue;
4268 if (inf && strict)
4269 ret = (val1 < values2[j]);
4270 else if (inf && !strict)
4271 ret = (val1 <= values2[j]);
4272 else if (!inf && strict)
4273 ret = (val1 > values2[j]);
4274 else if (!inf && !strict)
4275 ret = (val1 >= values2[j]);
4276 if (ret)
4277 break;
4278 }
4279 if (ret)
4280 break;
4281 init = 1;
4282 }
4283 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004284 xmlXPathFreeObject(arg1);
4285 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004286 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004287}
4288
4289/**
4290 * xmlXPathCompareNodeSetValue:
4291 * @ctxt: the XPath Parser context
4292 * @inf: less than (1) or greater than (0)
4293 * @strict: is the comparison strict
4294 * @arg: the node set
4295 * @val: the value
4296 *
4297 * Implement the compare operation between a nodeset and a value
4298 * @ns < @val (1, 1, ...
4299 * @ns <= @val (1, 0, ...
4300 * @ns > @val (0, 1, ...
4301 * @ns >= @val (0, 0, ...
4302 *
4303 * If one object to be compared is a node-set and the other is a boolean,
4304 * then the comparison will be true if and only if the result of performing
4305 * the comparison on the boolean and on the result of converting
4306 * the node-set to a boolean using the boolean function is true.
4307 *
4308 * Returns 0 or 1 depending on the results of the test.
4309 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004310static int
Owen Taylor3473f882001-02-23 17:55:21 +00004311xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4312 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4313 if ((val == NULL) || (arg == NULL) ||
4314 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4315 return(0);
4316
4317 switch(val->type) {
4318 case XPATH_NUMBER:
4319 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4320 case XPATH_NODESET:
4321 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004322 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004323 case XPATH_STRING:
4324 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4325 case XPATH_BOOLEAN:
4326 valuePush(ctxt, arg);
4327 xmlXPathBooleanFunction(ctxt, 1);
4328 valuePush(ctxt, val);
4329 return(xmlXPathCompareValues(ctxt, inf, strict));
4330 default:
4331 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004332 }
4333 return(0);
4334}
4335
4336/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004337 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004338 * @arg: the nodeset object argument
4339 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004340 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004341 *
4342 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4343 * If one object to be compared is a node-set and the other is a string,
4344 * then the comparison will be true if and only if there is a node in
4345 * the node-set such that the result of performing the comparison on the
4346 * string-value of the node and the other string is true.
4347 *
4348 * Returns 0 or 1 depending on the results of the test.
4349 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004350static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004351xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004352{
Owen Taylor3473f882001-02-23 17:55:21 +00004353 int i;
4354 xmlNodeSetPtr ns;
4355 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004356 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004357
4358 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004359 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4360 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004361 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004362 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004363 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004364 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004365 if (ns->nodeNr <= 0) {
4366 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004367 return(neq ^ 1);
4368 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004369 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004370 for (i = 0; i < ns->nodeNr; i++) {
4371 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4372 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4373 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4374 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004375 if (neq)
4376 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004377 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004378 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4379 if (neq)
4380 continue;
4381 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004382 } else if (neq) {
4383 if (str2 != NULL)
4384 xmlFree(str2);
4385 return (1);
4386 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004387 if (str2 != NULL)
4388 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004389 } else if (neq)
4390 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004391 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004392 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004393}
4394
4395/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004396 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004397 * @arg: the nodeset object argument
4398 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004399 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004400 *
4401 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4402 * If one object to be compared is a node-set and the other is a number,
4403 * then the comparison will be true if and only if there is a node in
4404 * the node-set such that the result of performing the comparison on the
4405 * number to be compared and on the result of converting the string-value
4406 * of that node to a number using the number function is true.
4407 *
4408 * Returns 0 or 1 depending on the results of the test.
4409 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004410static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004411xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4412 xmlXPathObjectPtr arg, double f, int neq) {
4413 int i, ret=0;
4414 xmlNodeSetPtr ns;
4415 xmlChar *str2;
4416 xmlXPathObjectPtr val;
4417 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004418
4419 if ((arg == NULL) ||
4420 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4421 return(0);
4422
William M. Brack0c022ad2002-07-12 00:56:01 +00004423 ns = arg->nodesetval;
4424 if (ns != NULL) {
4425 for (i=0;i<ns->nodeNr;i++) {
4426 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4427 if (str2 != NULL) {
4428 valuePush(ctxt, xmlXPathNewString(str2));
4429 xmlFree(str2);
4430 xmlXPathNumberFunction(ctxt, 1);
4431 val = valuePop(ctxt);
4432 v = val->floatval;
4433 xmlXPathFreeObject(val);
4434 if (!xmlXPathIsNaN(v)) {
4435 if ((!neq) && (v==f)) {
4436 ret = 1;
4437 break;
4438 } else if ((neq) && (v!=f)) {
4439 ret = 1;
4440 break;
4441 }
4442 }
4443 }
4444 }
4445 }
4446
4447 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004448}
4449
4450
4451/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004452 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004453 * @arg1: first nodeset object argument
4454 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004455 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004456 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004457 * Implement the equal / not equal operation on XPath nodesets:
4458 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004459 * If both objects to be compared are node-sets, then the comparison
4460 * will be true if and only if there is a node in the first node-set and
4461 * a node in the second node-set such that the result of performing the
4462 * comparison on the string-values of the two nodes is true.
4463 *
4464 * (needless to say, this is a costly operation)
4465 *
4466 * Returns 0 or 1 depending on the results of the test.
4467 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004468static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004469xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004470 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004471 unsigned int *hashs1;
4472 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004473 xmlChar **values1;
4474 xmlChar **values2;
4475 int ret = 0;
4476 xmlNodeSetPtr ns1;
4477 xmlNodeSetPtr ns2;
4478
4479 if ((arg1 == NULL) ||
4480 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4481 return(0);
4482 if ((arg2 == NULL) ||
4483 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4484 return(0);
4485
4486 ns1 = arg1->nodesetval;
4487 ns2 = arg2->nodesetval;
4488
Daniel Veillard911f49a2001-04-07 15:39:35 +00004489 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004490 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004491 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004492 return(0);
4493
4494 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004495 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004496 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004497 if (neq == 0)
4498 for (i = 0;i < ns1->nodeNr;i++)
4499 for (j = 0;j < ns2->nodeNr;j++)
4500 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4501 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004502
4503 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004504 if (values1 == NULL) {
4505 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004506 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004507 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004508 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4509 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004510 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004511 xmlFree(values1);
4512 return(0);
4513 }
Owen Taylor3473f882001-02-23 17:55:21 +00004514 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4515 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4516 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004517 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004518 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004519 xmlFree(values1);
4520 return(0);
4521 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004522 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4523 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004524 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004525 xmlFree(hashs1);
4526 xmlFree(values1);
4527 xmlFree(values2);
4528 return(0);
4529 }
Owen Taylor3473f882001-02-23 17:55:21 +00004530 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4531 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004532 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004533 for (j = 0;j < ns2->nodeNr;j++) {
4534 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004535 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004536 if (hashs1[i] != hashs2[j]) {
4537 if (neq) {
4538 ret = 1;
4539 break;
4540 }
4541 }
4542 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004543 if (values1[i] == NULL)
4544 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4545 if (values2[j] == NULL)
4546 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004547 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004548 if (ret)
4549 break;
4550 }
Owen Taylor3473f882001-02-23 17:55:21 +00004551 }
4552 if (ret)
4553 break;
4554 }
4555 for (i = 0;i < ns1->nodeNr;i++)
4556 if (values1[i] != NULL)
4557 xmlFree(values1[i]);
4558 for (j = 0;j < ns2->nodeNr;j++)
4559 if (values2[j] != NULL)
4560 xmlFree(values2[j]);
4561 xmlFree(values1);
4562 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004563 xmlFree(hashs1);
4564 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004565 return(ret);
4566}
4567
William M. Brack0c022ad2002-07-12 00:56:01 +00004568static int
4569xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4570 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004571 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004572 /*
4573 *At this point we are assured neither arg1 nor arg2
4574 *is a nodeset, so we can just pick the appropriate routine.
4575 */
Owen Taylor3473f882001-02-23 17:55:21 +00004576 switch (arg1->type) {
4577 case XPATH_UNDEFINED:
4578#ifdef DEBUG_EXPR
4579 xmlGenericError(xmlGenericErrorContext,
4580 "Equal: undefined\n");
4581#endif
4582 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004583 case XPATH_BOOLEAN:
4584 switch (arg2->type) {
4585 case XPATH_UNDEFINED:
4586#ifdef DEBUG_EXPR
4587 xmlGenericError(xmlGenericErrorContext,
4588 "Equal: undefined\n");
4589#endif
4590 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004591 case XPATH_BOOLEAN:
4592#ifdef DEBUG_EXPR
4593 xmlGenericError(xmlGenericErrorContext,
4594 "Equal: %d boolean %d \n",
4595 arg1->boolval, arg2->boolval);
4596#endif
4597 ret = (arg1->boolval == arg2->boolval);
4598 break;
4599 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004600 ret = (arg1->boolval ==
4601 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004602 break;
4603 case XPATH_STRING:
4604 if ((arg2->stringval == NULL) ||
4605 (arg2->stringval[0] == 0)) ret = 0;
4606 else
4607 ret = 1;
4608 ret = (arg1->boolval == ret);
4609 break;
4610 case XPATH_USERS:
4611 case XPATH_POINT:
4612 case XPATH_RANGE:
4613 case XPATH_LOCATIONSET:
4614 TODO
4615 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004616 case XPATH_NODESET:
4617 case XPATH_XSLT_TREE:
4618 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004619 }
4620 break;
4621 case XPATH_NUMBER:
4622 switch (arg2->type) {
4623 case XPATH_UNDEFINED:
4624#ifdef DEBUG_EXPR
4625 xmlGenericError(xmlGenericErrorContext,
4626 "Equal: undefined\n");
4627#endif
4628 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004629 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004630 ret = (arg2->boolval==
4631 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004632 break;
4633 case XPATH_STRING:
4634 valuePush(ctxt, arg2);
4635 xmlXPathNumberFunction(ctxt, 1);
4636 arg2 = valuePop(ctxt);
4637 /* no break on purpose */
4638 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004639 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004640 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4641 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004642 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4643 if (xmlXPathIsInf(arg2->floatval) == 1)
4644 ret = 1;
4645 else
4646 ret = 0;
4647 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4648 if (xmlXPathIsInf(arg2->floatval) == -1)
4649 ret = 1;
4650 else
4651 ret = 0;
4652 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4653 if (xmlXPathIsInf(arg1->floatval) == 1)
4654 ret = 1;
4655 else
4656 ret = 0;
4657 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4658 if (xmlXPathIsInf(arg1->floatval) == -1)
4659 ret = 1;
4660 else
4661 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004662 } else {
4663 ret = (arg1->floatval == arg2->floatval);
4664 }
Owen Taylor3473f882001-02-23 17:55:21 +00004665 break;
4666 case XPATH_USERS:
4667 case XPATH_POINT:
4668 case XPATH_RANGE:
4669 case XPATH_LOCATIONSET:
4670 TODO
4671 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004672 case XPATH_NODESET:
4673 case XPATH_XSLT_TREE:
4674 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004675 }
4676 break;
4677 case XPATH_STRING:
4678 switch (arg2->type) {
4679 case XPATH_UNDEFINED:
4680#ifdef DEBUG_EXPR
4681 xmlGenericError(xmlGenericErrorContext,
4682 "Equal: undefined\n");
4683#endif
4684 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004685 case XPATH_BOOLEAN:
4686 if ((arg1->stringval == NULL) ||
4687 (arg1->stringval[0] == 0)) ret = 0;
4688 else
4689 ret = 1;
4690 ret = (arg2->boolval == ret);
4691 break;
4692 case XPATH_STRING:
4693 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4694 break;
4695 case XPATH_NUMBER:
4696 valuePush(ctxt, arg1);
4697 xmlXPathNumberFunction(ctxt, 1);
4698 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004699 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004700 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4701 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004702 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4703 if (xmlXPathIsInf(arg2->floatval) == 1)
4704 ret = 1;
4705 else
4706 ret = 0;
4707 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4708 if (xmlXPathIsInf(arg2->floatval) == -1)
4709 ret = 1;
4710 else
4711 ret = 0;
4712 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4713 if (xmlXPathIsInf(arg1->floatval) == 1)
4714 ret = 1;
4715 else
4716 ret = 0;
4717 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4718 if (xmlXPathIsInf(arg1->floatval) == -1)
4719 ret = 1;
4720 else
4721 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004722 } else {
4723 ret = (arg1->floatval == arg2->floatval);
4724 }
Owen Taylor3473f882001-02-23 17:55:21 +00004725 break;
4726 case XPATH_USERS:
4727 case XPATH_POINT:
4728 case XPATH_RANGE:
4729 case XPATH_LOCATIONSET:
4730 TODO
4731 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004732 case XPATH_NODESET:
4733 case XPATH_XSLT_TREE:
4734 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004735 }
4736 break;
4737 case XPATH_USERS:
4738 case XPATH_POINT:
4739 case XPATH_RANGE:
4740 case XPATH_LOCATIONSET:
4741 TODO
4742 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004743 case XPATH_NODESET:
4744 case XPATH_XSLT_TREE:
4745 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004746 }
4747 xmlXPathFreeObject(arg1);
4748 xmlXPathFreeObject(arg2);
4749 return(ret);
4750}
4751
William M. Brack0c022ad2002-07-12 00:56:01 +00004752/**
4753 * xmlXPathEqualValues:
4754 * @ctxt: the XPath Parser context
4755 *
4756 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4757 *
4758 * Returns 0 or 1 depending on the results of the test.
4759 */
4760int
4761xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4762 xmlXPathObjectPtr arg1, arg2, argtmp;
4763 int ret = 0;
4764
4765 arg2 = valuePop(ctxt);
4766 arg1 = valuePop(ctxt);
4767 if ((arg1 == NULL) || (arg2 == NULL)) {
4768 if (arg1 != NULL)
4769 xmlXPathFreeObject(arg1);
4770 else
4771 xmlXPathFreeObject(arg2);
4772 XP_ERROR0(XPATH_INVALID_OPERAND);
4773 }
4774
4775 if (arg1 == arg2) {
4776#ifdef DEBUG_EXPR
4777 xmlGenericError(xmlGenericErrorContext,
4778 "Equal: by pointer\n");
4779#endif
4780 return(1);
4781 }
4782
4783 /*
4784 *If either argument is a nodeset, it's a 'special case'
4785 */
4786 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4787 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4788 /*
4789 *Hack it to assure arg1 is the nodeset
4790 */
4791 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4792 argtmp = arg2;
4793 arg2 = arg1;
4794 arg1 = argtmp;
4795 }
4796 switch (arg2->type) {
4797 case XPATH_UNDEFINED:
4798#ifdef DEBUG_EXPR
4799 xmlGenericError(xmlGenericErrorContext,
4800 "Equal: undefined\n");
4801#endif
4802 break;
4803 case XPATH_NODESET:
4804 case XPATH_XSLT_TREE:
4805 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4806 break;
4807 case XPATH_BOOLEAN:
4808 if ((arg1->nodesetval == NULL) ||
4809 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4810 else
4811 ret = 1;
4812 ret = (ret == arg2->boolval);
4813 break;
4814 case XPATH_NUMBER:
4815 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4816 break;
4817 case XPATH_STRING:
4818 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4819 break;
4820 case XPATH_USERS:
4821 case XPATH_POINT:
4822 case XPATH_RANGE:
4823 case XPATH_LOCATIONSET:
4824 TODO
4825 break;
4826 }
4827 xmlXPathFreeObject(arg1);
4828 xmlXPathFreeObject(arg2);
4829 return(ret);
4830 }
4831
4832 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4833}
4834
4835/**
4836 * xmlXPathNotEqualValues:
4837 * @ctxt: the XPath Parser context
4838 *
4839 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4840 *
4841 * Returns 0 or 1 depending on the results of the test.
4842 */
4843int
4844xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4845 xmlXPathObjectPtr arg1, arg2, argtmp;
4846 int ret = 0;
4847
4848 arg2 = valuePop(ctxt);
4849 arg1 = valuePop(ctxt);
4850 if ((arg1 == NULL) || (arg2 == NULL)) {
4851 if (arg1 != NULL)
4852 xmlXPathFreeObject(arg1);
4853 else
4854 xmlXPathFreeObject(arg2);
4855 XP_ERROR0(XPATH_INVALID_OPERAND);
4856 }
4857
4858 if (arg1 == arg2) {
4859#ifdef DEBUG_EXPR
4860 xmlGenericError(xmlGenericErrorContext,
4861 "NotEqual: by pointer\n");
4862#endif
4863 return(0);
4864 }
4865
4866 /*
4867 *If either argument is a nodeset, it's a 'special case'
4868 */
4869 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4870 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4871 /*
4872 *Hack it to assure arg1 is the nodeset
4873 */
4874 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4875 argtmp = arg2;
4876 arg2 = arg1;
4877 arg1 = argtmp;
4878 }
4879 switch (arg2->type) {
4880 case XPATH_UNDEFINED:
4881#ifdef DEBUG_EXPR
4882 xmlGenericError(xmlGenericErrorContext,
4883 "NotEqual: undefined\n");
4884#endif
4885 break;
4886 case XPATH_NODESET:
4887 case XPATH_XSLT_TREE:
4888 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4889 break;
4890 case XPATH_BOOLEAN:
4891 if ((arg1->nodesetval == NULL) ||
4892 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4893 else
4894 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004895 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004896 break;
4897 case XPATH_NUMBER:
4898 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4899 break;
4900 case XPATH_STRING:
4901 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4902 break;
4903 case XPATH_USERS:
4904 case XPATH_POINT:
4905 case XPATH_RANGE:
4906 case XPATH_LOCATIONSET:
4907 TODO
4908 break;
4909 }
4910 xmlXPathFreeObject(arg1);
4911 xmlXPathFreeObject(arg2);
4912 return(ret);
4913 }
4914
4915 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4916}
Owen Taylor3473f882001-02-23 17:55:21 +00004917
4918/**
4919 * xmlXPathCompareValues:
4920 * @ctxt: the XPath Parser context
4921 * @inf: less than (1) or greater than (0)
4922 * @strict: is the comparison strict
4923 *
4924 * Implement the compare operation on XPath objects:
4925 * @arg1 < @arg2 (1, 1, ...
4926 * @arg1 <= @arg2 (1, 0, ...
4927 * @arg1 > @arg2 (0, 1, ...
4928 * @arg1 >= @arg2 (0, 0, ...
4929 *
4930 * When neither object to be compared is a node-set and the operator is
4931 * <=, <, >=, >, then the objects are compared by converted both objects
4932 * to numbers and comparing the numbers according to IEEE 754. The <
4933 * comparison will be true if and only if the first number is less than the
4934 * second number. The <= comparison will be true if and only if the first
4935 * number is less than or equal to the second number. The > comparison
4936 * will be true if and only if the first number is greater than the second
4937 * number. The >= comparison will be true if and only if the first number
4938 * is greater than or equal to the second number.
4939 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004940 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004941 */
4942int
4943xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004944 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004945 xmlXPathObjectPtr arg1, arg2;
4946
William M. Brack0c022ad2002-07-12 00:56:01 +00004947 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004948 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004949 if ((arg1 == NULL) || (arg2 == NULL)) {
4950 if (arg1 != NULL)
4951 xmlXPathFreeObject(arg1);
4952 else
4953 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004954 XP_ERROR0(XPATH_INVALID_OPERAND);
4955 }
4956
William M. Brack0c022ad2002-07-12 00:56:01 +00004957 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4958 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4959 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4960 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004961 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004962 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004963 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004964 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4965 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004966 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004967 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4968 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004969 }
4970 }
4971 return(ret);
4972 }
4973
4974 if (arg1->type != XPATH_NUMBER) {
4975 valuePush(ctxt, arg1);
4976 xmlXPathNumberFunction(ctxt, 1);
4977 arg1 = valuePop(ctxt);
4978 }
4979 if (arg1->type != XPATH_NUMBER) {
4980 xmlXPathFreeObject(arg1);
4981 xmlXPathFreeObject(arg2);
4982 XP_ERROR0(XPATH_INVALID_OPERAND);
4983 }
4984 if (arg2->type != XPATH_NUMBER) {
4985 valuePush(ctxt, arg2);
4986 xmlXPathNumberFunction(ctxt, 1);
4987 arg2 = valuePop(ctxt);
4988 }
4989 if (arg2->type != XPATH_NUMBER) {
4990 xmlXPathFreeObject(arg1);
4991 xmlXPathFreeObject(arg2);
4992 XP_ERROR0(XPATH_INVALID_OPERAND);
4993 }
4994 /*
4995 * Add tests for infinity and nan
4996 * => feedback on 3.4 for Inf and NaN
4997 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004998 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004999 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005000 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005001 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005002 arg1i=xmlXPathIsInf(arg1->floatval);
5003 arg2i=xmlXPathIsInf(arg2->floatval);
5004 if (inf && strict) {
5005 if ((arg1i == -1 && arg2i != -1) ||
5006 (arg2i == 1 && arg1i != 1)) {
5007 ret = 1;
5008 } else if (arg1i == 0 && arg2i == 0) {
5009 ret = (arg1->floatval < arg2->floatval);
5010 } else {
5011 ret = 0;
5012 }
5013 }
5014 else if (inf && !strict) {
5015 if (arg1i == -1 || arg2i == 1) {
5016 ret = 1;
5017 } else if (arg1i == 0 && arg2i == 0) {
5018 ret = (arg1->floatval <= arg2->floatval);
5019 } else {
5020 ret = 0;
5021 }
5022 }
5023 else if (!inf && strict) {
5024 if ((arg1i == 1 && arg2i != 1) ||
5025 (arg2i == -1 && arg1i != -1)) {
5026 ret = 1;
5027 } else if (arg1i == 0 && arg2i == 0) {
5028 ret = (arg1->floatval > arg2->floatval);
5029 } else {
5030 ret = 0;
5031 }
5032 }
5033 else if (!inf && !strict) {
5034 if (arg1i == 1 || arg2i == -1) {
5035 ret = 1;
5036 } else if (arg1i == 0 && arg2i == 0) {
5037 ret = (arg1->floatval >= arg2->floatval);
5038 } else {
5039 ret = 0;
5040 }
5041 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005042 }
Owen Taylor3473f882001-02-23 17:55:21 +00005043 xmlXPathFreeObject(arg1);
5044 xmlXPathFreeObject(arg2);
5045 return(ret);
5046}
5047
5048/**
5049 * xmlXPathValueFlipSign:
5050 * @ctxt: the XPath Parser context
5051 *
5052 * Implement the unary - operation on an XPath object
5053 * The numeric operators convert their operands to numbers as if
5054 * by calling the number function.
5055 */
5056void
5057xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005058 CAST_TO_NUMBER;
5059 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005060 if (xmlXPathIsNaN(ctxt->value->floatval))
5061 ctxt->value->floatval=xmlXPathNAN;
5062 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5063 ctxt->value->floatval=xmlXPathNINF;
5064 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5065 ctxt->value->floatval=xmlXPathPINF;
5066 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005067 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5068 ctxt->value->floatval = xmlXPathNZERO;
5069 else
5070 ctxt->value->floatval = 0;
5071 }
5072 else
5073 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005074}
5075
5076/**
5077 * xmlXPathAddValues:
5078 * @ctxt: the XPath Parser context
5079 *
5080 * Implement the add operation on XPath objects:
5081 * The numeric operators convert their operands to numbers as if
5082 * by calling the number function.
5083 */
5084void
5085xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5086 xmlXPathObjectPtr arg;
5087 double val;
5088
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005089 arg = valuePop(ctxt);
5090 if (arg == NULL)
5091 XP_ERROR(XPATH_INVALID_OPERAND);
5092 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005093 xmlXPathFreeObject(arg);
5094
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005095 CAST_TO_NUMBER;
5096 CHECK_TYPE(XPATH_NUMBER);
5097 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005098}
5099
5100/**
5101 * xmlXPathSubValues:
5102 * @ctxt: the XPath Parser context
5103 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005104 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005105 * The numeric operators convert their operands to numbers as if
5106 * by calling the number function.
5107 */
5108void
5109xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5110 xmlXPathObjectPtr arg;
5111 double val;
5112
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005113 arg = valuePop(ctxt);
5114 if (arg == NULL)
5115 XP_ERROR(XPATH_INVALID_OPERAND);
5116 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005117 xmlXPathFreeObject(arg);
5118
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005119 CAST_TO_NUMBER;
5120 CHECK_TYPE(XPATH_NUMBER);
5121 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005122}
5123
5124/**
5125 * xmlXPathMultValues:
5126 * @ctxt: the XPath Parser context
5127 *
5128 * Implement the multiply operation on XPath objects:
5129 * The numeric operators convert their operands to numbers as if
5130 * by calling the number function.
5131 */
5132void
5133xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5134 xmlXPathObjectPtr arg;
5135 double val;
5136
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005137 arg = valuePop(ctxt);
5138 if (arg == NULL)
5139 XP_ERROR(XPATH_INVALID_OPERAND);
5140 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005141 xmlXPathFreeObject(arg);
5142
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005143 CAST_TO_NUMBER;
5144 CHECK_TYPE(XPATH_NUMBER);
5145 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005146}
5147
5148/**
5149 * xmlXPathDivValues:
5150 * @ctxt: the XPath Parser context
5151 *
5152 * Implement the div operation on XPath objects @arg1 / @arg2:
5153 * The numeric operators convert their operands to numbers as if
5154 * by calling the number function.
5155 */
5156void
5157xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5158 xmlXPathObjectPtr arg;
5159 double val;
5160
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005161 arg = valuePop(ctxt);
5162 if (arg == NULL)
5163 XP_ERROR(XPATH_INVALID_OPERAND);
5164 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005165 xmlXPathFreeObject(arg);
5166
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005167 CAST_TO_NUMBER;
5168 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005169 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5170 ctxt->value->floatval = xmlXPathNAN;
5171 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005172 if (ctxt->value->floatval == 0)
5173 ctxt->value->floatval = xmlXPathNAN;
5174 else if (ctxt->value->floatval > 0)
5175 ctxt->value->floatval = xmlXPathNINF;
5176 else if (ctxt->value->floatval < 0)
5177 ctxt->value->floatval = xmlXPathPINF;
5178 }
5179 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005180 if (ctxt->value->floatval == 0)
5181 ctxt->value->floatval = xmlXPathNAN;
5182 else if (ctxt->value->floatval > 0)
5183 ctxt->value->floatval = xmlXPathPINF;
5184 else if (ctxt->value->floatval < 0)
5185 ctxt->value->floatval = xmlXPathNINF;
5186 } else
5187 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005188}
5189
5190/**
5191 * xmlXPathModValues:
5192 * @ctxt: the XPath Parser context
5193 *
5194 * Implement the mod operation on XPath objects: @arg1 / @arg2
5195 * The numeric operators convert their operands to numbers as if
5196 * by calling the number function.
5197 */
5198void
5199xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5200 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005201 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005202
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005203 arg = valuePop(ctxt);
5204 if (arg == NULL)
5205 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005206 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005207 xmlXPathFreeObject(arg);
5208
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005209 CAST_TO_NUMBER;
5210 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005211 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005212 if (arg2 == 0)
5213 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005214 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005215 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005216 }
Owen Taylor3473f882001-02-23 17:55:21 +00005217}
5218
5219/************************************************************************
5220 * *
5221 * The traversal functions *
5222 * *
5223 ************************************************************************/
5224
Owen Taylor3473f882001-02-23 17:55:21 +00005225/*
5226 * A traversal function enumerates nodes along an axis.
5227 * Initially it must be called with NULL, and it indicates
5228 * termination on the axis by returning NULL.
5229 */
5230typedef xmlNodePtr (*xmlXPathTraversalFunction)
5231 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5232
5233/**
5234 * xmlXPathNextSelf:
5235 * @ctxt: the XPath Parser context
5236 * @cur: the current node in the traversal
5237 *
5238 * Traversal function for the "self" direction
5239 * The self axis contains just the context node itself
5240 *
5241 * Returns the next element following that axis
5242 */
5243xmlNodePtr
5244xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5245 if (cur == NULL)
5246 return(ctxt->context->node);
5247 return(NULL);
5248}
5249
5250/**
5251 * xmlXPathNextChild:
5252 * @ctxt: the XPath Parser context
5253 * @cur: the current node in the traversal
5254 *
5255 * Traversal function for the "child" direction
5256 * The child axis contains the children of the context node in document order.
5257 *
5258 * Returns the next element following that axis
5259 */
5260xmlNodePtr
5261xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5262 if (cur == NULL) {
5263 if (ctxt->context->node == NULL) return(NULL);
5264 switch (ctxt->context->node->type) {
5265 case XML_ELEMENT_NODE:
5266 case XML_TEXT_NODE:
5267 case XML_CDATA_SECTION_NODE:
5268 case XML_ENTITY_REF_NODE:
5269 case XML_ENTITY_NODE:
5270 case XML_PI_NODE:
5271 case XML_COMMENT_NODE:
5272 case XML_NOTATION_NODE:
5273 case XML_DTD_NODE:
5274 return(ctxt->context->node->children);
5275 case XML_DOCUMENT_NODE:
5276 case XML_DOCUMENT_TYPE_NODE:
5277 case XML_DOCUMENT_FRAG_NODE:
5278 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005279#ifdef LIBXML_DOCB_ENABLED
5280 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005281#endif
5282 return(((xmlDocPtr) ctxt->context->node)->children);
5283 case XML_ELEMENT_DECL:
5284 case XML_ATTRIBUTE_DECL:
5285 case XML_ENTITY_DECL:
5286 case XML_ATTRIBUTE_NODE:
5287 case XML_NAMESPACE_DECL:
5288 case XML_XINCLUDE_START:
5289 case XML_XINCLUDE_END:
5290 return(NULL);
5291 }
5292 return(NULL);
5293 }
5294 if ((cur->type == XML_DOCUMENT_NODE) ||
5295 (cur->type == XML_HTML_DOCUMENT_NODE))
5296 return(NULL);
5297 return(cur->next);
5298}
5299
5300/**
5301 * xmlXPathNextDescendant:
5302 * @ctxt: the XPath Parser context
5303 * @cur: the current node in the traversal
5304 *
5305 * Traversal function for the "descendant" direction
5306 * the descendant axis contains the descendants of the context node in document
5307 * order; a descendant is a child or a child of a child and so on.
5308 *
5309 * Returns the next element following that axis
5310 */
5311xmlNodePtr
5312xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5313 if (cur == NULL) {
5314 if (ctxt->context->node == NULL)
5315 return(NULL);
5316 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5317 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5318 return(NULL);
5319
5320 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5321 return(ctxt->context->doc->children);
5322 return(ctxt->context->node->children);
5323 }
5324
Daniel Veillard567e1b42001-08-01 15:53:47 +00005325 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005326 /*
5327 * Do not descend on entities declarations
5328 */
5329 if (cur->children->type != XML_ENTITY_DECL) {
5330 cur = cur->children;
5331 /*
5332 * Skip DTDs
5333 */
5334 if (cur->type != XML_DTD_NODE)
5335 return(cur);
5336 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005337 }
5338
5339 if (cur == ctxt->context->node) return(NULL);
5340
Daniel Veillard68e9e742002-11-16 15:35:11 +00005341 while (cur->next != NULL) {
5342 cur = cur->next;
5343 if ((cur->type != XML_ENTITY_DECL) &&
5344 (cur->type != XML_DTD_NODE))
5345 return(cur);
5346 }
Owen Taylor3473f882001-02-23 17:55:21 +00005347
5348 do {
5349 cur = cur->parent;
5350 if (cur == NULL) return(NULL);
5351 if (cur == ctxt->context->node) return(NULL);
5352 if (cur->next != NULL) {
5353 cur = cur->next;
5354 return(cur);
5355 }
5356 } while (cur != NULL);
5357 return(cur);
5358}
5359
5360/**
5361 * xmlXPathNextDescendantOrSelf:
5362 * @ctxt: the XPath Parser context
5363 * @cur: the current node in the traversal
5364 *
5365 * Traversal function for the "descendant-or-self" direction
5366 * the descendant-or-self axis contains the context node and the descendants
5367 * of the context node in document order; thus the context node is the first
5368 * node on the axis, and the first child of the context node is the second node
5369 * on the axis
5370 *
5371 * Returns the next element following that axis
5372 */
5373xmlNodePtr
5374xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5375 if (cur == NULL) {
5376 if (ctxt->context->node == NULL)
5377 return(NULL);
5378 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5379 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5380 return(NULL);
5381 return(ctxt->context->node);
5382 }
5383
5384 return(xmlXPathNextDescendant(ctxt, cur));
5385}
5386
5387/**
5388 * xmlXPathNextParent:
5389 * @ctxt: the XPath Parser context
5390 * @cur: the current node in the traversal
5391 *
5392 * Traversal function for the "parent" direction
5393 * The parent axis contains the parent of the context node, if there is one.
5394 *
5395 * Returns the next element following that axis
5396 */
5397xmlNodePtr
5398xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5399 /*
5400 * the parent of an attribute or namespace node is the element
5401 * to which the attribute or namespace node is attached
5402 * Namespace handling !!!
5403 */
5404 if (cur == NULL) {
5405 if (ctxt->context->node == NULL) return(NULL);
5406 switch (ctxt->context->node->type) {
5407 case XML_ELEMENT_NODE:
5408 case XML_TEXT_NODE:
5409 case XML_CDATA_SECTION_NODE:
5410 case XML_ENTITY_REF_NODE:
5411 case XML_ENTITY_NODE:
5412 case XML_PI_NODE:
5413 case XML_COMMENT_NODE:
5414 case XML_NOTATION_NODE:
5415 case XML_DTD_NODE:
5416 case XML_ELEMENT_DECL:
5417 case XML_ATTRIBUTE_DECL:
5418 case XML_XINCLUDE_START:
5419 case XML_XINCLUDE_END:
5420 case XML_ENTITY_DECL:
5421 if (ctxt->context->node->parent == NULL)
5422 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005423 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005424 ((ctxt->context->node->parent->name[0] == ' ') ||
5425 (xmlStrEqual(ctxt->context->node->parent->name,
5426 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005427 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005428 return(ctxt->context->node->parent);
5429 case XML_ATTRIBUTE_NODE: {
5430 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5431
5432 return(att->parent);
5433 }
5434 case XML_DOCUMENT_NODE:
5435 case XML_DOCUMENT_TYPE_NODE:
5436 case XML_DOCUMENT_FRAG_NODE:
5437 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005438#ifdef LIBXML_DOCB_ENABLED
5439 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005440#endif
5441 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005442 case XML_NAMESPACE_DECL: {
5443 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5444
5445 if ((ns->next != NULL) &&
5446 (ns->next->type != XML_NAMESPACE_DECL))
5447 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005448 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005449 }
Owen Taylor3473f882001-02-23 17:55:21 +00005450 }
5451 }
5452 return(NULL);
5453}
5454
5455/**
5456 * xmlXPathNextAncestor:
5457 * @ctxt: the XPath Parser context
5458 * @cur: the current node in the traversal
5459 *
5460 * Traversal function for the "ancestor" direction
5461 * the ancestor axis contains the ancestors of the context node; the ancestors
5462 * of the context node consist of the parent of context node and the parent's
5463 * parent and so on; the nodes are ordered in reverse document order; thus the
5464 * parent is the first node on the axis, and the parent's parent is the second
5465 * node on the axis
5466 *
5467 * Returns the next element following that axis
5468 */
5469xmlNodePtr
5470xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5471 /*
5472 * the parent of an attribute or namespace node is the element
5473 * to which the attribute or namespace node is attached
5474 * !!!!!!!!!!!!!
5475 */
5476 if (cur == NULL) {
5477 if (ctxt->context->node == NULL) return(NULL);
5478 switch (ctxt->context->node->type) {
5479 case XML_ELEMENT_NODE:
5480 case XML_TEXT_NODE:
5481 case XML_CDATA_SECTION_NODE:
5482 case XML_ENTITY_REF_NODE:
5483 case XML_ENTITY_NODE:
5484 case XML_PI_NODE:
5485 case XML_COMMENT_NODE:
5486 case XML_DTD_NODE:
5487 case XML_ELEMENT_DECL:
5488 case XML_ATTRIBUTE_DECL:
5489 case XML_ENTITY_DECL:
5490 case XML_NOTATION_NODE:
5491 case XML_XINCLUDE_START:
5492 case XML_XINCLUDE_END:
5493 if (ctxt->context->node->parent == NULL)
5494 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005495 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005496 ((ctxt->context->node->parent->name[0] == ' ') ||
5497 (xmlStrEqual(ctxt->context->node->parent->name,
5498 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005499 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005500 return(ctxt->context->node->parent);
5501 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005502 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005503
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005504 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005505 }
5506 case XML_DOCUMENT_NODE:
5507 case XML_DOCUMENT_TYPE_NODE:
5508 case XML_DOCUMENT_FRAG_NODE:
5509 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005510#ifdef LIBXML_DOCB_ENABLED
5511 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005512#endif
5513 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005514 case XML_NAMESPACE_DECL: {
5515 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5516
5517 if ((ns->next != NULL) &&
5518 (ns->next->type != XML_NAMESPACE_DECL))
5519 return((xmlNodePtr) ns->next);
5520 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005521 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005522 }
Owen Taylor3473f882001-02-23 17:55:21 +00005523 }
5524 return(NULL);
5525 }
5526 if (cur == ctxt->context->doc->children)
5527 return((xmlNodePtr) ctxt->context->doc);
5528 if (cur == (xmlNodePtr) ctxt->context->doc)
5529 return(NULL);
5530 switch (cur->type) {
5531 case XML_ELEMENT_NODE:
5532 case XML_TEXT_NODE:
5533 case XML_CDATA_SECTION_NODE:
5534 case XML_ENTITY_REF_NODE:
5535 case XML_ENTITY_NODE:
5536 case XML_PI_NODE:
5537 case XML_COMMENT_NODE:
5538 case XML_NOTATION_NODE:
5539 case XML_DTD_NODE:
5540 case XML_ELEMENT_DECL:
5541 case XML_ATTRIBUTE_DECL:
5542 case XML_ENTITY_DECL:
5543 case XML_XINCLUDE_START:
5544 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005545 if (cur->parent == NULL)
5546 return(NULL);
5547 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005548 ((cur->parent->name[0] == ' ') ||
5549 (xmlStrEqual(cur->parent->name,
5550 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005551 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005552 return(cur->parent);
5553 case XML_ATTRIBUTE_NODE: {
5554 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5555
5556 return(att->parent);
5557 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005558 case XML_NAMESPACE_DECL: {
5559 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5560
5561 if ((ns->next != NULL) &&
5562 (ns->next->type != XML_NAMESPACE_DECL))
5563 return((xmlNodePtr) ns->next);
5564 /* Bad, how did that namespace ended-up there ? */
5565 return(NULL);
5566 }
Owen Taylor3473f882001-02-23 17:55:21 +00005567 case XML_DOCUMENT_NODE:
5568 case XML_DOCUMENT_TYPE_NODE:
5569 case XML_DOCUMENT_FRAG_NODE:
5570 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005571#ifdef LIBXML_DOCB_ENABLED
5572 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005573#endif
5574 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005575 }
5576 return(NULL);
5577}
5578
5579/**
5580 * xmlXPathNextAncestorOrSelf:
5581 * @ctxt: the XPath Parser context
5582 * @cur: the current node in the traversal
5583 *
5584 * Traversal function for the "ancestor-or-self" direction
5585 * he ancestor-or-self axis contains the context node and ancestors of
5586 * the context node in reverse document order; thus the context node is
5587 * the first node on the axis, and the context node's parent the second;
5588 * parent here is defined the same as with the parent axis.
5589 *
5590 * Returns the next element following that axis
5591 */
5592xmlNodePtr
5593xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5594 if (cur == NULL)
5595 return(ctxt->context->node);
5596 return(xmlXPathNextAncestor(ctxt, cur));
5597}
5598
5599/**
5600 * xmlXPathNextFollowingSibling:
5601 * @ctxt: the XPath Parser context
5602 * @cur: the current node in the traversal
5603 *
5604 * Traversal function for the "following-sibling" direction
5605 * The following-sibling axis contains the following siblings of the context
5606 * node in document order.
5607 *
5608 * Returns the next element following that axis
5609 */
5610xmlNodePtr
5611xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5612 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5613 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5614 return(NULL);
5615 if (cur == (xmlNodePtr) ctxt->context->doc)
5616 return(NULL);
5617 if (cur == NULL)
5618 return(ctxt->context->node->next);
5619 return(cur->next);
5620}
5621
5622/**
5623 * xmlXPathNextPrecedingSibling:
5624 * @ctxt: the XPath Parser context
5625 * @cur: the current node in the traversal
5626 *
5627 * Traversal function for the "preceding-sibling" direction
5628 * The preceding-sibling axis contains the preceding siblings of the context
5629 * node in reverse document order; the first preceding sibling is first on the
5630 * axis; the sibling preceding that node is the second on the axis and so on.
5631 *
5632 * Returns the next element following that axis
5633 */
5634xmlNodePtr
5635xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5636 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5637 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5638 return(NULL);
5639 if (cur == (xmlNodePtr) ctxt->context->doc)
5640 return(NULL);
5641 if (cur == NULL)
5642 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005643 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5644 cur = cur->prev;
5645 if (cur == NULL)
5646 return(ctxt->context->node->prev);
5647 }
Owen Taylor3473f882001-02-23 17:55:21 +00005648 return(cur->prev);
5649}
5650
5651/**
5652 * xmlXPathNextFollowing:
5653 * @ctxt: the XPath Parser context
5654 * @cur: the current node in the traversal
5655 *
5656 * Traversal function for the "following" direction
5657 * The following axis contains all nodes in the same document as the context
5658 * node that are after the context node in document order, excluding any
5659 * descendants and excluding attribute nodes and namespace nodes; the nodes
5660 * are ordered in document order
5661 *
5662 * Returns the next element following that axis
5663 */
5664xmlNodePtr
5665xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5666 if (cur != NULL && cur->children != NULL)
5667 return cur->children ;
5668 if (cur == NULL) cur = ctxt->context->node;
5669 if (cur == NULL) return(NULL) ; /* ERROR */
5670 if (cur->next != NULL) return(cur->next) ;
5671 do {
5672 cur = cur->parent;
5673 if (cur == NULL) return(NULL);
5674 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5675 if (cur->next != NULL) return(cur->next);
5676 } while (cur != NULL);
5677 return(cur);
5678}
5679
5680/*
5681 * xmlXPathIsAncestor:
5682 * @ancestor: the ancestor node
5683 * @node: the current node
5684 *
5685 * Check that @ancestor is a @node's ancestor
5686 *
5687 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5688 */
5689static int
5690xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5691 if ((ancestor == NULL) || (node == NULL)) return(0);
5692 /* nodes need to be in the same document */
5693 if (ancestor->doc != node->doc) return(0);
5694 /* avoid searching if ancestor or node is the root node */
5695 if (ancestor == (xmlNodePtr) node->doc) return(1);
5696 if (node == (xmlNodePtr) ancestor->doc) return(0);
5697 while (node->parent != NULL) {
5698 if (node->parent == ancestor)
5699 return(1);
5700 node = node->parent;
5701 }
5702 return(0);
5703}
5704
5705/**
5706 * xmlXPathNextPreceding:
5707 * @ctxt: the XPath Parser context
5708 * @cur: the current node in the traversal
5709 *
5710 * Traversal function for the "preceding" direction
5711 * the preceding axis contains all nodes in the same document as the context
5712 * node that are before the context node in document order, excluding any
5713 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5714 * ordered in reverse document order
5715 *
5716 * Returns the next element following that axis
5717 */
5718xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005719xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5720{
Owen Taylor3473f882001-02-23 17:55:21 +00005721 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005722 cur = ctxt->context->node;
5723 if (cur == NULL)
5724 return (NULL);
5725 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5726 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005727 do {
5728 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005729 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5730 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005731 }
5732
5733 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005734 if (cur == NULL)
5735 return (NULL);
5736 if (cur == ctxt->context->doc->children)
5737 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005738 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005739 return (cur);
5740}
5741
5742/**
5743 * xmlXPathNextPrecedingInternal:
5744 * @ctxt: the XPath Parser context
5745 * @cur: the current node in the traversal
5746 *
5747 * Traversal function for the "preceding" direction
5748 * the preceding axis contains all nodes in the same document as the context
5749 * node that are before the context node in document order, excluding any
5750 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5751 * ordered in reverse document order
5752 * This is a faster implementation but internal only since it requires a
5753 * state kept in the parser context: ctxt->ancestor.
5754 *
5755 * Returns the next element following that axis
5756 */
5757static xmlNodePtr
5758xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5759 xmlNodePtr cur)
5760{
5761 if (cur == NULL) {
5762 cur = ctxt->context->node;
5763 if (cur == NULL)
5764 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005765 if (cur->type == XML_NAMESPACE_DECL)
5766 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005767 ctxt->ancestor = cur->parent;
5768 }
5769 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5770 cur = cur->prev;
5771 while (cur->prev == NULL) {
5772 cur = cur->parent;
5773 if (cur == NULL)
5774 return (NULL);
5775 if (cur == ctxt->context->doc->children)
5776 return (NULL);
5777 if (cur != ctxt->ancestor)
5778 return (cur);
5779 ctxt->ancestor = cur->parent;
5780 }
5781 cur = cur->prev;
5782 while (cur->last != NULL)
5783 cur = cur->last;
5784 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005785}
5786
5787/**
5788 * xmlXPathNextNamespace:
5789 * @ctxt: the XPath Parser context
5790 * @cur: the current attribute in the traversal
5791 *
5792 * Traversal function for the "namespace" direction
5793 * the namespace axis contains the namespace nodes of the context node;
5794 * the order of nodes on this axis is implementation-defined; the axis will
5795 * be empty unless the context node is an element
5796 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005797 * We keep the XML namespace node at the end of the list.
5798 *
Owen Taylor3473f882001-02-23 17:55:21 +00005799 * Returns the next element following that axis
5800 */
5801xmlNodePtr
5802xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5803 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005804 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005805 if (ctxt->context->tmpNsList != NULL)
5806 xmlFree(ctxt->context->tmpNsList);
5807 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005808 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005809 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005810 if (ctxt->context->tmpNsList != NULL) {
5811 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5812 ctxt->context->tmpNsNr++;
5813 }
5814 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005815 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005816 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005817 if (ctxt->context->tmpNsNr > 0) {
5818 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5819 } else {
5820 if (ctxt->context->tmpNsList != NULL)
5821 xmlFree(ctxt->context->tmpNsList);
5822 ctxt->context->tmpNsList = NULL;
5823 return(NULL);
5824 }
Owen Taylor3473f882001-02-23 17:55:21 +00005825}
5826
5827/**
5828 * xmlXPathNextAttribute:
5829 * @ctxt: the XPath Parser context
5830 * @cur: the current attribute in the traversal
5831 *
5832 * Traversal function for the "attribute" direction
5833 * TODO: support DTD inherited default attributes
5834 *
5835 * Returns the next element following that axis
5836 */
5837xmlNodePtr
5838xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005839 if (ctxt->context->node == NULL)
5840 return(NULL);
5841 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5842 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005843 if (cur == NULL) {
5844 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5845 return(NULL);
5846 return((xmlNodePtr)ctxt->context->node->properties);
5847 }
5848 return((xmlNodePtr)cur->next);
5849}
5850
5851/************************************************************************
5852 * *
5853 * NodeTest Functions *
5854 * *
5855 ************************************************************************/
5856
Owen Taylor3473f882001-02-23 17:55:21 +00005857#define IS_FUNCTION 200
5858
Owen Taylor3473f882001-02-23 17:55:21 +00005859
5860/************************************************************************
5861 * *
5862 * Implicit tree core function library *
5863 * *
5864 ************************************************************************/
5865
5866/**
5867 * xmlXPathRoot:
5868 * @ctxt: the XPath Parser context
5869 *
5870 * Initialize the context to the root of the document
5871 */
5872void
5873xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5874 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5875 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5876}
5877
5878/************************************************************************
5879 * *
5880 * The explicit core function library *
5881 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5882 * *
5883 ************************************************************************/
5884
5885
5886/**
5887 * xmlXPathLastFunction:
5888 * @ctxt: the XPath Parser context
5889 * @nargs: the number of arguments
5890 *
5891 * Implement the last() XPath function
5892 * number last()
5893 * The last function returns the number of nodes in the context node list.
5894 */
5895void
5896xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5897 CHECK_ARITY(0);
5898 if (ctxt->context->contextSize >= 0) {
5899 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5900#ifdef DEBUG_EXPR
5901 xmlGenericError(xmlGenericErrorContext,
5902 "last() : %d\n", ctxt->context->contextSize);
5903#endif
5904 } else {
5905 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5906 }
5907}
5908
5909/**
5910 * xmlXPathPositionFunction:
5911 * @ctxt: the XPath Parser context
5912 * @nargs: the number of arguments
5913 *
5914 * Implement the position() XPath function
5915 * number position()
5916 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005917 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005918 * will be equal to last().
5919 */
5920void
5921xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5922 CHECK_ARITY(0);
5923 if (ctxt->context->proximityPosition >= 0) {
5924 valuePush(ctxt,
5925 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5926#ifdef DEBUG_EXPR
5927 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5928 ctxt->context->proximityPosition);
5929#endif
5930 } else {
5931 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5932 }
5933}
5934
5935/**
5936 * xmlXPathCountFunction:
5937 * @ctxt: the XPath Parser context
5938 * @nargs: the number of arguments
5939 *
5940 * Implement the count() XPath function
5941 * number count(node-set)
5942 */
5943void
5944xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5945 xmlXPathObjectPtr cur;
5946
5947 CHECK_ARITY(1);
5948 if ((ctxt->value == NULL) ||
5949 ((ctxt->value->type != XPATH_NODESET) &&
5950 (ctxt->value->type != XPATH_XSLT_TREE)))
5951 XP_ERROR(XPATH_INVALID_TYPE);
5952 cur = valuePop(ctxt);
5953
Daniel Veillard911f49a2001-04-07 15:39:35 +00005954 if ((cur == NULL) || (cur->nodesetval == NULL))
5955 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005956 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005957 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005958 } else {
5959 if ((cur->nodesetval->nodeNr != 1) ||
5960 (cur->nodesetval->nodeTab == NULL)) {
5961 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5962 } else {
5963 xmlNodePtr tmp;
5964 int i = 0;
5965
5966 tmp = cur->nodesetval->nodeTab[0];
5967 if (tmp != NULL) {
5968 tmp = tmp->children;
5969 while (tmp != NULL) {
5970 tmp = tmp->next;
5971 i++;
5972 }
5973 }
5974 valuePush(ctxt, xmlXPathNewFloat((double) i));
5975 }
5976 }
Owen Taylor3473f882001-02-23 17:55:21 +00005977 xmlXPathFreeObject(cur);
5978}
5979
5980/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005981 * xmlXPathGetElementsByIds:
5982 * @doc: the document
5983 * @ids: a whitespace separated list of IDs
5984 *
5985 * Selects elements by their unique ID.
5986 *
5987 * Returns a node-set of selected elements.
5988 */
5989static xmlNodeSetPtr
5990xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5991 xmlNodeSetPtr ret;
5992 const xmlChar *cur = ids;
5993 xmlChar *ID;
5994 xmlAttrPtr attr;
5995 xmlNodePtr elem = NULL;
5996
Daniel Veillard7a985a12003-07-06 17:57:42 +00005997 if (ids == NULL) return(NULL);
5998
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005999 ret = xmlXPathNodeSetCreate(NULL);
6000
William M. Brack76e95df2003-10-18 16:20:14 +00006001 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006002 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006003 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006004 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006005
6006 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006007 if (ID != NULL) {
6008 if (xmlValidateNCName(ID, 1) == 0) {
6009 attr = xmlGetID(doc, ID);
6010 if (attr != NULL) {
6011 if (attr->type == XML_ATTRIBUTE_NODE)
6012 elem = attr->parent;
6013 else if (attr->type == XML_ELEMENT_NODE)
6014 elem = (xmlNodePtr) attr;
6015 else
6016 elem = NULL;
6017 if (elem != NULL)
6018 xmlXPathNodeSetAdd(ret, elem);
6019 }
6020 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006021 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006022 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006023
William M. Brack76e95df2003-10-18 16:20:14 +00006024 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006025 ids = cur;
6026 }
6027 return(ret);
6028}
6029
6030/**
Owen Taylor3473f882001-02-23 17:55:21 +00006031 * xmlXPathIdFunction:
6032 * @ctxt: the XPath Parser context
6033 * @nargs: the number of arguments
6034 *
6035 * Implement the id() XPath function
6036 * node-set id(object)
6037 * The id function selects elements by their unique ID
6038 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6039 * then the result is the union of the result of applying id to the
6040 * string value of each of the nodes in the argument node-set. When the
6041 * argument to id is of any other type, the argument is converted to a
6042 * string as if by a call to the string function; the string is split
6043 * into a whitespace-separated list of tokens (whitespace is any sequence
6044 * of characters matching the production S); the result is a node-set
6045 * containing the elements in the same document as the context node that
6046 * have a unique ID equal to any of the tokens in the list.
6047 */
6048void
6049xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006050 xmlChar *tokens;
6051 xmlNodeSetPtr ret;
6052 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006053
6054 CHECK_ARITY(1);
6055 obj = valuePop(ctxt);
6056 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006057 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006058 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006059 int i;
6060
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006061 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006062
Daniel Veillard911f49a2001-04-07 15:39:35 +00006063 if (obj->nodesetval != NULL) {
6064 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006065 tokens =
6066 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6067 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6068 ret = xmlXPathNodeSetMerge(ret, ns);
6069 xmlXPathFreeNodeSet(ns);
6070 if (tokens != NULL)
6071 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006072 }
Owen Taylor3473f882001-02-23 17:55:21 +00006073 }
6074
6075 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006076 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006077 return;
6078 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006079 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006080
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006081 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6082 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006083
Owen Taylor3473f882001-02-23 17:55:21 +00006084 xmlXPathFreeObject(obj);
6085 return;
6086}
6087
6088/**
6089 * xmlXPathLocalNameFunction:
6090 * @ctxt: the XPath Parser context
6091 * @nargs: the number of arguments
6092 *
6093 * Implement the local-name() XPath function
6094 * string local-name(node-set?)
6095 * The local-name function returns a string containing the local part
6096 * of the name of the node in the argument node-set that is first in
6097 * document order. If the node-set is empty or the first node has no
6098 * name, an empty string is returned. If the argument is omitted it
6099 * defaults to the context node.
6100 */
6101void
6102xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6103 xmlXPathObjectPtr cur;
6104
6105 if (nargs == 0) {
6106 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6107 nargs = 1;
6108 }
6109
6110 CHECK_ARITY(1);
6111 if ((ctxt->value == NULL) ||
6112 ((ctxt->value->type != XPATH_NODESET) &&
6113 (ctxt->value->type != XPATH_XSLT_TREE)))
6114 XP_ERROR(XPATH_INVALID_TYPE);
6115 cur = valuePop(ctxt);
6116
Daniel Veillard911f49a2001-04-07 15:39:35 +00006117 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006118 valuePush(ctxt, xmlXPathNewCString(""));
6119 } else {
6120 int i = 0; /* Should be first in document order !!!!! */
6121 switch (cur->nodesetval->nodeTab[i]->type) {
6122 case XML_ELEMENT_NODE:
6123 case XML_ATTRIBUTE_NODE:
6124 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006125 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6126 valuePush(ctxt, xmlXPathNewCString(""));
6127 else
6128 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006129 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6130 break;
6131 case XML_NAMESPACE_DECL:
6132 valuePush(ctxt, xmlXPathNewString(
6133 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6134 break;
6135 default:
6136 valuePush(ctxt, xmlXPathNewCString(""));
6137 }
6138 }
6139 xmlXPathFreeObject(cur);
6140}
6141
6142/**
6143 * xmlXPathNamespaceURIFunction:
6144 * @ctxt: the XPath Parser context
6145 * @nargs: the number of arguments
6146 *
6147 * Implement the namespace-uri() XPath function
6148 * string namespace-uri(node-set?)
6149 * The namespace-uri function returns a string containing the
6150 * namespace URI of the expanded name of the node in the argument
6151 * node-set that is first in document order. If the node-set is empty,
6152 * the first node has no name, or the expanded name has no namespace
6153 * URI, an empty string is returned. If the argument is omitted it
6154 * defaults to the context node.
6155 */
6156void
6157xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6158 xmlXPathObjectPtr cur;
6159
6160 if (nargs == 0) {
6161 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6162 nargs = 1;
6163 }
6164 CHECK_ARITY(1);
6165 if ((ctxt->value == NULL) ||
6166 ((ctxt->value->type != XPATH_NODESET) &&
6167 (ctxt->value->type != XPATH_XSLT_TREE)))
6168 XP_ERROR(XPATH_INVALID_TYPE);
6169 cur = valuePop(ctxt);
6170
Daniel Veillard911f49a2001-04-07 15:39:35 +00006171 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006172 valuePush(ctxt, xmlXPathNewCString(""));
6173 } else {
6174 int i = 0; /* Should be first in document order !!!!! */
6175 switch (cur->nodesetval->nodeTab[i]->type) {
6176 case XML_ELEMENT_NODE:
6177 case XML_ATTRIBUTE_NODE:
6178 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6179 valuePush(ctxt, xmlXPathNewCString(""));
6180 else
6181 valuePush(ctxt, xmlXPathNewString(
6182 cur->nodesetval->nodeTab[i]->ns->href));
6183 break;
6184 default:
6185 valuePush(ctxt, xmlXPathNewCString(""));
6186 }
6187 }
6188 xmlXPathFreeObject(cur);
6189}
6190
6191/**
6192 * xmlXPathNameFunction:
6193 * @ctxt: the XPath Parser context
6194 * @nargs: the number of arguments
6195 *
6196 * Implement the name() XPath function
6197 * string name(node-set?)
6198 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006199 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006200 * order. The QName must represent the name with respect to the namespace
6201 * declarations in effect on the node whose name is being represented.
6202 * Typically, this will be the form in which the name occurred in the XML
6203 * source. This need not be the case if there are namespace declarations
6204 * in effect on the node that associate multiple prefixes with the same
6205 * namespace. However, an implementation may include information about
6206 * the original prefix in its representation of nodes; in this case, an
6207 * implementation can ensure that the returned string is always the same
6208 * as the QName used in the XML source. If the argument it omitted it
6209 * defaults to the context node.
6210 * Libxml keep the original prefix so the "real qualified name" used is
6211 * returned.
6212 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006213static void
Daniel Veillard04383752001-07-08 14:27:15 +00006214xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6215{
Owen Taylor3473f882001-02-23 17:55:21 +00006216 xmlXPathObjectPtr cur;
6217
6218 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006219 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6220 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006221 }
6222
6223 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006224 if ((ctxt->value == NULL) ||
6225 ((ctxt->value->type != XPATH_NODESET) &&
6226 (ctxt->value->type != XPATH_XSLT_TREE)))
6227 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006228 cur = valuePop(ctxt);
6229
Daniel Veillard911f49a2001-04-07 15:39:35 +00006230 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006231 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006232 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006233 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006234
Daniel Veillard04383752001-07-08 14:27:15 +00006235 switch (cur->nodesetval->nodeTab[i]->type) {
6236 case XML_ELEMENT_NODE:
6237 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006238 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6239 valuePush(ctxt, xmlXPathNewCString(""));
6240 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6241 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006242 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006243 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006244
Daniel Veillard652d8a92003-02-04 19:28:49 +00006245 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006246 xmlChar *fullname;
6247
6248 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6249 cur->nodesetval->nodeTab[i]->ns->prefix,
6250 NULL, 0);
6251 if (fullname == cur->nodesetval->nodeTab[i]->name)
6252 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6253 if (fullname == NULL) {
6254 XP_ERROR(XPATH_MEMORY_ERROR);
6255 }
6256 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006257 }
6258 break;
6259 default:
6260 valuePush(ctxt,
6261 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6262 xmlXPathLocalNameFunction(ctxt, 1);
6263 }
Owen Taylor3473f882001-02-23 17:55:21 +00006264 }
6265 xmlXPathFreeObject(cur);
6266}
6267
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006268
6269/**
Owen Taylor3473f882001-02-23 17:55:21 +00006270 * xmlXPathStringFunction:
6271 * @ctxt: the XPath Parser context
6272 * @nargs: the number of arguments
6273 *
6274 * Implement the string() XPath function
6275 * string string(object?)
6276 * he string function converts an object to a string as follows:
6277 * - A node-set is converted to a string by returning the value of
6278 * the node in the node-set that is first in document order.
6279 * If the node-set is empty, an empty string is returned.
6280 * - A number is converted to a string as follows
6281 * + NaN is converted to the string NaN
6282 * + positive zero is converted to the string 0
6283 * + negative zero is converted to the string 0
6284 * + positive infinity is converted to the string Infinity
6285 * + negative infinity is converted to the string -Infinity
6286 * + if the number is an integer, the number is represented in
6287 * decimal form as a Number with no decimal point and no leading
6288 * zeros, preceded by a minus sign (-) if the number is negative
6289 * + otherwise, the number is represented in decimal form as a
6290 * Number including a decimal point with at least one digit
6291 * before the decimal point and at least one digit after the
6292 * decimal point, preceded by a minus sign (-) if the number
6293 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006294 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006295 * before the decimal point; beyond the one required digit
6296 * after the decimal point there must be as many, but only as
6297 * many, more digits as are needed to uniquely distinguish the
6298 * number from all other IEEE 754 numeric values.
6299 * - The boolean false value is converted to the string false.
6300 * The boolean true value is converted to the string true.
6301 *
6302 * If the argument is omitted, it defaults to a node-set with the
6303 * context node as its only member.
6304 */
6305void
6306xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6307 xmlXPathObjectPtr cur;
6308
6309 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006310 valuePush(ctxt,
6311 xmlXPathWrapString(
6312 xmlXPathCastNodeToString(ctxt->context->node)));
6313 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006314 }
6315
6316 CHECK_ARITY(1);
6317 cur = valuePop(ctxt);
6318 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006319 cur = xmlXPathConvertString(cur);
6320 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006321}
6322
6323/**
6324 * xmlXPathStringLengthFunction:
6325 * @ctxt: the XPath Parser context
6326 * @nargs: the number of arguments
6327 *
6328 * Implement the string-length() XPath function
6329 * number string-length(string?)
6330 * The string-length returns the number of characters in the string
6331 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6332 * the context node converted to a string, in other words the value
6333 * of the context node.
6334 */
6335void
6336xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6337 xmlXPathObjectPtr cur;
6338
6339 if (nargs == 0) {
6340 if (ctxt->context->node == NULL) {
6341 valuePush(ctxt, xmlXPathNewFloat(0));
6342 } else {
6343 xmlChar *content;
6344
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006345 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006346 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006347 xmlFree(content);
6348 }
6349 return;
6350 }
6351 CHECK_ARITY(1);
6352 CAST_TO_STRING;
6353 CHECK_TYPE(XPATH_STRING);
6354 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006355 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006356 xmlXPathFreeObject(cur);
6357}
6358
6359/**
6360 * xmlXPathConcatFunction:
6361 * @ctxt: the XPath Parser context
6362 * @nargs: the number of arguments
6363 *
6364 * Implement the concat() XPath function
6365 * string concat(string, string, string*)
6366 * The concat function returns the concatenation of its arguments.
6367 */
6368void
6369xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6370 xmlXPathObjectPtr cur, newobj;
6371 xmlChar *tmp;
6372
6373 if (nargs < 2) {
6374 CHECK_ARITY(2);
6375 }
6376
6377 CAST_TO_STRING;
6378 cur = valuePop(ctxt);
6379 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6380 xmlXPathFreeObject(cur);
6381 return;
6382 }
6383 nargs--;
6384
6385 while (nargs > 0) {
6386 CAST_TO_STRING;
6387 newobj = valuePop(ctxt);
6388 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6389 xmlXPathFreeObject(newobj);
6390 xmlXPathFreeObject(cur);
6391 XP_ERROR(XPATH_INVALID_TYPE);
6392 }
6393 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6394 newobj->stringval = cur->stringval;
6395 cur->stringval = tmp;
6396
6397 xmlXPathFreeObject(newobj);
6398 nargs--;
6399 }
6400 valuePush(ctxt, cur);
6401}
6402
6403/**
6404 * xmlXPathContainsFunction:
6405 * @ctxt: the XPath Parser context
6406 * @nargs: the number of arguments
6407 *
6408 * Implement the contains() XPath function
6409 * boolean contains(string, string)
6410 * The contains function returns true if the first argument string
6411 * contains the second argument string, and otherwise returns false.
6412 */
6413void
6414xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6415 xmlXPathObjectPtr hay, needle;
6416
6417 CHECK_ARITY(2);
6418 CAST_TO_STRING;
6419 CHECK_TYPE(XPATH_STRING);
6420 needle = valuePop(ctxt);
6421 CAST_TO_STRING;
6422 hay = valuePop(ctxt);
6423 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6424 xmlXPathFreeObject(hay);
6425 xmlXPathFreeObject(needle);
6426 XP_ERROR(XPATH_INVALID_TYPE);
6427 }
6428 if (xmlStrstr(hay->stringval, needle->stringval))
6429 valuePush(ctxt, xmlXPathNewBoolean(1));
6430 else
6431 valuePush(ctxt, xmlXPathNewBoolean(0));
6432 xmlXPathFreeObject(hay);
6433 xmlXPathFreeObject(needle);
6434}
6435
6436/**
6437 * xmlXPathStartsWithFunction:
6438 * @ctxt: the XPath Parser context
6439 * @nargs: the number of arguments
6440 *
6441 * Implement the starts-with() XPath function
6442 * boolean starts-with(string, string)
6443 * The starts-with function returns true if the first argument string
6444 * starts with the second argument string, and otherwise returns false.
6445 */
6446void
6447xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6448 xmlXPathObjectPtr hay, needle;
6449 int n;
6450
6451 CHECK_ARITY(2);
6452 CAST_TO_STRING;
6453 CHECK_TYPE(XPATH_STRING);
6454 needle = valuePop(ctxt);
6455 CAST_TO_STRING;
6456 hay = valuePop(ctxt);
6457 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6458 xmlXPathFreeObject(hay);
6459 xmlXPathFreeObject(needle);
6460 XP_ERROR(XPATH_INVALID_TYPE);
6461 }
6462 n = xmlStrlen(needle->stringval);
6463 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6464 valuePush(ctxt, xmlXPathNewBoolean(0));
6465 else
6466 valuePush(ctxt, xmlXPathNewBoolean(1));
6467 xmlXPathFreeObject(hay);
6468 xmlXPathFreeObject(needle);
6469}
6470
6471/**
6472 * xmlXPathSubstringFunction:
6473 * @ctxt: the XPath Parser context
6474 * @nargs: the number of arguments
6475 *
6476 * Implement the substring() XPath function
6477 * string substring(string, number, number?)
6478 * The substring function returns the substring of the first argument
6479 * starting at the position specified in the second argument with
6480 * length specified in the third argument. For example,
6481 * substring("12345",2,3) returns "234". If the third argument is not
6482 * specified, it returns the substring starting at the position specified
6483 * in the second argument and continuing to the end of the string. For
6484 * example, substring("12345",2) returns "2345". More precisely, each
6485 * character in the string (see [3.6 Strings]) is considered to have a
6486 * numeric position: the position of the first character is 1, the position
6487 * of the second character is 2 and so on. The returned substring contains
6488 * those characters for which the position of the character is greater than
6489 * or equal to the second argument and, if the third argument is specified,
6490 * less than the sum of the second and third arguments; the comparisons
6491 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6492 * - substring("12345", 1.5, 2.6) returns "234"
6493 * - substring("12345", 0, 3) returns "12"
6494 * - substring("12345", 0 div 0, 3) returns ""
6495 * - substring("12345", 1, 0 div 0) returns ""
6496 * - substring("12345", -42, 1 div 0) returns "12345"
6497 * - substring("12345", -1 div 0, 1 div 0) returns ""
6498 */
6499void
6500xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6501 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006502 double le=0, in;
6503 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006504 xmlChar *ret;
6505
Owen Taylor3473f882001-02-23 17:55:21 +00006506 if (nargs < 2) {
6507 CHECK_ARITY(2);
6508 }
6509 if (nargs > 3) {
6510 CHECK_ARITY(3);
6511 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006512 /*
6513 * take care of possible last (position) argument
6514 */
Owen Taylor3473f882001-02-23 17:55:21 +00006515 if (nargs == 3) {
6516 CAST_TO_NUMBER;
6517 CHECK_TYPE(XPATH_NUMBER);
6518 len = valuePop(ctxt);
6519 le = len->floatval;
6520 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006521 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006522
Owen Taylor3473f882001-02-23 17:55:21 +00006523 CAST_TO_NUMBER;
6524 CHECK_TYPE(XPATH_NUMBER);
6525 start = valuePop(ctxt);
6526 in = start->floatval;
6527 xmlXPathFreeObject(start);
6528 CAST_TO_STRING;
6529 CHECK_TYPE(XPATH_STRING);
6530 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006531 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006532
Daniel Veillard97ac1312001-05-30 19:14:17 +00006533 /*
6534 * If last pos not present, calculate last position
6535 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006536 if (nargs != 3) {
6537 le = (double)m;
6538 if (in < 1.0)
6539 in = 1.0;
6540 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006541
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006542 /* Need to check for the special cases where either
6543 * the index is NaN, the length is NaN, or both
6544 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006545 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006546 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006547 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006548 * To meet the requirements of the spec, the arguments
6549 * must be converted to integer format before
6550 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006551 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006552 * First we go to integer form, rounding up
6553 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006554 */
6555 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006556 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006557
Daniel Veillard9e412302002-06-10 15:59:44 +00006558 if (xmlXPathIsInf(le) == 1) {
6559 l = m;
6560 if (i < 1)
6561 i = 1;
6562 }
6563 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6564 l = 0;
6565 else {
6566 l = (int) le;
6567 if (((double)l)+0.5 <= le) l++;
6568 }
6569
6570 /* Now we normalize inidices */
6571 i -= 1;
6572 l += i;
6573 if (i < 0)
6574 i = 0;
6575 if (l > m)
6576 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006577
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006578 /* number of chars to copy */
6579 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006580
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006581 ret = xmlUTF8Strsub(str->stringval, i, l);
6582 }
6583 else {
6584 ret = NULL;
6585 }
6586
Owen Taylor3473f882001-02-23 17:55:21 +00006587 if (ret == NULL)
6588 valuePush(ctxt, xmlXPathNewCString(""));
6589 else {
6590 valuePush(ctxt, xmlXPathNewString(ret));
6591 xmlFree(ret);
6592 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006593
Owen Taylor3473f882001-02-23 17:55:21 +00006594 xmlXPathFreeObject(str);
6595}
6596
6597/**
6598 * xmlXPathSubstringBeforeFunction:
6599 * @ctxt: the XPath Parser context
6600 * @nargs: the number of arguments
6601 *
6602 * Implement the substring-before() XPath function
6603 * string substring-before(string, string)
6604 * The substring-before function returns the substring of the first
6605 * argument string that precedes the first occurrence of the second
6606 * argument string in the first argument string, or the empty string
6607 * if the first argument string does not contain the second argument
6608 * string. For example, substring-before("1999/04/01","/") returns 1999.
6609 */
6610void
6611xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6612 xmlXPathObjectPtr str;
6613 xmlXPathObjectPtr find;
6614 xmlBufferPtr target;
6615 const xmlChar *point;
6616 int offset;
6617
6618 CHECK_ARITY(2);
6619 CAST_TO_STRING;
6620 find = valuePop(ctxt);
6621 CAST_TO_STRING;
6622 str = valuePop(ctxt);
6623
6624 target = xmlBufferCreate();
6625 if (target) {
6626 point = xmlStrstr(str->stringval, find->stringval);
6627 if (point) {
6628 offset = (int)(point - str->stringval);
6629 xmlBufferAdd(target, str->stringval, offset);
6630 }
6631 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6632 xmlBufferFree(target);
6633 }
6634
6635 xmlXPathFreeObject(str);
6636 xmlXPathFreeObject(find);
6637}
6638
6639/**
6640 * xmlXPathSubstringAfterFunction:
6641 * @ctxt: the XPath Parser context
6642 * @nargs: the number of arguments
6643 *
6644 * Implement the substring-after() XPath function
6645 * string substring-after(string, string)
6646 * The substring-after function returns the substring of the first
6647 * argument string that follows the first occurrence of the second
6648 * argument string in the first argument string, or the empty stringi
6649 * if the first argument string does not contain the second argument
6650 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6651 * and substring-after("1999/04/01","19") returns 99/04/01.
6652 */
6653void
6654xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6655 xmlXPathObjectPtr str;
6656 xmlXPathObjectPtr find;
6657 xmlBufferPtr target;
6658 const xmlChar *point;
6659 int offset;
6660
6661 CHECK_ARITY(2);
6662 CAST_TO_STRING;
6663 find = valuePop(ctxt);
6664 CAST_TO_STRING;
6665 str = valuePop(ctxt);
6666
6667 target = xmlBufferCreate();
6668 if (target) {
6669 point = xmlStrstr(str->stringval, find->stringval);
6670 if (point) {
6671 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6672 xmlBufferAdd(target, &str->stringval[offset],
6673 xmlStrlen(str->stringval) - offset);
6674 }
6675 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6676 xmlBufferFree(target);
6677 }
6678
6679 xmlXPathFreeObject(str);
6680 xmlXPathFreeObject(find);
6681}
6682
6683/**
6684 * xmlXPathNormalizeFunction:
6685 * @ctxt: the XPath Parser context
6686 * @nargs: the number of arguments
6687 *
6688 * Implement the normalize-space() XPath function
6689 * string normalize-space(string?)
6690 * The normalize-space function returns the argument string with white
6691 * space normalized by stripping leading and trailing whitespace
6692 * and replacing sequences of whitespace characters by a single
6693 * space. Whitespace characters are the same allowed by the S production
6694 * in XML. If the argument is omitted, it defaults to the context
6695 * node converted to a string, in other words the value of the context node.
6696 */
6697void
6698xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6699 xmlXPathObjectPtr obj = NULL;
6700 xmlChar *source = NULL;
6701 xmlBufferPtr target;
6702 xmlChar blank;
6703
6704 if (nargs == 0) {
6705 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006706 valuePush(ctxt,
6707 xmlXPathWrapString(
6708 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006709 nargs = 1;
6710 }
6711
6712 CHECK_ARITY(1);
6713 CAST_TO_STRING;
6714 CHECK_TYPE(XPATH_STRING);
6715 obj = valuePop(ctxt);
6716 source = obj->stringval;
6717
6718 target = xmlBufferCreate();
6719 if (target && source) {
6720
6721 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006722 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006723 source++;
6724
6725 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6726 blank = 0;
6727 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006728 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006729 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006730 } else {
6731 if (blank) {
6732 xmlBufferAdd(target, &blank, 1);
6733 blank = 0;
6734 }
6735 xmlBufferAdd(target, source, 1);
6736 }
6737 source++;
6738 }
6739
6740 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6741 xmlBufferFree(target);
6742 }
6743 xmlXPathFreeObject(obj);
6744}
6745
6746/**
6747 * xmlXPathTranslateFunction:
6748 * @ctxt: the XPath Parser context
6749 * @nargs: the number of arguments
6750 *
6751 * Implement the translate() XPath function
6752 * string translate(string, string, string)
6753 * The translate function returns the first argument string with
6754 * occurrences of characters in the second argument string replaced
6755 * by the character at the corresponding position in the third argument
6756 * string. For example, translate("bar","abc","ABC") returns the string
6757 * BAr. If there is a character in the second argument string with no
6758 * character at a corresponding position in the third argument string
6759 * (because the second argument string is longer than the third argument
6760 * string), then occurrences of that character in the first argument
6761 * string are removed. For example, translate("--aaa--","abc-","ABC")
6762 * returns "AAA". If a character occurs more than once in second
6763 * argument string, then the first occurrence determines the replacement
6764 * character. If the third argument string is longer than the second
6765 * argument string, then excess characters are ignored.
6766 */
6767void
6768xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006769 xmlXPathObjectPtr str;
6770 xmlXPathObjectPtr from;
6771 xmlXPathObjectPtr to;
6772 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006773 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006774 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006775 xmlChar *point;
6776 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006777
Daniel Veillarde043ee12001-04-16 14:08:07 +00006778 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006779
Daniel Veillarde043ee12001-04-16 14:08:07 +00006780 CAST_TO_STRING;
6781 to = valuePop(ctxt);
6782 CAST_TO_STRING;
6783 from = valuePop(ctxt);
6784 CAST_TO_STRING;
6785 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006786
Daniel Veillarde043ee12001-04-16 14:08:07 +00006787 target = xmlBufferCreate();
6788 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006789 max = xmlUTF8Strlen(to->stringval);
6790 for (cptr = str->stringval; (ch=*cptr); ) {
6791 offset = xmlUTF8Strloc(from->stringval, cptr);
6792 if (offset >= 0) {
6793 if (offset < max) {
6794 point = xmlUTF8Strpos(to->stringval, offset);
6795 if (point)
6796 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6797 }
6798 } else
6799 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6800
6801 /* Step to next character in input */
6802 cptr++;
6803 if ( ch & 0x80 ) {
6804 /* if not simple ascii, verify proper format */
6805 if ( (ch & 0xc0) != 0xc0 ) {
6806 xmlGenericError(xmlGenericErrorContext,
6807 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6808 break;
6809 }
6810 /* then skip over remaining bytes for this char */
6811 while ( (ch <<= 1) & 0x80 )
6812 if ( (*cptr++ & 0xc0) != 0x80 ) {
6813 xmlGenericError(xmlGenericErrorContext,
6814 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6815 break;
6816 }
6817 if (ch & 0x80) /* must have had error encountered */
6818 break;
6819 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006820 }
Owen Taylor3473f882001-02-23 17:55:21 +00006821 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006822 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6823 xmlBufferFree(target);
6824 xmlXPathFreeObject(str);
6825 xmlXPathFreeObject(from);
6826 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006827}
6828
6829/**
6830 * xmlXPathBooleanFunction:
6831 * @ctxt: the XPath Parser context
6832 * @nargs: the number of arguments
6833 *
6834 * Implement the boolean() XPath function
6835 * boolean boolean(object)
6836 * he boolean function converts its argument to a boolean as follows:
6837 * - a number is true if and only if it is neither positive or
6838 * negative zero nor NaN
6839 * - a node-set is true if and only if it is non-empty
6840 * - a string is true if and only if its length is non-zero
6841 */
6842void
6843xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6844 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006845
6846 CHECK_ARITY(1);
6847 cur = valuePop(ctxt);
6848 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006849 cur = xmlXPathConvertBoolean(cur);
6850 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006851}
6852
6853/**
6854 * xmlXPathNotFunction:
6855 * @ctxt: the XPath Parser context
6856 * @nargs: the number of arguments
6857 *
6858 * Implement the not() XPath function
6859 * boolean not(boolean)
6860 * The not function returns true if its argument is false,
6861 * and false otherwise.
6862 */
6863void
6864xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6865 CHECK_ARITY(1);
6866 CAST_TO_BOOLEAN;
6867 CHECK_TYPE(XPATH_BOOLEAN);
6868 ctxt->value->boolval = ! ctxt->value->boolval;
6869}
6870
6871/**
6872 * xmlXPathTrueFunction:
6873 * @ctxt: the XPath Parser context
6874 * @nargs: the number of arguments
6875 *
6876 * Implement the true() XPath function
6877 * boolean true()
6878 */
6879void
6880xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6881 CHECK_ARITY(0);
6882 valuePush(ctxt, xmlXPathNewBoolean(1));
6883}
6884
6885/**
6886 * xmlXPathFalseFunction:
6887 * @ctxt: the XPath Parser context
6888 * @nargs: the number of arguments
6889 *
6890 * Implement the false() XPath function
6891 * boolean false()
6892 */
6893void
6894xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6895 CHECK_ARITY(0);
6896 valuePush(ctxt, xmlXPathNewBoolean(0));
6897}
6898
6899/**
6900 * xmlXPathLangFunction:
6901 * @ctxt: the XPath Parser context
6902 * @nargs: the number of arguments
6903 *
6904 * Implement the lang() XPath function
6905 * boolean lang(string)
6906 * The lang function returns true or false depending on whether the
6907 * language of the context node as specified by xml:lang attributes
6908 * is the same as or is a sublanguage of the language specified by
6909 * the argument string. The language of the context node is determined
6910 * by the value of the xml:lang attribute on the context node, or, if
6911 * the context node has no xml:lang attribute, by the value of the
6912 * xml:lang attribute on the nearest ancestor of the context node that
6913 * has an xml:lang attribute. If there is no such attribute, then lang
6914 * returns false. If there is such an attribute, then lang returns
6915 * true if the attribute value is equal to the argument ignoring case,
6916 * or if there is some suffix starting with - such that the attribute
6917 * value is equal to the argument ignoring that suffix of the attribute
6918 * value and ignoring case.
6919 */
6920void
6921xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6922 xmlXPathObjectPtr val;
6923 const xmlChar *theLang;
6924 const xmlChar *lang;
6925 int ret = 0;
6926 int i;
6927
6928 CHECK_ARITY(1);
6929 CAST_TO_STRING;
6930 CHECK_TYPE(XPATH_STRING);
6931 val = valuePop(ctxt);
6932 lang = val->stringval;
6933 theLang = xmlNodeGetLang(ctxt->context->node);
6934 if ((theLang != NULL) && (lang != NULL)) {
6935 for (i = 0;lang[i] != 0;i++)
6936 if (toupper(lang[i]) != toupper(theLang[i]))
6937 goto not_equal;
6938 ret = 1;
6939 }
6940not_equal:
6941 xmlXPathFreeObject(val);
6942 valuePush(ctxt, xmlXPathNewBoolean(ret));
6943}
6944
6945/**
6946 * xmlXPathNumberFunction:
6947 * @ctxt: the XPath Parser context
6948 * @nargs: the number of arguments
6949 *
6950 * Implement the number() XPath function
6951 * number number(object?)
6952 */
6953void
6954xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6955 xmlXPathObjectPtr cur;
6956 double res;
6957
6958 if (nargs == 0) {
6959 if (ctxt->context->node == NULL) {
6960 valuePush(ctxt, xmlXPathNewFloat(0.0));
6961 } else {
6962 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6963
6964 res = xmlXPathStringEvalNumber(content);
6965 valuePush(ctxt, xmlXPathNewFloat(res));
6966 xmlFree(content);
6967 }
6968 return;
6969 }
6970
6971 CHECK_ARITY(1);
6972 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006973 cur = xmlXPathConvertNumber(cur);
6974 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006975}
6976
6977/**
6978 * xmlXPathSumFunction:
6979 * @ctxt: the XPath Parser context
6980 * @nargs: the number of arguments
6981 *
6982 * Implement the sum() XPath function
6983 * number sum(node-set)
6984 * The sum function returns the sum of the values of the nodes in
6985 * the argument node-set.
6986 */
6987void
6988xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6989 xmlXPathObjectPtr cur;
6990 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006991 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006992
6993 CHECK_ARITY(1);
6994 if ((ctxt->value == NULL) ||
6995 ((ctxt->value->type != XPATH_NODESET) &&
6996 (ctxt->value->type != XPATH_XSLT_TREE)))
6997 XP_ERROR(XPATH_INVALID_TYPE);
6998 cur = valuePop(ctxt);
6999
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007000 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007001 valuePush(ctxt, xmlXPathNewFloat(0.0));
7002 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007003 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7004 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007005 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007006 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007007 }
7008 xmlXPathFreeObject(cur);
7009}
7010
7011/**
7012 * xmlXPathFloorFunction:
7013 * @ctxt: the XPath Parser context
7014 * @nargs: the number of arguments
7015 *
7016 * Implement the floor() XPath function
7017 * number floor(number)
7018 * The floor function returns the largest (closest to positive infinity)
7019 * number that is not greater than the argument and that is an integer.
7020 */
7021void
7022xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007023 double f;
7024
Owen Taylor3473f882001-02-23 17:55:21 +00007025 CHECK_ARITY(1);
7026 CAST_TO_NUMBER;
7027 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007028
7029 f = (double)((int) ctxt->value->floatval);
7030 if (f != ctxt->value->floatval) {
7031 if (ctxt->value->floatval > 0)
7032 ctxt->value->floatval = f;
7033 else
7034 ctxt->value->floatval = f - 1;
7035 }
Owen Taylor3473f882001-02-23 17:55:21 +00007036}
7037
7038/**
7039 * xmlXPathCeilingFunction:
7040 * @ctxt: the XPath Parser context
7041 * @nargs: the number of arguments
7042 *
7043 * Implement the ceiling() XPath function
7044 * number ceiling(number)
7045 * The ceiling function returns the smallest (closest to negative infinity)
7046 * number that is not less than the argument and that is an integer.
7047 */
7048void
7049xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7050 double f;
7051
7052 CHECK_ARITY(1);
7053 CAST_TO_NUMBER;
7054 CHECK_TYPE(XPATH_NUMBER);
7055
7056#if 0
7057 ctxt->value->floatval = ceil(ctxt->value->floatval);
7058#else
7059 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007060 if (f != ctxt->value->floatval) {
7061 if (ctxt->value->floatval > 0)
7062 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007063 else {
7064 if (ctxt->value->floatval < 0 && f == 0)
7065 ctxt->value->floatval = xmlXPathNZERO;
7066 else
7067 ctxt->value->floatval = f;
7068 }
7069
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007070 }
Owen Taylor3473f882001-02-23 17:55:21 +00007071#endif
7072}
7073
7074/**
7075 * xmlXPathRoundFunction:
7076 * @ctxt: the XPath Parser context
7077 * @nargs: the number of arguments
7078 *
7079 * Implement the round() XPath function
7080 * number round(number)
7081 * The round function returns the number that is closest to the
7082 * argument and that is an integer. If there are two such numbers,
7083 * then the one that is even is returned.
7084 */
7085void
7086xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7087 double f;
7088
7089 CHECK_ARITY(1);
7090 CAST_TO_NUMBER;
7091 CHECK_TYPE(XPATH_NUMBER);
7092
Daniel Veillardcda96922001-08-21 10:56:31 +00007093 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7094 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7095 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007096 (ctxt->value->floatval == 0.0))
7097 return;
7098
Owen Taylor3473f882001-02-23 17:55:21 +00007099 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007100 if (ctxt->value->floatval < 0) {
7101 if (ctxt->value->floatval < f - 0.5)
7102 ctxt->value->floatval = f - 1;
7103 else
7104 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007105 if (ctxt->value->floatval == 0)
7106 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007107 } else {
7108 if (ctxt->value->floatval < f + 0.5)
7109 ctxt->value->floatval = f;
7110 else
7111 ctxt->value->floatval = f + 1;
7112 }
Owen Taylor3473f882001-02-23 17:55:21 +00007113}
7114
7115/************************************************************************
7116 * *
7117 * The Parser *
7118 * *
7119 ************************************************************************/
7120
7121/*
7122 * a couple of forward declarations since we use a recursive call based
7123 * implementation.
7124 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007125static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007126static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007127static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007128static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007129static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7130 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007131
7132/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007133 * xmlXPathCurrentChar:
7134 * @ctxt: the XPath parser context
7135 * @cur: pointer to the beginning of the char
7136 * @len: pointer to the length of the char read
7137 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007138 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007139 * bytes in the input buffer.
7140 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007141 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007142 */
7143
7144static int
7145xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7146 unsigned char c;
7147 unsigned int val;
7148 const xmlChar *cur;
7149
7150 if (ctxt == NULL)
7151 return(0);
7152 cur = ctxt->cur;
7153
7154 /*
7155 * We are supposed to handle UTF8, check it's valid
7156 * From rfc2044: encoding of the Unicode values on UTF-8:
7157 *
7158 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7159 * 0000 0000-0000 007F 0xxxxxxx
7160 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7161 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7162 *
7163 * Check for the 0x110000 limit too
7164 */
7165 c = *cur;
7166 if (c & 0x80) {
7167 if ((cur[1] & 0xc0) != 0x80)
7168 goto encoding_error;
7169 if ((c & 0xe0) == 0xe0) {
7170
7171 if ((cur[2] & 0xc0) != 0x80)
7172 goto encoding_error;
7173 if ((c & 0xf0) == 0xf0) {
7174 if (((c & 0xf8) != 0xf0) ||
7175 ((cur[3] & 0xc0) != 0x80))
7176 goto encoding_error;
7177 /* 4-byte code */
7178 *len = 4;
7179 val = (cur[0] & 0x7) << 18;
7180 val |= (cur[1] & 0x3f) << 12;
7181 val |= (cur[2] & 0x3f) << 6;
7182 val |= cur[3] & 0x3f;
7183 } else {
7184 /* 3-byte code */
7185 *len = 3;
7186 val = (cur[0] & 0xf) << 12;
7187 val |= (cur[1] & 0x3f) << 6;
7188 val |= cur[2] & 0x3f;
7189 }
7190 } else {
7191 /* 2-byte code */
7192 *len = 2;
7193 val = (cur[0] & 0x1f) << 6;
7194 val |= cur[1] & 0x3f;
7195 }
7196 if (!IS_CHAR(val)) {
7197 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7198 }
7199 return(val);
7200 } else {
7201 /* 1-byte code */
7202 *len = 1;
7203 return((int) *cur);
7204 }
7205encoding_error:
7206 /*
7207 * If we detect an UTF8 error that probably mean that the
7208 * input encoding didn't get properly advertized in the
7209 * declaration header. Report the error and switch the encoding
7210 * to ISO-Latin-1 (if you don't like this policy, just declare the
7211 * encoding !)
7212 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007213 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007214 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007215}
7216
7217/**
Owen Taylor3473f882001-02-23 17:55:21 +00007218 * xmlXPathParseNCName:
7219 * @ctxt: the XPath Parser context
7220 *
7221 * parse an XML namespace non qualified name.
7222 *
7223 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7224 *
7225 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7226 * CombiningChar | Extender
7227 *
7228 * Returns the namespace name or NULL
7229 */
7230
7231xmlChar *
7232xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007233 const xmlChar *in;
7234 xmlChar *ret;
7235 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007236
Daniel Veillard2156a562001-04-28 12:24:34 +00007237 /*
7238 * Accelerator for simple ASCII names
7239 */
7240 in = ctxt->cur;
7241 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7242 ((*in >= 0x41) && (*in <= 0x5A)) ||
7243 (*in == '_')) {
7244 in++;
7245 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7246 ((*in >= 0x41) && (*in <= 0x5A)) ||
7247 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007248 (*in == '_') || (*in == '.') ||
7249 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007250 in++;
7251 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7252 (*in == '[') || (*in == ']') || (*in == ':') ||
7253 (*in == '@') || (*in == '*')) {
7254 count = in - ctxt->cur;
7255 if (count == 0)
7256 return(NULL);
7257 ret = xmlStrndup(ctxt->cur, count);
7258 ctxt->cur = in;
7259 return(ret);
7260 }
7261 }
7262 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007263}
7264
Daniel Veillard2156a562001-04-28 12:24:34 +00007265
Owen Taylor3473f882001-02-23 17:55:21 +00007266/**
7267 * xmlXPathParseQName:
7268 * @ctxt: the XPath Parser context
7269 * @prefix: a xmlChar **
7270 *
7271 * parse an XML qualified name
7272 *
7273 * [NS 5] QName ::= (Prefix ':')? LocalPart
7274 *
7275 * [NS 6] Prefix ::= NCName
7276 *
7277 * [NS 7] LocalPart ::= NCName
7278 *
7279 * Returns the function returns the local part, and prefix is updated
7280 * to get the Prefix if any.
7281 */
7282
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007283static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007284xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7285 xmlChar *ret = NULL;
7286
7287 *prefix = NULL;
7288 ret = xmlXPathParseNCName(ctxt);
7289 if (CUR == ':') {
7290 *prefix = ret;
7291 NEXT;
7292 ret = xmlXPathParseNCName(ctxt);
7293 }
7294 return(ret);
7295}
7296
7297/**
7298 * xmlXPathParseName:
7299 * @ctxt: the XPath Parser context
7300 *
7301 * parse an XML name
7302 *
7303 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7304 * CombiningChar | Extender
7305 *
7306 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7307 *
7308 * Returns the namespace name or NULL
7309 */
7310
7311xmlChar *
7312xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007313 const xmlChar *in;
7314 xmlChar *ret;
7315 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007316
Daniel Veillard61d80a22001-04-27 17:13:01 +00007317 /*
7318 * Accelerator for simple ASCII names
7319 */
7320 in = ctxt->cur;
7321 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7322 ((*in >= 0x41) && (*in <= 0x5A)) ||
7323 (*in == '_') || (*in == ':')) {
7324 in++;
7325 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7326 ((*in >= 0x41) && (*in <= 0x5A)) ||
7327 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007328 (*in == '_') || (*in == '-') ||
7329 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007330 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007331 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007332 count = in - ctxt->cur;
7333 ret = xmlStrndup(ctxt->cur, count);
7334 ctxt->cur = in;
7335 return(ret);
7336 }
7337 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007338 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007339}
7340
Daniel Veillard61d80a22001-04-27 17:13:01 +00007341static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007342xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007343 xmlChar buf[XML_MAX_NAMELEN + 5];
7344 int len = 0, l;
7345 int c;
7346
7347 /*
7348 * Handler for more complex cases
7349 */
7350 c = CUR_CHAR(l);
7351 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007352 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7353 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007354 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007355 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007356 return(NULL);
7357 }
7358
7359 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7360 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7361 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007362 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007363 (IS_COMBINING(c)) ||
7364 (IS_EXTENDER(c)))) {
7365 COPY_BUF(l,buf,len,c);
7366 NEXTL(l);
7367 c = CUR_CHAR(l);
7368 if (len >= XML_MAX_NAMELEN) {
7369 /*
7370 * Okay someone managed to make a huge name, so he's ready to pay
7371 * for the processing speed.
7372 */
7373 xmlChar *buffer;
7374 int max = len * 2;
7375
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007376 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007377 if (buffer == NULL) {
7378 XP_ERROR0(XPATH_MEMORY_ERROR);
7379 }
7380 memcpy(buffer, buf, len);
7381 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7382 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007383 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007384 (IS_COMBINING(c)) ||
7385 (IS_EXTENDER(c))) {
7386 if (len + 10 > max) {
7387 max *= 2;
7388 buffer = (xmlChar *) xmlRealloc(buffer,
7389 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007390 if (buffer == NULL) {
7391 XP_ERROR0(XPATH_MEMORY_ERROR);
7392 }
7393 }
7394 COPY_BUF(l,buffer,len,c);
7395 NEXTL(l);
7396 c = CUR_CHAR(l);
7397 }
7398 buffer[len] = 0;
7399 return(buffer);
7400 }
7401 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007402 if (len == 0)
7403 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007404 return(xmlStrndup(buf, len));
7405}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007406
7407#define MAX_FRAC 20
7408
7409static double my_pow10[MAX_FRAC] = {
7410 1.0, 10.0, 100.0, 1000.0, 10000.0,
7411 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7412 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7413 100000000000000.0,
7414 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7415 1000000000000000000.0, 10000000000000000000.0
7416};
7417
Owen Taylor3473f882001-02-23 17:55:21 +00007418/**
7419 * xmlXPathStringEvalNumber:
7420 * @str: A string to scan
7421 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007422 * [30a] Float ::= Number ('e' Digits?)?
7423 *
Owen Taylor3473f882001-02-23 17:55:21 +00007424 * [30] Number ::= Digits ('.' Digits?)?
7425 * | '.' Digits
7426 * [31] Digits ::= [0-9]+
7427 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007428 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007429 * In complement of the Number expression, this function also handles
7430 * negative values : '-' Number.
7431 *
7432 * Returns the double value.
7433 */
7434double
7435xmlXPathStringEvalNumber(const xmlChar *str) {
7436 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007437 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007438 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007439 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007440 int exponent = 0;
7441 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007442#ifdef __GNUC__
7443 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007444 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007445#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007446 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007447 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007448 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7449 return(xmlXPathNAN);
7450 }
7451 if (*cur == '-') {
7452 isneg = 1;
7453 cur++;
7454 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007455
7456#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007457 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007458 * tmp/temp is a workaround against a gcc compiler bug
7459 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007460 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007461 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007462 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007463 ret = ret * 10;
7464 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007465 ok = 1;
7466 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007467 temp = (double) tmp;
7468 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007469 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007470#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007471 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007472 while ((*cur >= '0') && (*cur <= '9')) {
7473 ret = ret * 10 + (*cur - '0');
7474 ok = 1;
7475 cur++;
7476 }
7477#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007478
Owen Taylor3473f882001-02-23 17:55:21 +00007479 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007480 int v, frac = 0;
7481 double fraction = 0;
7482
Owen Taylor3473f882001-02-23 17:55:21 +00007483 cur++;
7484 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7485 return(xmlXPathNAN);
7486 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007487 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7488 v = (*cur - '0');
7489 fraction = fraction * 10 + v;
7490 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007491 cur++;
7492 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007493 fraction /= my_pow10[frac];
7494 ret = ret + fraction;
7495 while ((*cur >= '0') && (*cur <= '9'))
7496 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007497 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007498 if ((*cur == 'e') || (*cur == 'E')) {
7499 cur++;
7500 if (*cur == '-') {
7501 is_exponent_negative = 1;
7502 cur++;
7503 }
7504 while ((*cur >= '0') && (*cur <= '9')) {
7505 exponent = exponent * 10 + (*cur - '0');
7506 cur++;
7507 }
7508 }
William M. Brack76e95df2003-10-18 16:20:14 +00007509 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007510 if (*cur != 0) return(xmlXPathNAN);
7511 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007512 if (is_exponent_negative) exponent = -exponent;
7513 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007514 return(ret);
7515}
7516
7517/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007518 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007519 * @ctxt: the XPath Parser context
7520 *
7521 * [30] Number ::= Digits ('.' Digits?)?
7522 * | '.' Digits
7523 * [31] Digits ::= [0-9]+
7524 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007525 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007526 *
7527 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007528static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007529xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7530{
Owen Taylor3473f882001-02-23 17:55:21 +00007531 double ret = 0.0;
7532 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007533 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007534 int exponent = 0;
7535 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007536#ifdef __GNUC__
7537 unsigned long tmp = 0;
7538 double temp;
7539#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007540
7541 CHECK_ERROR;
7542 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7543 XP_ERROR(XPATH_NUMBER_ERROR);
7544 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007545#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007546 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007547 * tmp/temp is a workaround against a gcc compiler bug
7548 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007549 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007550 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007551 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007552 ret = ret * 10;
7553 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007554 ok = 1;
7555 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007556 temp = (double) tmp;
7557 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007558 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007559#else
7560 ret = 0;
7561 while ((CUR >= '0') && (CUR <= '9')) {
7562 ret = ret * 10 + (CUR - '0');
7563 ok = 1;
7564 NEXT;
7565 }
7566#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007567 if (CUR == '.') {
7568 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007569 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7570 XP_ERROR(XPATH_NUMBER_ERROR);
7571 }
7572 while ((CUR >= '0') && (CUR <= '9')) {
7573 mult /= 10;
7574 ret = ret + (CUR - '0') * mult;
7575 NEXT;
7576 }
Owen Taylor3473f882001-02-23 17:55:21 +00007577 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007578 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007579 NEXT;
7580 if (CUR == '-') {
7581 is_exponent_negative = 1;
7582 NEXT;
7583 }
7584 while ((CUR >= '0') && (CUR <= '9')) {
7585 exponent = exponent * 10 + (CUR - '0');
7586 NEXT;
7587 }
7588 if (is_exponent_negative)
7589 exponent = -exponent;
7590 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007591 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007592 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007593 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007594}
7595
7596/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007597 * xmlXPathParseLiteral:
7598 * @ctxt: the XPath Parser context
7599 *
7600 * Parse a Literal
7601 *
7602 * [29] Literal ::= '"' [^"]* '"'
7603 * | "'" [^']* "'"
7604 *
7605 * Returns the value found or NULL in case of error
7606 */
7607static xmlChar *
7608xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7609 const xmlChar *q;
7610 xmlChar *ret = NULL;
7611
7612 if (CUR == '"') {
7613 NEXT;
7614 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007615 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007616 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007617 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007618 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7619 } else {
7620 ret = xmlStrndup(q, CUR_PTR - q);
7621 NEXT;
7622 }
7623 } else if (CUR == '\'') {
7624 NEXT;
7625 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007626 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007627 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007628 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007629 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7630 } else {
7631 ret = xmlStrndup(q, CUR_PTR - q);
7632 NEXT;
7633 }
7634 } else {
7635 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7636 }
7637 return(ret);
7638}
7639
7640/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007641 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007642 * @ctxt: the XPath Parser context
7643 *
7644 * Parse a Literal and push it on the stack.
7645 *
7646 * [29] Literal ::= '"' [^"]* '"'
7647 * | "'" [^']* "'"
7648 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007649 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007650 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007651static void
7652xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007653 const xmlChar *q;
7654 xmlChar *ret = NULL;
7655
7656 if (CUR == '"') {
7657 NEXT;
7658 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007659 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007660 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007661 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007662 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7663 } else {
7664 ret = xmlStrndup(q, CUR_PTR - q);
7665 NEXT;
7666 }
7667 } else if (CUR == '\'') {
7668 NEXT;
7669 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007670 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007671 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007672 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007673 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7674 } else {
7675 ret = xmlStrndup(q, CUR_PTR - q);
7676 NEXT;
7677 }
7678 } else {
7679 XP_ERROR(XPATH_START_LITERAL_ERROR);
7680 }
7681 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007682 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7683 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007684 xmlFree(ret);
7685}
7686
7687/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007688 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007689 * @ctxt: the XPath Parser context
7690 *
7691 * Parse a VariableReference, evaluate it and push it on the stack.
7692 *
7693 * The variable bindings consist of a mapping from variable names
7694 * to variable values. The value of a variable is an object, which
7695 * of any of the types that are possible for the value of an expression,
7696 * and may also be of additional types not specified here.
7697 *
7698 * Early evaluation is possible since:
7699 * The variable bindings [...] used to evaluate a subexpression are
7700 * always the same as those used to evaluate the containing expression.
7701 *
7702 * [36] VariableReference ::= '$' QName
7703 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007704static void
7705xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007706 xmlChar *name;
7707 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007708
7709 SKIP_BLANKS;
7710 if (CUR != '$') {
7711 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7712 }
7713 NEXT;
7714 name = xmlXPathParseQName(ctxt, &prefix);
7715 if (name == NULL) {
7716 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7717 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007718 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007719 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7720 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007721 SKIP_BLANKS;
7722}
7723
7724/**
7725 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007726 * @name: a name string
7727 *
7728 * Is the name given a NodeType one.
7729 *
7730 * [38] NodeType ::= 'comment'
7731 * | 'text'
7732 * | 'processing-instruction'
7733 * | 'node'
7734 *
7735 * Returns 1 if true 0 otherwise
7736 */
7737int
7738xmlXPathIsNodeType(const xmlChar *name) {
7739 if (name == NULL)
7740 return(0);
7741
Daniel Veillard1971ee22002-01-31 20:29:19 +00007742 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007743 return(1);
7744 if (xmlStrEqual(name, BAD_CAST "text"))
7745 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007746 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007747 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007748 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007749 return(1);
7750 return(0);
7751}
7752
7753/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007754 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007755 * @ctxt: the XPath Parser context
7756 *
7757 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7758 * [17] Argument ::= Expr
7759 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007760 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007761 * pushed on the stack
7762 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007763static void
7764xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007765 xmlChar *name;
7766 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007767 int nbargs = 0;
7768
7769 name = xmlXPathParseQName(ctxt, &prefix);
7770 if (name == NULL) {
7771 XP_ERROR(XPATH_EXPR_ERROR);
7772 }
7773 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007774#ifdef DEBUG_EXPR
7775 if (prefix == NULL)
7776 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7777 name);
7778 else
7779 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7780 prefix, name);
7781#endif
7782
Owen Taylor3473f882001-02-23 17:55:21 +00007783 if (CUR != '(') {
7784 XP_ERROR(XPATH_EXPR_ERROR);
7785 }
7786 NEXT;
7787 SKIP_BLANKS;
7788
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007789 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007790 if (CUR != ')') {
7791 while (CUR != 0) {
7792 int op1 = ctxt->comp->last;
7793 ctxt->comp->last = -1;
7794 xmlXPathCompileExpr(ctxt);
7795 CHECK_ERROR;
7796 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7797 nbargs++;
7798 if (CUR == ')') break;
7799 if (CUR != ',') {
7800 XP_ERROR(XPATH_EXPR_ERROR);
7801 }
7802 NEXT;
7803 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007804 }
Owen Taylor3473f882001-02-23 17:55:21 +00007805 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007806 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7807 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007808 NEXT;
7809 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007810}
7811
7812/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007813 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007814 * @ctxt: the XPath Parser context
7815 *
7816 * [15] PrimaryExpr ::= VariableReference
7817 * | '(' Expr ')'
7818 * | Literal
7819 * | Number
7820 * | FunctionCall
7821 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007822 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007823 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007824static void
7825xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007826 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007827 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007828 else if (CUR == '(') {
7829 NEXT;
7830 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007831 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007832 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007833 if (CUR != ')') {
7834 XP_ERROR(XPATH_EXPR_ERROR);
7835 }
7836 NEXT;
7837 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007838 } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007839 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007840 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007841 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007842 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007843 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007844 }
7845 SKIP_BLANKS;
7846}
7847
7848/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007849 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007850 * @ctxt: the XPath Parser context
7851 *
7852 * [20] FilterExpr ::= PrimaryExpr
7853 * | FilterExpr Predicate
7854 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007855 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007856 * Square brackets are used to filter expressions in the same way that
7857 * they are used in location paths. It is an error if the expression to
7858 * be filtered does not evaluate to a node-set. The context node list
7859 * used for evaluating the expression in square brackets is the node-set
7860 * to be filtered listed in document order.
7861 */
7862
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007863static void
7864xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7865 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007866 CHECK_ERROR;
7867 SKIP_BLANKS;
7868
7869 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007870 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007871 SKIP_BLANKS;
7872 }
7873
7874
7875}
7876
7877/**
7878 * xmlXPathScanName:
7879 * @ctxt: the XPath Parser context
7880 *
7881 * Trickery: parse an XML name but without consuming the input flow
7882 * Needed to avoid insanity in the parser state.
7883 *
7884 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7885 * CombiningChar | Extender
7886 *
7887 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7888 *
7889 * [6] Names ::= Name (S Name)*
7890 *
7891 * Returns the Name parsed or NULL
7892 */
7893
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007894static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007895xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7896 xmlChar buf[XML_MAX_NAMELEN];
7897 int len = 0;
7898
7899 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007900 if (!IS_LETTER_CH(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00007901 (CUR != ':')) {
7902 return(NULL);
7903 }
7904
William M. Brack76e95df2003-10-18 16:20:14 +00007905 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007906 (NXT(len) == '.') || (NXT(len) == '-') ||
7907 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007908 (IS_COMBINING_CH(NXT(len))) ||
7909 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007910 buf[len] = NXT(len);
7911 len++;
7912 if (len >= XML_MAX_NAMELEN) {
7913 xmlGenericError(xmlGenericErrorContext,
7914 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brack76e95df2003-10-18 16:20:14 +00007915 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007916 (NXT(len) == '.') || (NXT(len) == '-') ||
7917 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007918 (IS_COMBINING_CH(NXT(len))) ||
7919 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00007920 len++;
7921 break;
7922 }
7923 }
7924 return(xmlStrndup(buf, len));
7925}
7926
7927/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007928 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007929 * @ctxt: the XPath Parser context
7930 *
7931 * [19] PathExpr ::= LocationPath
7932 * | FilterExpr
7933 * | FilterExpr '/' RelativeLocationPath
7934 * | FilterExpr '//' RelativeLocationPath
7935 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007936 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007937 * The / operator and // operators combine an arbitrary expression
7938 * and a relative location path. It is an error if the expression
7939 * does not evaluate to a node-set.
7940 * The / operator does composition in the same way as when / is
7941 * used in a location path. As in location paths, // is short for
7942 * /descendant-or-self::node()/.
7943 */
7944
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007945static void
7946xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007947 int lc = 1; /* Should we branch to LocationPath ? */
7948 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7949
7950 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007951 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
7952 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007953 lc = 0;
7954 } else if (CUR == '*') {
7955 /* relative or absolute location path */
7956 lc = 1;
7957 } else if (CUR == '/') {
7958 /* relative or absolute location path */
7959 lc = 1;
7960 } else if (CUR == '@') {
7961 /* relative abbreviated attribute location path */
7962 lc = 1;
7963 } else if (CUR == '.') {
7964 /* relative abbreviated attribute location path */
7965 lc = 1;
7966 } else {
7967 /*
7968 * Problem is finding if we have a name here whether it's:
7969 * - a nodetype
7970 * - a function call in which case it's followed by '('
7971 * - an axis in which case it's followed by ':'
7972 * - a element name
7973 * We do an a priori analysis here rather than having to
7974 * maintain parsed token content through the recursive function
7975 * calls. This looks uglier but makes the code quite easier to
7976 * read/write/debug.
7977 */
7978 SKIP_BLANKS;
7979 name = xmlXPathScanName(ctxt);
7980 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7981#ifdef DEBUG_STEP
7982 xmlGenericError(xmlGenericErrorContext,
7983 "PathExpr: Axis\n");
7984#endif
7985 lc = 1;
7986 xmlFree(name);
7987 } else if (name != NULL) {
7988 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00007989
7990
7991 while (NXT(len) != 0) {
7992 if (NXT(len) == '/') {
7993 /* element name */
7994#ifdef DEBUG_STEP
7995 xmlGenericError(xmlGenericErrorContext,
7996 "PathExpr: AbbrRelLocation\n");
7997#endif
7998 lc = 1;
7999 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008000 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008001 /* ignore blanks */
8002 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008003 } else if (NXT(len) == ':') {
8004#ifdef DEBUG_STEP
8005 xmlGenericError(xmlGenericErrorContext,
8006 "PathExpr: AbbrRelLocation\n");
8007#endif
8008 lc = 1;
8009 break;
8010 } else if ((NXT(len) == '(')) {
8011 /* Note Type or Function */
8012 if (xmlXPathIsNodeType(name)) {
8013#ifdef DEBUG_STEP
8014 xmlGenericError(xmlGenericErrorContext,
8015 "PathExpr: Type search\n");
8016#endif
8017 lc = 1;
8018 } else {
8019#ifdef DEBUG_STEP
8020 xmlGenericError(xmlGenericErrorContext,
8021 "PathExpr: function call\n");
8022#endif
8023 lc = 0;
8024 }
8025 break;
8026 } else if ((NXT(len) == '[')) {
8027 /* element name */
8028#ifdef DEBUG_STEP
8029 xmlGenericError(xmlGenericErrorContext,
8030 "PathExpr: AbbrRelLocation\n");
8031#endif
8032 lc = 1;
8033 break;
8034 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8035 (NXT(len) == '=')) {
8036 lc = 1;
8037 break;
8038 } else {
8039 lc = 1;
8040 break;
8041 }
8042 len++;
8043 }
8044 if (NXT(len) == 0) {
8045#ifdef DEBUG_STEP
8046 xmlGenericError(xmlGenericErrorContext,
8047 "PathExpr: AbbrRelLocation\n");
8048#endif
8049 /* element name */
8050 lc = 1;
8051 }
8052 xmlFree(name);
8053 } else {
8054 /* make sure all cases are covered explicitely */
8055 XP_ERROR(XPATH_EXPR_ERROR);
8056 }
8057 }
8058
8059 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008060 if (CUR == '/') {
8061 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8062 } else {
8063 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008064 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008065 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008066 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008067 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008068 CHECK_ERROR;
8069 if ((CUR == '/') && (NXT(1) == '/')) {
8070 SKIP(2);
8071 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008072
8073 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8074 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8075 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8076
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008077 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008078 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008079 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008080 }
8081 }
8082 SKIP_BLANKS;
8083}
8084
8085/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008086 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008087 * @ctxt: the XPath Parser context
8088 *
8089 * [18] UnionExpr ::= PathExpr
8090 * | UnionExpr '|' PathExpr
8091 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008092 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008093 */
8094
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008095static void
8096xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8097 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008098 CHECK_ERROR;
8099 SKIP_BLANKS;
8100 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008101 int op1 = ctxt->comp->last;
8102 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008103
8104 NEXT;
8105 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008106 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008107
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008108 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8109
Owen Taylor3473f882001-02-23 17:55:21 +00008110 SKIP_BLANKS;
8111 }
Owen Taylor3473f882001-02-23 17:55:21 +00008112}
8113
8114/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008115 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008116 * @ctxt: the XPath Parser context
8117 *
8118 * [27] UnaryExpr ::= UnionExpr
8119 * | '-' UnaryExpr
8120 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008121 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008122 */
8123
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008124static void
8125xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008126 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008127 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008128
8129 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008130 while (CUR == '-') {
8131 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008132 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008133 NEXT;
8134 SKIP_BLANKS;
8135 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008136
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008137 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008138 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008139 if (found) {
8140 if (minus)
8141 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8142 else
8143 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008144 }
8145}
8146
8147/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008148 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008149 * @ctxt: the XPath Parser context
8150 *
8151 * [26] MultiplicativeExpr ::= UnaryExpr
8152 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8153 * | MultiplicativeExpr 'div' UnaryExpr
8154 * | MultiplicativeExpr 'mod' UnaryExpr
8155 * [34] MultiplyOperator ::= '*'
8156 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008157 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008158 */
8159
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008160static void
8161xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8162 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008163 CHECK_ERROR;
8164 SKIP_BLANKS;
8165 while ((CUR == '*') ||
8166 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8167 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8168 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008169 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008170
8171 if (CUR == '*') {
8172 op = 0;
8173 NEXT;
8174 } else if (CUR == 'd') {
8175 op = 1;
8176 SKIP(3);
8177 } else if (CUR == 'm') {
8178 op = 2;
8179 SKIP(3);
8180 }
8181 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008182 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008183 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008184 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008185 SKIP_BLANKS;
8186 }
8187}
8188
8189/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008190 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008191 * @ctxt: the XPath Parser context
8192 *
8193 * [25] AdditiveExpr ::= MultiplicativeExpr
8194 * | AdditiveExpr '+' MultiplicativeExpr
8195 * | AdditiveExpr '-' MultiplicativeExpr
8196 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008197 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008198 */
8199
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008200static void
8201xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008202
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008203 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008204 CHECK_ERROR;
8205 SKIP_BLANKS;
8206 while ((CUR == '+') || (CUR == '-')) {
8207 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008208 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008209
8210 if (CUR == '+') plus = 1;
8211 else plus = 0;
8212 NEXT;
8213 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008214 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008215 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008216 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008217 SKIP_BLANKS;
8218 }
8219}
8220
8221/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008222 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008223 * @ctxt: the XPath Parser context
8224 *
8225 * [24] RelationalExpr ::= AdditiveExpr
8226 * | RelationalExpr '<' AdditiveExpr
8227 * | RelationalExpr '>' AdditiveExpr
8228 * | RelationalExpr '<=' AdditiveExpr
8229 * | RelationalExpr '>=' AdditiveExpr
8230 *
8231 * A <= B > C is allowed ? Answer from James, yes with
8232 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8233 * which is basically what got implemented.
8234 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008235 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008236 * on the stack
8237 */
8238
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008239static void
8240xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8241 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008242 CHECK_ERROR;
8243 SKIP_BLANKS;
8244 while ((CUR == '<') ||
8245 (CUR == '>') ||
8246 ((CUR == '<') && (NXT(1) == '=')) ||
8247 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008248 int inf, strict;
8249 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008250
8251 if (CUR == '<') inf = 1;
8252 else inf = 0;
8253 if (NXT(1) == '=') strict = 0;
8254 else strict = 1;
8255 NEXT;
8256 if (!strict) NEXT;
8257 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008258 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008259 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008260 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008261 SKIP_BLANKS;
8262 }
8263}
8264
8265/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008266 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008267 * @ctxt: the XPath Parser context
8268 *
8269 * [23] EqualityExpr ::= RelationalExpr
8270 * | EqualityExpr '=' RelationalExpr
8271 * | EqualityExpr '!=' RelationalExpr
8272 *
8273 * A != B != C is allowed ? Answer from James, yes with
8274 * (RelationalExpr = RelationalExpr) = RelationalExpr
8275 * (RelationalExpr != RelationalExpr) != RelationalExpr
8276 * which is basically what got implemented.
8277 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008278 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008279 *
8280 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008281static void
8282xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8283 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008284 CHECK_ERROR;
8285 SKIP_BLANKS;
8286 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008287 int eq;
8288 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008289
8290 if (CUR == '=') eq = 1;
8291 else eq = 0;
8292 NEXT;
8293 if (!eq) NEXT;
8294 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008295 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008296 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008297 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008298 SKIP_BLANKS;
8299 }
8300}
8301
8302/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008303 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008304 * @ctxt: the XPath Parser context
8305 *
8306 * [22] AndExpr ::= EqualityExpr
8307 * | AndExpr 'and' EqualityExpr
8308 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008309 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008310 *
8311 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008312static void
8313xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8314 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008315 CHECK_ERROR;
8316 SKIP_BLANKS;
8317 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008318 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008319 SKIP(3);
8320 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008321 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008322 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008323 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008324 SKIP_BLANKS;
8325 }
8326}
8327
8328/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008329 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008330 * @ctxt: the XPath Parser context
8331 *
8332 * [14] Expr ::= OrExpr
8333 * [21] OrExpr ::= AndExpr
8334 * | OrExpr 'or' AndExpr
8335 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008336 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008337 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008338static void
8339xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8340 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008341 CHECK_ERROR;
8342 SKIP_BLANKS;
8343 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008344 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008345 SKIP(2);
8346 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008347 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008348 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008349 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8350 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008351 SKIP_BLANKS;
8352 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008353 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8354 /* more ops could be optimized too */
8355 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8356 }
Owen Taylor3473f882001-02-23 17:55:21 +00008357}
8358
8359/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008360 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008361 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008362 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008363 *
8364 * [8] Predicate ::= '[' PredicateExpr ']'
8365 * [9] PredicateExpr ::= Expr
8366 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008367 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008368 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008369static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008370xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008371 int op1 = ctxt->comp->last;
8372
8373 SKIP_BLANKS;
8374 if (CUR != '[') {
8375 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8376 }
8377 NEXT;
8378 SKIP_BLANKS;
8379
8380 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008381 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008382 CHECK_ERROR;
8383
8384 if (CUR != ']') {
8385 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8386 }
8387
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008388 if (filter)
8389 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8390 else
8391 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008392
8393 NEXT;
8394 SKIP_BLANKS;
8395}
8396
8397/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008398 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008399 * @ctxt: the XPath Parser context
8400 * @test: pointer to a xmlXPathTestVal
8401 * @type: pointer to a xmlXPathTypeVal
8402 * @prefix: placeholder for a possible name prefix
8403 *
8404 * [7] NodeTest ::= NameTest
8405 * | NodeType '(' ')'
8406 * | 'processing-instruction' '(' Literal ')'
8407 *
8408 * [37] NameTest ::= '*'
8409 * | NCName ':' '*'
8410 * | QName
8411 * [38] NodeType ::= 'comment'
8412 * | 'text'
8413 * | 'processing-instruction'
8414 * | 'node'
8415 *
8416 * Returns the name found and update @test, @type and @prefix appropriately
8417 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008418static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008419xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8420 xmlXPathTypeVal *type, const xmlChar **prefix,
8421 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008422 int blanks;
8423
8424 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8425 STRANGE;
8426 return(NULL);
8427 }
William M. Brack78637da2003-07-31 14:47:38 +00008428 *type = (xmlXPathTypeVal) 0;
8429 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008430 *prefix = NULL;
8431 SKIP_BLANKS;
8432
8433 if ((name == NULL) && (CUR == '*')) {
8434 /*
8435 * All elements
8436 */
8437 NEXT;
8438 *test = NODE_TEST_ALL;
8439 return(NULL);
8440 }
8441
8442 if (name == NULL)
8443 name = xmlXPathParseNCName(ctxt);
8444 if (name == NULL) {
8445 XP_ERROR0(XPATH_EXPR_ERROR);
8446 }
8447
William M. Brack76e95df2003-10-18 16:20:14 +00008448 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008449 SKIP_BLANKS;
8450 if (CUR == '(') {
8451 NEXT;
8452 /*
8453 * NodeType or PI search
8454 */
8455 if (xmlStrEqual(name, BAD_CAST "comment"))
8456 *type = NODE_TYPE_COMMENT;
8457 else if (xmlStrEqual(name, BAD_CAST "node"))
8458 *type = NODE_TYPE_NODE;
8459 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8460 *type = NODE_TYPE_PI;
8461 else if (xmlStrEqual(name, BAD_CAST "text"))
8462 *type = NODE_TYPE_TEXT;
8463 else {
8464 if (name != NULL)
8465 xmlFree(name);
8466 XP_ERROR0(XPATH_EXPR_ERROR);
8467 }
8468
8469 *test = NODE_TEST_TYPE;
8470
8471 SKIP_BLANKS;
8472 if (*type == NODE_TYPE_PI) {
8473 /*
8474 * Specific case: search a PI by name.
8475 */
Owen Taylor3473f882001-02-23 17:55:21 +00008476 if (name != NULL)
8477 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008478 name = NULL;
8479 if (CUR != ')') {
8480 name = xmlXPathParseLiteral(ctxt);
8481 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008482 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008483 SKIP_BLANKS;
8484 }
Owen Taylor3473f882001-02-23 17:55:21 +00008485 }
8486 if (CUR != ')') {
8487 if (name != NULL)
8488 xmlFree(name);
8489 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8490 }
8491 NEXT;
8492 return(name);
8493 }
8494 *test = NODE_TEST_NAME;
8495 if ((!blanks) && (CUR == ':')) {
8496 NEXT;
8497
8498 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008499 * Since currently the parser context don't have a
8500 * namespace list associated:
8501 * The namespace name for this prefix can be computed
8502 * only at evaluation time. The compilation is done
8503 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008504 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008505#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008506 *prefix = xmlXPathNsLookup(ctxt->context, name);
8507 if (name != NULL)
8508 xmlFree(name);
8509 if (*prefix == NULL) {
8510 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8511 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008512#else
8513 *prefix = name;
8514#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008515
8516 if (CUR == '*') {
8517 /*
8518 * All elements
8519 */
8520 NEXT;
8521 *test = NODE_TEST_ALL;
8522 return(NULL);
8523 }
8524
8525 name = xmlXPathParseNCName(ctxt);
8526 if (name == NULL) {
8527 XP_ERROR0(XPATH_EXPR_ERROR);
8528 }
8529 }
8530 return(name);
8531}
8532
8533/**
8534 * xmlXPathIsAxisName:
8535 * @name: a preparsed name token
8536 *
8537 * [6] AxisName ::= 'ancestor'
8538 * | 'ancestor-or-self'
8539 * | 'attribute'
8540 * | 'child'
8541 * | 'descendant'
8542 * | 'descendant-or-self'
8543 * | 'following'
8544 * | 'following-sibling'
8545 * | 'namespace'
8546 * | 'parent'
8547 * | 'preceding'
8548 * | 'preceding-sibling'
8549 * | 'self'
8550 *
8551 * Returns the axis or 0
8552 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008553static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008554xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008555 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008556 switch (name[0]) {
8557 case 'a':
8558 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8559 ret = AXIS_ANCESTOR;
8560 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8561 ret = AXIS_ANCESTOR_OR_SELF;
8562 if (xmlStrEqual(name, BAD_CAST "attribute"))
8563 ret = AXIS_ATTRIBUTE;
8564 break;
8565 case 'c':
8566 if (xmlStrEqual(name, BAD_CAST "child"))
8567 ret = AXIS_CHILD;
8568 break;
8569 case 'd':
8570 if (xmlStrEqual(name, BAD_CAST "descendant"))
8571 ret = AXIS_DESCENDANT;
8572 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8573 ret = AXIS_DESCENDANT_OR_SELF;
8574 break;
8575 case 'f':
8576 if (xmlStrEqual(name, BAD_CAST "following"))
8577 ret = AXIS_FOLLOWING;
8578 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8579 ret = AXIS_FOLLOWING_SIBLING;
8580 break;
8581 case 'n':
8582 if (xmlStrEqual(name, BAD_CAST "namespace"))
8583 ret = AXIS_NAMESPACE;
8584 break;
8585 case 'p':
8586 if (xmlStrEqual(name, BAD_CAST "parent"))
8587 ret = AXIS_PARENT;
8588 if (xmlStrEqual(name, BAD_CAST "preceding"))
8589 ret = AXIS_PRECEDING;
8590 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8591 ret = AXIS_PRECEDING_SIBLING;
8592 break;
8593 case 's':
8594 if (xmlStrEqual(name, BAD_CAST "self"))
8595 ret = AXIS_SELF;
8596 break;
8597 }
8598 return(ret);
8599}
8600
8601/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008602 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008603 * @ctxt: the XPath Parser context
8604 *
8605 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8606 * | AbbreviatedStep
8607 *
8608 * [12] AbbreviatedStep ::= '.' | '..'
8609 *
8610 * [5] AxisSpecifier ::= AxisName '::'
8611 * | AbbreviatedAxisSpecifier
8612 *
8613 * [13] AbbreviatedAxisSpecifier ::= '@'?
8614 *
8615 * Modified for XPtr range support as:
8616 *
8617 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8618 * | AbbreviatedStep
8619 * | 'range-to' '(' Expr ')' Predicate*
8620 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008621 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008622 * A location step of . is short for self::node(). This is
8623 * particularly useful in conjunction with //. For example, the
8624 * location path .//para is short for
8625 * self::node()/descendant-or-self::node()/child::para
8626 * and so will select all para descendant elements of the context
8627 * node.
8628 * Similarly, a location step of .. is short for parent::node().
8629 * For example, ../title is short for parent::node()/child::title
8630 * and so will select the title children of the parent of the context
8631 * node.
8632 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008633static void
8634xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008635#ifdef LIBXML_XPTR_ENABLED
8636 int rangeto = 0;
8637 int op2 = -1;
8638#endif
8639
Owen Taylor3473f882001-02-23 17:55:21 +00008640 SKIP_BLANKS;
8641 if ((CUR == '.') && (NXT(1) == '.')) {
8642 SKIP(2);
8643 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008644 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8645 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008646 } else if (CUR == '.') {
8647 NEXT;
8648 SKIP_BLANKS;
8649 } else {
8650 xmlChar *name = NULL;
8651 const xmlChar *prefix = NULL;
8652 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008653 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008654 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008655 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008656
8657 /*
8658 * The modification needed for XPointer change to the production
8659 */
8660#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008661 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008662 name = xmlXPathParseNCName(ctxt);
8663 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008664 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008665 xmlFree(name);
8666 SKIP_BLANKS;
8667 if (CUR != '(') {
8668 XP_ERROR(XPATH_EXPR_ERROR);
8669 }
8670 NEXT;
8671 SKIP_BLANKS;
8672
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008673 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008674 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008675 CHECK_ERROR;
8676
8677 SKIP_BLANKS;
8678 if (CUR != ')') {
8679 XP_ERROR(XPATH_EXPR_ERROR);
8680 }
8681 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008682 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008683 goto eval_predicates;
8684 }
8685 }
8686#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008687 if (CUR == '*') {
8688 axis = AXIS_CHILD;
8689 } else {
8690 if (name == NULL)
8691 name = xmlXPathParseNCName(ctxt);
8692 if (name != NULL) {
8693 axis = xmlXPathIsAxisName(name);
8694 if (axis != 0) {
8695 SKIP_BLANKS;
8696 if ((CUR == ':') && (NXT(1) == ':')) {
8697 SKIP(2);
8698 xmlFree(name);
8699 name = NULL;
8700 } else {
8701 /* an element name can conflict with an axis one :-\ */
8702 axis = AXIS_CHILD;
8703 }
Owen Taylor3473f882001-02-23 17:55:21 +00008704 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008705 axis = AXIS_CHILD;
8706 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008707 } else if (CUR == '@') {
8708 NEXT;
8709 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008710 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008711 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008712 }
Owen Taylor3473f882001-02-23 17:55:21 +00008713 }
8714
8715 CHECK_ERROR;
8716
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008717 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008718 if (test == 0)
8719 return;
8720
8721#ifdef DEBUG_STEP
8722 xmlGenericError(xmlGenericErrorContext,
8723 "Basis : computing new set\n");
8724#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008725
Owen Taylor3473f882001-02-23 17:55:21 +00008726#ifdef DEBUG_STEP
8727 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008728 if (ctxt->value == NULL)
8729 xmlGenericError(xmlGenericErrorContext, "no value\n");
8730 else if (ctxt->value->nodesetval == NULL)
8731 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8732 else
8733 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008734#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008735
8736eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008737 op1 = ctxt->comp->last;
8738 ctxt->comp->last = -1;
8739
Owen Taylor3473f882001-02-23 17:55:21 +00008740 SKIP_BLANKS;
8741 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008742 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008743 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008744
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008745#ifdef LIBXML_XPTR_ENABLED
8746 if (rangeto) {
8747 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8748 } else
8749#endif
8750 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8751 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008752
Owen Taylor3473f882001-02-23 17:55:21 +00008753 }
8754#ifdef DEBUG_STEP
8755 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008756 if (ctxt->value == NULL)
8757 xmlGenericError(xmlGenericErrorContext, "no value\n");
8758 else if (ctxt->value->nodesetval == NULL)
8759 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8760 else
8761 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8762 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008763#endif
8764}
8765
8766/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008767 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008768 * @ctxt: the XPath Parser context
8769 *
8770 * [3] RelativeLocationPath ::= Step
8771 * | RelativeLocationPath '/' Step
8772 * | AbbreviatedRelativeLocationPath
8773 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8774 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008775 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008776 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008777static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008778xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008779(xmlXPathParserContextPtr ctxt) {
8780 SKIP_BLANKS;
8781 if ((CUR == '/') && (NXT(1) == '/')) {
8782 SKIP(2);
8783 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008784 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8785 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008786 } else if (CUR == '/') {
8787 NEXT;
8788 SKIP_BLANKS;
8789 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008790 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008791 SKIP_BLANKS;
8792 while (CUR == '/') {
8793 if ((CUR == '/') && (NXT(1) == '/')) {
8794 SKIP(2);
8795 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008796 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008797 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008798 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008799 } else if (CUR == '/') {
8800 NEXT;
8801 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008802 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008803 }
8804 SKIP_BLANKS;
8805 }
8806}
8807
8808/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008809 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008810 * @ctxt: the XPath Parser context
8811 *
8812 * [1] LocationPath ::= RelativeLocationPath
8813 * | AbsoluteLocationPath
8814 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8815 * | AbbreviatedAbsoluteLocationPath
8816 * [10] AbbreviatedAbsoluteLocationPath ::=
8817 * '//' RelativeLocationPath
8818 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008819 * Compile a location path
8820 *
Owen Taylor3473f882001-02-23 17:55:21 +00008821 * // is short for /descendant-or-self::node()/. For example,
8822 * //para is short for /descendant-or-self::node()/child::para and
8823 * so will select any para element in the document (even a para element
8824 * that is a document element will be selected by //para since the
8825 * document element node is a child of the root node); div//para is
8826 * short for div/descendant-or-self::node()/child::para and so will
8827 * select all para descendants of div children.
8828 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008829static void
8830xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008831 SKIP_BLANKS;
8832 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008833 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008834 } else {
8835 while (CUR == '/') {
8836 if ((CUR == '/') && (NXT(1) == '/')) {
8837 SKIP(2);
8838 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008839 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8840 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008841 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008842 } else if (CUR == '/') {
8843 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008844 SKIP_BLANKS;
8845 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008846 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008847 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008848 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008849 }
8850 }
8851 }
8852}
8853
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008854/************************************************************************
8855 * *
8856 * XPath precompiled expression evaluation *
8857 * *
8858 ************************************************************************/
8859
Daniel Veillardf06307e2001-07-03 10:35:50 +00008860static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008861xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8862
8863/**
8864 * xmlXPathNodeCollectAndTest:
8865 * @ctxt: the XPath Parser context
8866 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008867 * @first: pointer to the first element in document order
8868 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008869 *
8870 * This is the function implementing a step: based on the current list
8871 * of nodes, it builds up a new list, looking at all nodes under that
8872 * axis and selecting them it also do the predicate filtering
8873 *
8874 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 *
8876 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008877 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008878static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008879xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008880 xmlXPathStepOpPtr op,
8881 xmlNodePtr * first, xmlNodePtr * last)
8882{
William M. Brack78637da2003-07-31 14:47:38 +00008883 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8884 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8885 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008886 const xmlChar *prefix = op->value4;
8887 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008888 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008889
8890#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008891 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008892#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008893 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008894 xmlNodeSetPtr ret, list;
8895 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008896 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008897 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008898 xmlNodePtr cur = NULL;
8899 xmlXPathObjectPtr obj;
8900 xmlNodeSetPtr nodelist;
8901 xmlNodePtr tmp;
8902
Daniel Veillardf06307e2001-07-03 10:35:50 +00008903 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008904 obj = valuePop(ctxt);
8905 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008906 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008907 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008908 URI = xmlXPathNsLookup(ctxt->context, prefix);
8909 if (URI == NULL)
8910 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008911 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008912#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008913 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008914#endif
8915 switch (axis) {
8916 case AXIS_ANCESTOR:
8917#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008918 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008919#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008920 first = NULL;
8921 next = xmlXPathNextAncestor;
8922 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923 case AXIS_ANCESTOR_OR_SELF:
8924#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008925 xmlGenericError(xmlGenericErrorContext,
8926 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008927#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008928 first = NULL;
8929 next = xmlXPathNextAncestorOrSelf;
8930 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008931 case AXIS_ATTRIBUTE:
8932#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008933 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008934#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008935 first = NULL;
8936 last = NULL;
8937 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008938 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008939 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008940 case AXIS_CHILD:
8941#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008942 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008943#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008944 last = NULL;
8945 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008946 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008947 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008948 case AXIS_DESCENDANT:
8949#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008950 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008951#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008952 last = NULL;
8953 next = xmlXPathNextDescendant;
8954 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008955 case AXIS_DESCENDANT_OR_SELF:
8956#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008957 xmlGenericError(xmlGenericErrorContext,
8958 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008959#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008960 last = NULL;
8961 next = xmlXPathNextDescendantOrSelf;
8962 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008963 case AXIS_FOLLOWING:
8964#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008965 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008966#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008967 last = NULL;
8968 next = xmlXPathNextFollowing;
8969 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970 case AXIS_FOLLOWING_SIBLING:
8971#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972 xmlGenericError(xmlGenericErrorContext,
8973 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008974#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975 last = NULL;
8976 next = xmlXPathNextFollowingSibling;
8977 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008978 case AXIS_NAMESPACE:
8979#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008981#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982 first = NULL;
8983 last = NULL;
8984 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008985 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008986 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008987 case AXIS_PARENT:
8988#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008989 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008990#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008991 first = NULL;
8992 next = xmlXPathNextParent;
8993 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008994 case AXIS_PRECEDING:
8995#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008996 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008997#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008998 first = NULL;
8999 next = xmlXPathNextPrecedingInternal;
9000 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009001 case AXIS_PRECEDING_SIBLING:
9002#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009003 xmlGenericError(xmlGenericErrorContext,
9004 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009005#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009006 first = NULL;
9007 next = xmlXPathNextPrecedingSibling;
9008 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009009 case AXIS_SELF:
9010#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009012#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009013 first = NULL;
9014 last = NULL;
9015 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009016 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009017 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009018 }
9019 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009020 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009021
9022 nodelist = obj->nodesetval;
9023 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009024 xmlXPathFreeObject(obj);
9025 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9026 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009027 }
9028 addNode = xmlXPathNodeSetAddUnique;
9029 ret = NULL;
9030#ifdef DEBUG_STEP
9031 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009032 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009033 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009034 case NODE_TEST_NONE:
9035 xmlGenericError(xmlGenericErrorContext,
9036 " searching for none !!!\n");
9037 break;
9038 case NODE_TEST_TYPE:
9039 xmlGenericError(xmlGenericErrorContext,
9040 " searching for type %d\n", type);
9041 break;
9042 case NODE_TEST_PI:
9043 xmlGenericError(xmlGenericErrorContext,
9044 " searching for PI !!!\n");
9045 break;
9046 case NODE_TEST_ALL:
9047 xmlGenericError(xmlGenericErrorContext,
9048 " searching for *\n");
9049 break;
9050 case NODE_TEST_NS:
9051 xmlGenericError(xmlGenericErrorContext,
9052 " searching for namespace %s\n",
9053 prefix);
9054 break;
9055 case NODE_TEST_NAME:
9056 xmlGenericError(xmlGenericErrorContext,
9057 " searching for name %s\n", name);
9058 if (prefix != NULL)
9059 xmlGenericError(xmlGenericErrorContext,
9060 " with namespace %s\n", prefix);
9061 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009062 }
9063 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9064#endif
9065 /*
9066 * 2.3 Node Tests
9067 * - For the attribute axis, the principal node type is attribute.
9068 * - For the namespace axis, the principal node type is namespace.
9069 * - For other axes, the principal node type is element.
9070 *
9071 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009072 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009073 * select all element children of the context node
9074 */
9075 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009076 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009077 ctxt->context->node = nodelist->nodeTab[i];
9078
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 cur = NULL;
9080 list = xmlXPathNodeSetCreate(NULL);
9081 do {
9082 cur = next(ctxt, cur);
9083 if (cur == NULL)
9084 break;
9085 if ((first != NULL) && (*first == cur))
9086 break;
9087 if (((t % 256) == 0) &&
9088 (first != NULL) && (*first != NULL) &&
9089 (xmlXPathCmpNodes(*first, cur) >= 0))
9090 break;
9091 if ((last != NULL) && (*last == cur))
9092 break;
9093 if (((t % 256) == 0) &&
9094 (last != NULL) && (*last != NULL) &&
9095 (xmlXPathCmpNodes(cur, *last) >= 0))
9096 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009097 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009099 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9100#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009102 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 ctxt->context->node = tmp;
9104 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009105 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009106 if ((cur->type == type) ||
9107 ((type == NODE_TYPE_NODE) &&
9108 ((cur->type == XML_DOCUMENT_NODE) ||
9109 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9110 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009111 (cur->type == XML_NAMESPACE_DECL) ||
9112 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009113 (cur->type == XML_PI_NODE) ||
9114 (cur->type == XML_COMMENT_NODE) ||
9115 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009116 (cur->type == XML_TEXT_NODE))) ||
9117 ((type == NODE_TYPE_TEXT) &&
9118 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009119#ifdef DEBUG_STEP
9120 n++;
9121#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009122 addNode(list, cur);
9123 }
9124 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009125 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009126 if (cur->type == XML_PI_NODE) {
9127 if ((name != NULL) &&
9128 (!xmlStrEqual(name, cur->name)))
9129 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009130#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009132#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009133 addNode(list, cur);
9134 }
9135 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009136 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009137 if (axis == AXIS_ATTRIBUTE) {
9138 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009139#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009140 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009141#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009142 addNode(list, cur);
9143 }
9144 } else if (axis == AXIS_NAMESPACE) {
9145 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009146#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009147 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009148#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009149 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9150 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 }
9152 } else {
9153 if (cur->type == XML_ELEMENT_NODE) {
9154 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009155#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009156 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009157#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009158 addNode(list, cur);
9159 } else if ((cur->ns != NULL) &&
9160 (xmlStrEqual(URI, cur->ns->href))) {
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 }
9167 }
9168 break;
9169 case NODE_TEST_NS:{
9170 TODO;
9171 break;
9172 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009173 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009174 switch (cur->type) {
9175 case XML_ELEMENT_NODE:
9176 if (xmlStrEqual(name, cur->name)) {
9177 if (prefix == NULL) {
9178 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009179#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009180 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009181#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009182 addNode(list, cur);
9183 }
9184 } else {
9185 if ((cur->ns != NULL) &&
9186 (xmlStrEqual(URI,
9187 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009188#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009189 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009190#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009191 addNode(list, cur);
9192 }
9193 }
9194 }
9195 break;
9196 case XML_ATTRIBUTE_NODE:{
9197 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009198
Daniel Veillardf06307e2001-07-03 10:35:50 +00009199 if (xmlStrEqual(name, attr->name)) {
9200 if (prefix == NULL) {
9201 if ((attr->ns == NULL) ||
9202 (attr->ns->prefix == NULL)) {
9203#ifdef DEBUG_STEP
9204 n++;
9205#endif
9206 addNode(list,
9207 (xmlNodePtr) attr);
9208 }
9209 } else {
9210 if ((attr->ns != NULL) &&
9211 (xmlStrEqual(URI,
9212 attr->ns->
9213 href))) {
9214#ifdef DEBUG_STEP
9215 n++;
9216#endif
9217 addNode(list,
9218 (xmlNodePtr) attr);
9219 }
9220 }
9221 }
9222 break;
9223 }
9224 case XML_NAMESPACE_DECL:
9225 if (cur->type == XML_NAMESPACE_DECL) {
9226 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009227
Daniel Veillardf06307e2001-07-03 10:35:50 +00009228 if ((ns->prefix != NULL) && (name != NULL)
9229 && (xmlStrEqual(ns->prefix, name))) {
9230#ifdef DEBUG_STEP
9231 n++;
9232#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009233 xmlXPathNodeSetAddNs(list,
9234 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009235 }
9236 }
9237 break;
9238 default:
9239 break;
9240 }
9241 break;
9242 break;
9243 }
9244 } while (cur != NULL);
9245
9246 /*
9247 * If there is some predicate filtering do it now
9248 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009249 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009250 xmlXPathObjectPtr obj2;
9251
9252 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9253 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9254 CHECK_TYPE0(XPATH_NODESET);
9255 obj2 = valuePop(ctxt);
9256 list = obj2->nodesetval;
9257 obj2->nodesetval = NULL;
9258 xmlXPathFreeObject(obj2);
9259 }
9260 if (ret == NULL) {
9261 ret = list;
9262 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009263 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009264 xmlXPathFreeNodeSet(list);
9265 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009266 }
9267 ctxt->context->node = tmp;
9268#ifdef DEBUG_STEP
9269 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009270 "\nExamined %d nodes, found %d nodes at that step\n",
9271 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009272#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009273 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009274 if ((obj->boolval) && (obj->user != NULL)) {
9275 ctxt->value->boolval = 1;
9276 ctxt->value->user = obj->user;
9277 obj->user = NULL;
9278 obj->boolval = 0;
9279 }
9280 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009281 return(t);
9282}
9283
9284/**
9285 * xmlXPathNodeCollectAndTestNth:
9286 * @ctxt: the XPath Parser context
9287 * @op: the XPath precompiled step operation
9288 * @indx: the index to collect
9289 * @first: pointer to the first element in document order
9290 * @last: pointer to the last element in document order
9291 *
9292 * This is the function implementing a step: based on the current list
9293 * of nodes, it builds up a new list, looking at all nodes under that
9294 * axis and selecting them it also do the predicate filtering
9295 *
9296 * Pushes the new NodeSet resulting from the search.
9297 * Returns the number of node traversed
9298 */
9299static int
9300xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9301 xmlXPathStepOpPtr op, int indx,
9302 xmlNodePtr * first, xmlNodePtr * last)
9303{
William M. Brack78637da2003-07-31 14:47:38 +00009304 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9305 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9306 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009307 const xmlChar *prefix = op->value4;
9308 const xmlChar *name = op->value5;
9309 const xmlChar *URI = NULL;
9310 int n = 0, t = 0;
9311
9312 int i;
9313 xmlNodeSetPtr list;
9314 xmlXPathTraversalFunction next = NULL;
9315 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9316 xmlNodePtr cur = NULL;
9317 xmlXPathObjectPtr obj;
9318 xmlNodeSetPtr nodelist;
9319 xmlNodePtr tmp;
9320
9321 CHECK_TYPE0(XPATH_NODESET);
9322 obj = valuePop(ctxt);
9323 addNode = xmlXPathNodeSetAdd;
9324 if (prefix != NULL) {
9325 URI = xmlXPathNsLookup(ctxt->context, prefix);
9326 if (URI == NULL)
9327 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9328 }
9329#ifdef DEBUG_STEP_NTH
9330 xmlGenericError(xmlGenericErrorContext, "new step : ");
9331 if (first != NULL) {
9332 if (*first != NULL)
9333 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9334 (*first)->name);
9335 else
9336 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9337 }
9338 if (last != NULL) {
9339 if (*last != NULL)
9340 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9341 (*last)->name);
9342 else
9343 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9344 }
9345#endif
9346 switch (axis) {
9347 case AXIS_ANCESTOR:
9348#ifdef DEBUG_STEP_NTH
9349 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9350#endif
9351 first = NULL;
9352 next = xmlXPathNextAncestor;
9353 break;
9354 case AXIS_ANCESTOR_OR_SELF:
9355#ifdef DEBUG_STEP_NTH
9356 xmlGenericError(xmlGenericErrorContext,
9357 "axis 'ancestors-or-self' ");
9358#endif
9359 first = NULL;
9360 next = xmlXPathNextAncestorOrSelf;
9361 break;
9362 case AXIS_ATTRIBUTE:
9363#ifdef DEBUG_STEP_NTH
9364 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9365#endif
9366 first = NULL;
9367 last = NULL;
9368 next = xmlXPathNextAttribute;
9369 break;
9370 case AXIS_CHILD:
9371#ifdef DEBUG_STEP_NTH
9372 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9373#endif
9374 last = NULL;
9375 next = xmlXPathNextChild;
9376 break;
9377 case AXIS_DESCENDANT:
9378#ifdef DEBUG_STEP_NTH
9379 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9380#endif
9381 last = NULL;
9382 next = xmlXPathNextDescendant;
9383 break;
9384 case AXIS_DESCENDANT_OR_SELF:
9385#ifdef DEBUG_STEP_NTH
9386 xmlGenericError(xmlGenericErrorContext,
9387 "axis 'descendant-or-self' ");
9388#endif
9389 last = NULL;
9390 next = xmlXPathNextDescendantOrSelf;
9391 break;
9392 case AXIS_FOLLOWING:
9393#ifdef DEBUG_STEP_NTH
9394 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9395#endif
9396 last = NULL;
9397 next = xmlXPathNextFollowing;
9398 break;
9399 case AXIS_FOLLOWING_SIBLING:
9400#ifdef DEBUG_STEP_NTH
9401 xmlGenericError(xmlGenericErrorContext,
9402 "axis 'following-siblings' ");
9403#endif
9404 last = NULL;
9405 next = xmlXPathNextFollowingSibling;
9406 break;
9407 case AXIS_NAMESPACE:
9408#ifdef DEBUG_STEP_NTH
9409 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9410#endif
9411 last = NULL;
9412 first = NULL;
9413 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9414 break;
9415 case AXIS_PARENT:
9416#ifdef DEBUG_STEP_NTH
9417 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9418#endif
9419 first = NULL;
9420 next = xmlXPathNextParent;
9421 break;
9422 case AXIS_PRECEDING:
9423#ifdef DEBUG_STEP_NTH
9424 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9425#endif
9426 first = NULL;
9427 next = xmlXPathNextPrecedingInternal;
9428 break;
9429 case AXIS_PRECEDING_SIBLING:
9430#ifdef DEBUG_STEP_NTH
9431 xmlGenericError(xmlGenericErrorContext,
9432 "axis 'preceding-sibling' ");
9433#endif
9434 first = NULL;
9435 next = xmlXPathNextPrecedingSibling;
9436 break;
9437 case AXIS_SELF:
9438#ifdef DEBUG_STEP_NTH
9439 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9440#endif
9441 first = NULL;
9442 last = NULL;
9443 next = xmlXPathNextSelf;
9444 break;
9445 }
9446 if (next == NULL)
9447 return(0);
9448
9449 nodelist = obj->nodesetval;
9450 if (nodelist == NULL) {
9451 xmlXPathFreeObject(obj);
9452 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9453 return(0);
9454 }
9455 addNode = xmlXPathNodeSetAddUnique;
9456#ifdef DEBUG_STEP_NTH
9457 xmlGenericError(xmlGenericErrorContext,
9458 " context contains %d nodes\n", nodelist->nodeNr);
9459 switch (test) {
9460 case NODE_TEST_NONE:
9461 xmlGenericError(xmlGenericErrorContext,
9462 " searching for none !!!\n");
9463 break;
9464 case NODE_TEST_TYPE:
9465 xmlGenericError(xmlGenericErrorContext,
9466 " searching for type %d\n", type);
9467 break;
9468 case NODE_TEST_PI:
9469 xmlGenericError(xmlGenericErrorContext,
9470 " searching for PI !!!\n");
9471 break;
9472 case NODE_TEST_ALL:
9473 xmlGenericError(xmlGenericErrorContext,
9474 " searching for *\n");
9475 break;
9476 case NODE_TEST_NS:
9477 xmlGenericError(xmlGenericErrorContext,
9478 " searching for namespace %s\n",
9479 prefix);
9480 break;
9481 case NODE_TEST_NAME:
9482 xmlGenericError(xmlGenericErrorContext,
9483 " searching for name %s\n", name);
9484 if (prefix != NULL)
9485 xmlGenericError(xmlGenericErrorContext,
9486 " with namespace %s\n", prefix);
9487 break;
9488 }
9489 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9490#endif
9491 /*
9492 * 2.3 Node Tests
9493 * - For the attribute axis, the principal node type is attribute.
9494 * - For the namespace axis, the principal node type is namespace.
9495 * - For other axes, the principal node type is element.
9496 *
9497 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009498 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009499 * select all element children of the context node
9500 */
9501 tmp = ctxt->context->node;
9502 list = xmlXPathNodeSetCreate(NULL);
9503 for (i = 0; i < nodelist->nodeNr; i++) {
9504 ctxt->context->node = nodelist->nodeTab[i];
9505
9506 cur = NULL;
9507 n = 0;
9508 do {
9509 cur = next(ctxt, cur);
9510 if (cur == NULL)
9511 break;
9512 if ((first != NULL) && (*first == cur))
9513 break;
9514 if (((t % 256) == 0) &&
9515 (first != NULL) && (*first != NULL) &&
9516 (xmlXPathCmpNodes(*first, cur) >= 0))
9517 break;
9518 if ((last != NULL) && (*last == cur))
9519 break;
9520 if (((t % 256) == 0) &&
9521 (last != NULL) && (*last != NULL) &&
9522 (xmlXPathCmpNodes(cur, *last) >= 0))
9523 break;
9524 t++;
9525 switch (test) {
9526 case NODE_TEST_NONE:
9527 ctxt->context->node = tmp;
9528 STRANGE return(0);
9529 case NODE_TEST_TYPE:
9530 if ((cur->type == type) ||
9531 ((type == NODE_TYPE_NODE) &&
9532 ((cur->type == XML_DOCUMENT_NODE) ||
9533 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9534 (cur->type == XML_ELEMENT_NODE) ||
9535 (cur->type == XML_PI_NODE) ||
9536 (cur->type == XML_COMMENT_NODE) ||
9537 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009538 (cur->type == XML_TEXT_NODE))) ||
9539 ((type == NODE_TYPE_TEXT) &&
9540 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009541 n++;
9542 if (n == indx)
9543 addNode(list, cur);
9544 }
9545 break;
9546 case NODE_TEST_PI:
9547 if (cur->type == XML_PI_NODE) {
9548 if ((name != NULL) &&
9549 (!xmlStrEqual(name, cur->name)))
9550 break;
9551 n++;
9552 if (n == indx)
9553 addNode(list, cur);
9554 }
9555 break;
9556 case NODE_TEST_ALL:
9557 if (axis == AXIS_ATTRIBUTE) {
9558 if (cur->type == XML_ATTRIBUTE_NODE) {
9559 n++;
9560 if (n == indx)
9561 addNode(list, cur);
9562 }
9563 } else if (axis == AXIS_NAMESPACE) {
9564 if (cur->type == XML_NAMESPACE_DECL) {
9565 n++;
9566 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009567 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9568 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009569 }
9570 } else {
9571 if (cur->type == XML_ELEMENT_NODE) {
9572 if (prefix == NULL) {
9573 n++;
9574 if (n == indx)
9575 addNode(list, cur);
9576 } else if ((cur->ns != NULL) &&
9577 (xmlStrEqual(URI, cur->ns->href))) {
9578 n++;
9579 if (n == indx)
9580 addNode(list, cur);
9581 }
9582 }
9583 }
9584 break;
9585 case NODE_TEST_NS:{
9586 TODO;
9587 break;
9588 }
9589 case NODE_TEST_NAME:
9590 switch (cur->type) {
9591 case XML_ELEMENT_NODE:
9592 if (xmlStrEqual(name, cur->name)) {
9593 if (prefix == NULL) {
9594 if (cur->ns == NULL) {
9595 n++;
9596 if (n == indx)
9597 addNode(list, cur);
9598 }
9599 } else {
9600 if ((cur->ns != NULL) &&
9601 (xmlStrEqual(URI,
9602 cur->ns->href))) {
9603 n++;
9604 if (n == indx)
9605 addNode(list, cur);
9606 }
9607 }
9608 }
9609 break;
9610 case XML_ATTRIBUTE_NODE:{
9611 xmlAttrPtr attr = (xmlAttrPtr) cur;
9612
9613 if (xmlStrEqual(name, attr->name)) {
9614 if (prefix == NULL) {
9615 if ((attr->ns == NULL) ||
9616 (attr->ns->prefix == NULL)) {
9617 n++;
9618 if (n == indx)
9619 addNode(list, cur);
9620 }
9621 } else {
9622 if ((attr->ns != NULL) &&
9623 (xmlStrEqual(URI,
9624 attr->ns->
9625 href))) {
9626 n++;
9627 if (n == indx)
9628 addNode(list, cur);
9629 }
9630 }
9631 }
9632 break;
9633 }
9634 case XML_NAMESPACE_DECL:
9635 if (cur->type == XML_NAMESPACE_DECL) {
9636 xmlNsPtr ns = (xmlNsPtr) cur;
9637
9638 if ((ns->prefix != NULL) && (name != NULL)
9639 && (xmlStrEqual(ns->prefix, name))) {
9640 n++;
9641 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009642 xmlXPathNodeSetAddNs(list,
9643 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009644 }
9645 }
9646 break;
9647 default:
9648 break;
9649 }
9650 break;
9651 break;
9652 }
9653 } while (n < indx);
9654 }
9655 ctxt->context->node = tmp;
9656#ifdef DEBUG_STEP_NTH
9657 xmlGenericError(xmlGenericErrorContext,
9658 "\nExamined %d nodes, found %d nodes at that step\n",
9659 t, list->nodeNr);
9660#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009661 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009662 if ((obj->boolval) && (obj->user != NULL)) {
9663 ctxt->value->boolval = 1;
9664 ctxt->value->user = obj->user;
9665 obj->user = NULL;
9666 obj->boolval = 0;
9667 }
9668 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009669 return(t);
9670}
9671
9672/**
9673 * xmlXPathCompOpEvalFirst:
9674 * @ctxt: the XPath parser context with the compiled expression
9675 * @op: an XPath compiled operation
9676 * @first: the first elem found so far
9677 *
9678 * Evaluate the Precompiled XPath operation searching only the first
9679 * element in document order
9680 *
9681 * Returns the number of examined objects.
9682 */
9683static int
9684xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9685 xmlXPathStepOpPtr op, xmlNodePtr * first)
9686{
9687 int total = 0, cur;
9688 xmlXPathCompExprPtr comp;
9689 xmlXPathObjectPtr arg1, arg2;
9690
Daniel Veillard556c6682001-10-06 09:59:51 +00009691 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009692 comp = ctxt->comp;
9693 switch (op->op) {
9694 case XPATH_OP_END:
9695 return (0);
9696 case XPATH_OP_UNION:
9697 total =
9698 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9699 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009700 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009701 if ((ctxt->value != NULL)
9702 && (ctxt->value->type == XPATH_NODESET)
9703 && (ctxt->value->nodesetval != NULL)
9704 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9705 /*
9706 * limit tree traversing to first node in the result
9707 */
9708 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9709 *first = ctxt->value->nodesetval->nodeTab[0];
9710 }
9711 cur =
9712 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9713 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009714 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009715 CHECK_TYPE0(XPATH_NODESET);
9716 arg2 = valuePop(ctxt);
9717
9718 CHECK_TYPE0(XPATH_NODESET);
9719 arg1 = valuePop(ctxt);
9720
9721 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9722 arg2->nodesetval);
9723 valuePush(ctxt, arg1);
9724 xmlXPathFreeObject(arg2);
9725 /* optimizer */
9726 if (total > cur)
9727 xmlXPathCompSwap(op);
9728 return (total + cur);
9729 case XPATH_OP_ROOT:
9730 xmlXPathRoot(ctxt);
9731 return (0);
9732 case XPATH_OP_NODE:
9733 if (op->ch1 != -1)
9734 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009735 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009736 if (op->ch2 != -1)
9737 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009738 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009739 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9740 return (total);
9741 case XPATH_OP_RESET:
9742 if (op->ch1 != -1)
9743 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009744 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009745 if (op->ch2 != -1)
9746 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009747 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009748 ctxt->context->node = NULL;
9749 return (total);
9750 case XPATH_OP_COLLECT:{
9751 if (op->ch1 == -1)
9752 return (total);
9753
9754 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009755 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009756
9757 /*
9758 * Optimization for [n] selection where n is a number
9759 */
9760 if ((op->ch2 != -1) &&
9761 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9762 (comp->steps[op->ch2].ch1 == -1) &&
9763 (comp->steps[op->ch2].ch2 != -1) &&
9764 (comp->steps[comp->steps[op->ch2].ch2].op ==
9765 XPATH_OP_VALUE)) {
9766 xmlXPathObjectPtr val;
9767
9768 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9769 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9770 int indx = (int) val->floatval;
9771
9772 if (val->floatval == (float) indx) {
9773 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9774 first, NULL);
9775 return (total);
9776 }
9777 }
9778 }
9779 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9780 return (total);
9781 }
9782 case XPATH_OP_VALUE:
9783 valuePush(ctxt,
9784 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9785 return (0);
9786 case XPATH_OP_SORT:
9787 if (op->ch1 != -1)
9788 total +=
9789 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9790 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009791 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009792 if ((ctxt->value != NULL)
9793 && (ctxt->value->type == XPATH_NODESET)
9794 && (ctxt->value->nodesetval != NULL))
9795 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9796 return (total);
9797 default:
9798 return (xmlXPathCompOpEval(ctxt, op));
9799 }
9800}
9801
9802/**
9803 * xmlXPathCompOpEvalLast:
9804 * @ctxt: the XPath parser context with the compiled expression
9805 * @op: an XPath compiled operation
9806 * @last: the last elem found so far
9807 *
9808 * Evaluate the Precompiled XPath operation searching only the last
9809 * element in document order
9810 *
9811 * Returns the number of node traversed
9812 */
9813static int
9814xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9815 xmlNodePtr * last)
9816{
9817 int total = 0, cur;
9818 xmlXPathCompExprPtr comp;
9819 xmlXPathObjectPtr arg1, arg2;
9820
Daniel Veillard556c6682001-10-06 09:59:51 +00009821 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009822 comp = ctxt->comp;
9823 switch (op->op) {
9824 case XPATH_OP_END:
9825 return (0);
9826 case XPATH_OP_UNION:
9827 total =
9828 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009829 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009830 if ((ctxt->value != NULL)
9831 && (ctxt->value->type == XPATH_NODESET)
9832 && (ctxt->value->nodesetval != NULL)
9833 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9834 /*
9835 * limit tree traversing to first node in the result
9836 */
9837 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9838 *last =
9839 ctxt->value->nodesetval->nodeTab[ctxt->value->
9840 nodesetval->nodeNr -
9841 1];
9842 }
9843 cur =
9844 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009845 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009846 if ((ctxt->value != NULL)
9847 && (ctxt->value->type == XPATH_NODESET)
9848 && (ctxt->value->nodesetval != NULL)
9849 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9850 }
9851 CHECK_TYPE0(XPATH_NODESET);
9852 arg2 = valuePop(ctxt);
9853
9854 CHECK_TYPE0(XPATH_NODESET);
9855 arg1 = valuePop(ctxt);
9856
9857 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9858 arg2->nodesetval);
9859 valuePush(ctxt, arg1);
9860 xmlXPathFreeObject(arg2);
9861 /* optimizer */
9862 if (total > cur)
9863 xmlXPathCompSwap(op);
9864 return (total + cur);
9865 case XPATH_OP_ROOT:
9866 xmlXPathRoot(ctxt);
9867 return (0);
9868 case XPATH_OP_NODE:
9869 if (op->ch1 != -1)
9870 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009871 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009872 if (op->ch2 != -1)
9873 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009874 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009875 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9876 return (total);
9877 case XPATH_OP_RESET:
9878 if (op->ch1 != -1)
9879 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009880 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009881 if (op->ch2 != -1)
9882 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009883 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009884 ctxt->context->node = NULL;
9885 return (total);
9886 case XPATH_OP_COLLECT:{
9887 if (op->ch1 == -1)
9888 return (0);
9889
9890 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009891 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009892
9893 /*
9894 * Optimization for [n] selection where n is a number
9895 */
9896 if ((op->ch2 != -1) &&
9897 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9898 (comp->steps[op->ch2].ch1 == -1) &&
9899 (comp->steps[op->ch2].ch2 != -1) &&
9900 (comp->steps[comp->steps[op->ch2].ch2].op ==
9901 XPATH_OP_VALUE)) {
9902 xmlXPathObjectPtr val;
9903
9904 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9905 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9906 int indx = (int) val->floatval;
9907
9908 if (val->floatval == (float) indx) {
9909 total +=
9910 xmlXPathNodeCollectAndTestNth(ctxt, op,
9911 indx, NULL,
9912 last);
9913 return (total);
9914 }
9915 }
9916 }
9917 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9918 return (total);
9919 }
9920 case XPATH_OP_VALUE:
9921 valuePush(ctxt,
9922 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9923 return (0);
9924 case XPATH_OP_SORT:
9925 if (op->ch1 != -1)
9926 total +=
9927 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9928 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009929 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009930 if ((ctxt->value != NULL)
9931 && (ctxt->value->type == XPATH_NODESET)
9932 && (ctxt->value->nodesetval != NULL))
9933 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9934 return (total);
9935 default:
9936 return (xmlXPathCompOpEval(ctxt, op));
9937 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009938}
9939
Owen Taylor3473f882001-02-23 17:55:21 +00009940/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009941 * xmlXPathCompOpEval:
9942 * @ctxt: the XPath parser context with the compiled expression
9943 * @op: an XPath compiled operation
9944 *
9945 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009946 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009947 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948static int
9949xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9950{
9951 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009952 int equal, ret;
9953 xmlXPathCompExprPtr comp;
9954 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009955 xmlNodePtr bak;
9956 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009957 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009958 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009959
Daniel Veillard556c6682001-10-06 09:59:51 +00009960 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009961 comp = ctxt->comp;
9962 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009963 case XPATH_OP_END:
9964 return (0);
9965 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009966 bakd = ctxt->context->doc;
9967 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009968 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009969 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009970 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009971 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009972 xmlXPathBooleanFunction(ctxt, 1);
9973 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9974 return (total);
9975 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009976 ctxt->context->doc = bakd;
9977 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009978 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009979 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009981 if (ctxt->error) {
9982 xmlXPathFreeObject(arg2);
9983 return(0);
9984 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009985 xmlXPathBooleanFunction(ctxt, 1);
9986 arg1 = valuePop(ctxt);
9987 arg1->boolval &= arg2->boolval;
9988 valuePush(ctxt, arg1);
9989 xmlXPathFreeObject(arg2);
9990 return (total);
9991 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009992 bakd = ctxt->context->doc;
9993 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009994 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009995 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009997 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009998 xmlXPathBooleanFunction(ctxt, 1);
9999 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10000 return (total);
10001 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010002 ctxt->context->doc = bakd;
10003 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010004 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010005 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010006 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010007 if (ctxt->error) {
10008 xmlXPathFreeObject(arg2);
10009 return(0);
10010 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010011 xmlXPathBooleanFunction(ctxt, 1);
10012 arg1 = valuePop(ctxt);
10013 arg1->boolval |= arg2->boolval;
10014 valuePush(ctxt, arg1);
10015 xmlXPathFreeObject(arg2);
10016 return (total);
10017 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010018 bakd = ctxt->context->doc;
10019 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010020 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010021 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010022 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010023 CHECK_ERROR0;
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 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010030 if (op->value)
10031 equal = xmlXPathEqualValues(ctxt);
10032 else
10033 equal = xmlXPathNotEqualValues(ctxt);
10034 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010035 return (total);
10036 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010037 bakd = ctxt->context->doc;
10038 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010039 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010040 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010041 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010042 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010043 ctxt->context->doc = bakd;
10044 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010045 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010046 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010047 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010048 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010049 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10050 valuePush(ctxt, xmlXPathNewBoolean(ret));
10051 return (total);
10052 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010053 bakd = ctxt->context->doc;
10054 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010055 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010056 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010057 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010058 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010059 if (op->ch2 != -1) {
10060 ctxt->context->doc = bakd;
10061 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010062 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010063 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010064 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010065 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010066 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010067 if (op->value == 0)
10068 xmlXPathSubValues(ctxt);
10069 else if (op->value == 1)
10070 xmlXPathAddValues(ctxt);
10071 else if (op->value == 2)
10072 xmlXPathValueFlipSign(ctxt);
10073 else if (op->value == 3) {
10074 CAST_TO_NUMBER;
10075 CHECK_TYPE0(XPATH_NUMBER);
10076 }
10077 return (total);
10078 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010079 bakd = ctxt->context->doc;
10080 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010081 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010082 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010083 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010084 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010085 ctxt->context->doc = bakd;
10086 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010087 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010088 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010089 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010090 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010091 if (op->value == 0)
10092 xmlXPathMultValues(ctxt);
10093 else if (op->value == 1)
10094 xmlXPathDivValues(ctxt);
10095 else if (op->value == 2)
10096 xmlXPathModValues(ctxt);
10097 return (total);
10098 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010099 bakd = ctxt->context->doc;
10100 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010101 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010102 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010103 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010104 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010105 ctxt->context->doc = bakd;
10106 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010107 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010108 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010109 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010110 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010111 CHECK_TYPE0(XPATH_NODESET);
10112 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010113
Daniel Veillardf06307e2001-07-03 10:35:50 +000010114 CHECK_TYPE0(XPATH_NODESET);
10115 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010116
Daniel Veillardf06307e2001-07-03 10:35:50 +000010117 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10118 arg2->nodesetval);
10119 valuePush(ctxt, arg1);
10120 xmlXPathFreeObject(arg2);
10121 return (total);
10122 case XPATH_OP_ROOT:
10123 xmlXPathRoot(ctxt);
10124 return (total);
10125 case XPATH_OP_NODE:
10126 if (op->ch1 != -1)
10127 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010128 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010129 if (op->ch2 != -1)
10130 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010131 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010132 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10133 return (total);
10134 case XPATH_OP_RESET:
10135 if (op->ch1 != -1)
10136 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010137 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010138 if (op->ch2 != -1)
10139 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010140 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010141 ctxt->context->node = NULL;
10142 return (total);
10143 case XPATH_OP_COLLECT:{
10144 if (op->ch1 == -1)
10145 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010146
Daniel Veillardf06307e2001-07-03 10:35:50 +000010147 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010148 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010149
Daniel Veillardf06307e2001-07-03 10:35:50 +000010150 /*
10151 * Optimization for [n] selection where n is a number
10152 */
10153 if ((op->ch2 != -1) &&
10154 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10155 (comp->steps[op->ch2].ch1 == -1) &&
10156 (comp->steps[op->ch2].ch2 != -1) &&
10157 (comp->steps[comp->steps[op->ch2].ch2].op ==
10158 XPATH_OP_VALUE)) {
10159 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010160
Daniel Veillardf06307e2001-07-03 10:35:50 +000010161 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10162 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10163 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010164
Daniel Veillardf06307e2001-07-03 10:35:50 +000010165 if (val->floatval == (float) indx) {
10166 total +=
10167 xmlXPathNodeCollectAndTestNth(ctxt, op,
10168 indx, NULL,
10169 NULL);
10170 return (total);
10171 }
10172 }
10173 }
10174 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10175 return (total);
10176 }
10177 case XPATH_OP_VALUE:
10178 valuePush(ctxt,
10179 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10180 return (total);
10181 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010182 xmlXPathObjectPtr val;
10183
Daniel Veillardf06307e2001-07-03 10:35:50 +000010184 if (op->ch1 != -1)
10185 total +=
10186 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010187 if (op->value5 == NULL) {
10188 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10189 if (val == NULL) {
10190 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10191 return(0);
10192 }
10193 valuePush(ctxt, val);
10194 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010195 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010196
Daniel Veillardf06307e2001-07-03 10:35:50 +000010197 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10198 if (URI == NULL) {
10199 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010200 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010201 op->value4, op->value5);
10202 return (total);
10203 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010204 val = xmlXPathVariableLookupNS(ctxt->context,
10205 op->value4, URI);
10206 if (val == NULL) {
10207 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10208 return(0);
10209 }
10210 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010211 }
10212 return (total);
10213 }
10214 case XPATH_OP_FUNCTION:{
10215 xmlXPathFunction func;
10216 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010217 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010218
10219 if (op->ch1 != -1)
10220 total +=
10221 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010222 if (ctxt->valueNr < op->value) {
10223 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010224 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010225 ctxt->error = XPATH_INVALID_OPERAND;
10226 return (total);
10227 }
10228 for (i = 0; i < op->value; i++)
10229 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10230 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010231 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010232 ctxt->error = XPATH_INVALID_OPERAND;
10233 return (total);
10234 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010235 if (op->cache != NULL)
10236 func = (xmlXPathFunction) op->cache;
10237 else {
10238 const xmlChar *URI = NULL;
10239
10240 if (op->value5 == NULL)
10241 func =
10242 xmlXPathFunctionLookup(ctxt->context,
10243 op->value4);
10244 else {
10245 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10246 if (URI == NULL) {
10247 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010248 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010249 op->value4, op->value5);
10250 return (total);
10251 }
10252 func = xmlXPathFunctionLookupNS(ctxt->context,
10253 op->value4, URI);
10254 }
10255 if (func == NULL) {
10256 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010257 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010258 op->value4);
10259 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010260 }
10261 op->cache = (void *) func;
10262 op->cacheURI = (void *) URI;
10263 }
10264 oldFunc = ctxt->context->function;
10265 oldFuncURI = ctxt->context->functionURI;
10266 ctxt->context->function = op->value4;
10267 ctxt->context->functionURI = op->cacheURI;
10268 func(ctxt, op->value);
10269 ctxt->context->function = oldFunc;
10270 ctxt->context->functionURI = oldFuncURI;
10271 return (total);
10272 }
10273 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010274 bakd = ctxt->context->doc;
10275 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010276 if (op->ch1 != -1)
10277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010278 ctxt->context->doc = bakd;
10279 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010280 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010281 if (op->ch2 != -1)
10282 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010283 ctxt->context->doc = bakd;
10284 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010285 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010286 return (total);
10287 case XPATH_OP_PREDICATE:
10288 case XPATH_OP_FILTER:{
10289 xmlXPathObjectPtr res;
10290 xmlXPathObjectPtr obj, tmp;
10291 xmlNodeSetPtr newset = NULL;
10292 xmlNodeSetPtr oldset;
10293 xmlNodePtr oldnode;
10294 int i;
10295
10296 /*
10297 * Optimization for ()[1] selection i.e. the first elem
10298 */
10299 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10300 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10301 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10302 xmlXPathObjectPtr val;
10303
10304 val = comp->steps[op->ch2].value4;
10305 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10306 (val->floatval == 1.0)) {
10307 xmlNodePtr first = NULL;
10308
10309 total +=
10310 xmlXPathCompOpEvalFirst(ctxt,
10311 &comp->steps[op->ch1],
10312 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010313 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010314 /*
10315 * The nodeset should be in document order,
10316 * Keep only the first value
10317 */
10318 if ((ctxt->value != NULL) &&
10319 (ctxt->value->type == XPATH_NODESET) &&
10320 (ctxt->value->nodesetval != NULL) &&
10321 (ctxt->value->nodesetval->nodeNr > 1))
10322 ctxt->value->nodesetval->nodeNr = 1;
10323 return (total);
10324 }
10325 }
10326 /*
10327 * Optimization for ()[last()] selection i.e. the last elem
10328 */
10329 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10330 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10331 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10332 int f = comp->steps[op->ch2].ch1;
10333
10334 if ((f != -1) &&
10335 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10336 (comp->steps[f].value5 == NULL) &&
10337 (comp->steps[f].value == 0) &&
10338 (comp->steps[f].value4 != NULL) &&
10339 (xmlStrEqual
10340 (comp->steps[f].value4, BAD_CAST "last"))) {
10341 xmlNodePtr last = NULL;
10342
10343 total +=
10344 xmlXPathCompOpEvalLast(ctxt,
10345 &comp->steps[op->ch1],
10346 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010347 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010348 /*
10349 * The nodeset should be in document order,
10350 * Keep only the last value
10351 */
10352 if ((ctxt->value != NULL) &&
10353 (ctxt->value->type == XPATH_NODESET) &&
10354 (ctxt->value->nodesetval != NULL) &&
10355 (ctxt->value->nodesetval->nodeTab != NULL) &&
10356 (ctxt->value->nodesetval->nodeNr > 1)) {
10357 ctxt->value->nodesetval->nodeTab[0] =
10358 ctxt->value->nodesetval->nodeTab[ctxt->
10359 value->
10360 nodesetval->
10361 nodeNr -
10362 1];
10363 ctxt->value->nodesetval->nodeNr = 1;
10364 }
10365 return (total);
10366 }
10367 }
10368
10369 if (op->ch1 != -1)
10370 total +=
10371 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010372 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010373 if (op->ch2 == -1)
10374 return (total);
10375 if (ctxt->value == NULL)
10376 return (total);
10377
10378 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010379
10380#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010381 /*
10382 * Hum are we filtering the result of an XPointer expression
10383 */
10384 if (ctxt->value->type == XPATH_LOCATIONSET) {
10385 xmlLocationSetPtr newlocset = NULL;
10386 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010387
Daniel Veillardf06307e2001-07-03 10:35:50 +000010388 /*
10389 * Extract the old locset, and then evaluate the result of the
10390 * expression for all the element in the locset. use it to grow
10391 * up a new locset.
10392 */
10393 CHECK_TYPE0(XPATH_LOCATIONSET);
10394 obj = valuePop(ctxt);
10395 oldlocset = obj->user;
10396 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010397
Daniel Veillardf06307e2001-07-03 10:35:50 +000010398 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10399 ctxt->context->contextSize = 0;
10400 ctxt->context->proximityPosition = 0;
10401 if (op->ch2 != -1)
10402 total +=
10403 xmlXPathCompOpEval(ctxt,
10404 &comp->steps[op->ch2]);
10405 res = valuePop(ctxt);
10406 if (res != NULL)
10407 xmlXPathFreeObject(res);
10408 valuePush(ctxt, obj);
10409 CHECK_ERROR0;
10410 return (total);
10411 }
10412 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010413
Daniel Veillardf06307e2001-07-03 10:35:50 +000010414 for (i = 0; i < oldlocset->locNr; i++) {
10415 /*
10416 * Run the evaluation with a node list made of a
10417 * single item in the nodelocset.
10418 */
10419 ctxt->context->node = oldlocset->locTab[i]->user;
10420 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10421 valuePush(ctxt, tmp);
10422 ctxt->context->contextSize = oldlocset->locNr;
10423 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010424
Daniel Veillardf06307e2001-07-03 10:35:50 +000010425 if (op->ch2 != -1)
10426 total +=
10427 xmlXPathCompOpEval(ctxt,
10428 &comp->steps[op->ch2]);
10429 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010430
Daniel Veillardf06307e2001-07-03 10:35:50 +000010431 /*
10432 * The result of the evaluation need to be tested to
10433 * decided whether the filter succeeded or not
10434 */
10435 res = valuePop(ctxt);
10436 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10437 xmlXPtrLocationSetAdd(newlocset,
10438 xmlXPathObjectCopy
10439 (oldlocset->locTab[i]));
10440 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010441
Daniel Veillardf06307e2001-07-03 10:35:50 +000010442 /*
10443 * Cleanup
10444 */
10445 if (res != NULL)
10446 xmlXPathFreeObject(res);
10447 if (ctxt->value == tmp) {
10448 res = valuePop(ctxt);
10449 xmlXPathFreeObject(res);
10450 }
10451
10452 ctxt->context->node = NULL;
10453 }
10454
10455 /*
10456 * The result is used as the new evaluation locset.
10457 */
10458 xmlXPathFreeObject(obj);
10459 ctxt->context->node = NULL;
10460 ctxt->context->contextSize = -1;
10461 ctxt->context->proximityPosition = -1;
10462 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10463 ctxt->context->node = oldnode;
10464 return (total);
10465 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010466#endif /* LIBXML_XPTR_ENABLED */
10467
Daniel Veillardf06307e2001-07-03 10:35:50 +000010468 /*
10469 * Extract the old set, and then evaluate the result of the
10470 * expression for all the element in the set. use it to grow
10471 * up a new set.
10472 */
10473 CHECK_TYPE0(XPATH_NODESET);
10474 obj = valuePop(ctxt);
10475 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010476
Daniel Veillardf06307e2001-07-03 10:35:50 +000010477 oldnode = ctxt->context->node;
10478 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010479
Daniel Veillardf06307e2001-07-03 10:35:50 +000010480 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10481 ctxt->context->contextSize = 0;
10482 ctxt->context->proximityPosition = 0;
10483 if (op->ch2 != -1)
10484 total +=
10485 xmlXPathCompOpEval(ctxt,
10486 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010487 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010488 res = valuePop(ctxt);
10489 if (res != NULL)
10490 xmlXPathFreeObject(res);
10491 valuePush(ctxt, obj);
10492 ctxt->context->node = oldnode;
10493 CHECK_ERROR0;
10494 } else {
10495 /*
10496 * Initialize the new set.
10497 */
10498 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010499
Daniel Veillardf06307e2001-07-03 10:35:50 +000010500 for (i = 0; i < oldset->nodeNr; i++) {
10501 /*
10502 * Run the evaluation with a node list made of
10503 * a single item in the nodeset.
10504 */
10505 ctxt->context->node = oldset->nodeTab[i];
10506 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10507 valuePush(ctxt, tmp);
10508 ctxt->context->contextSize = oldset->nodeNr;
10509 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010510
Daniel Veillardf06307e2001-07-03 10:35:50 +000010511 if (op->ch2 != -1)
10512 total +=
10513 xmlXPathCompOpEval(ctxt,
10514 &comp->steps[op->ch2]);
10515 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010516
Daniel Veillardf06307e2001-07-03 10:35:50 +000010517 /*
10518 * The result of the evaluation need to be tested to
10519 * decided whether the filter succeeded or not
10520 */
10521 res = valuePop(ctxt);
10522 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10523 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10524 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010525
Daniel Veillardf06307e2001-07-03 10:35:50 +000010526 /*
10527 * Cleanup
10528 */
10529 if (res != NULL)
10530 xmlXPathFreeObject(res);
10531 if (ctxt->value == tmp) {
10532 res = valuePop(ctxt);
10533 xmlXPathFreeObject(res);
10534 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010535
Daniel Veillardf06307e2001-07-03 10:35:50 +000010536 ctxt->context->node = NULL;
10537 }
10538
10539 /*
10540 * The result is used as the new evaluation set.
10541 */
10542 xmlXPathFreeObject(obj);
10543 ctxt->context->node = NULL;
10544 ctxt->context->contextSize = -1;
10545 ctxt->context->proximityPosition = -1;
10546 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10547 }
10548 ctxt->context->node = oldnode;
10549 return (total);
10550 }
10551 case XPATH_OP_SORT:
10552 if (op->ch1 != -1)
10553 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010554 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010555 if ((ctxt->value != NULL) &&
10556 (ctxt->value->type == XPATH_NODESET) &&
10557 (ctxt->value->nodesetval != NULL))
10558 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10559 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010560#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010561 case XPATH_OP_RANGETO:{
10562 xmlXPathObjectPtr range;
10563 xmlXPathObjectPtr res, obj;
10564 xmlXPathObjectPtr tmp;
10565 xmlLocationSetPtr newset = NULL;
10566 xmlNodeSetPtr oldset;
10567 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010568
Daniel Veillardf06307e2001-07-03 10:35:50 +000010569 if (op->ch1 != -1)
10570 total +=
10571 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10572 if (op->ch2 == -1)
10573 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010574
Daniel Veillardf06307e2001-07-03 10:35:50 +000010575 CHECK_TYPE0(XPATH_NODESET);
10576 obj = valuePop(ctxt);
10577 oldset = obj->nodesetval;
10578 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010579
Daniel Veillardf06307e2001-07-03 10:35:50 +000010580 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010581
Daniel Veillardf06307e2001-07-03 10:35:50 +000010582 if (oldset != NULL) {
10583 for (i = 0; i < oldset->nodeNr; i++) {
10584 /*
10585 * Run the evaluation with a node list made of a single item
10586 * in the nodeset.
10587 */
10588 ctxt->context->node = oldset->nodeTab[i];
10589 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10590 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591
Daniel Veillardf06307e2001-07-03 10:35:50 +000010592 if (op->ch2 != -1)
10593 total +=
10594 xmlXPathCompOpEval(ctxt,
10595 &comp->steps[op->ch2]);
10596 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010597
Daniel Veillardf06307e2001-07-03 10:35:50 +000010598 /*
10599 * The result of the evaluation need to be tested to
10600 * decided whether the filter succeeded or not
10601 */
10602 res = valuePop(ctxt);
10603 range =
10604 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10605 res);
10606 if (range != NULL) {
10607 xmlXPtrLocationSetAdd(newset, range);
10608 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010609
Daniel Veillardf06307e2001-07-03 10:35:50 +000010610 /*
10611 * Cleanup
10612 */
10613 if (res != NULL)
10614 xmlXPathFreeObject(res);
10615 if (ctxt->value == tmp) {
10616 res = valuePop(ctxt);
10617 xmlXPathFreeObject(res);
10618 }
10619
10620 ctxt->context->node = NULL;
10621 }
10622 }
10623
10624 /*
10625 * The result is used as the new evaluation set.
10626 */
10627 xmlXPathFreeObject(obj);
10628 ctxt->context->node = NULL;
10629 ctxt->context->contextSize = -1;
10630 ctxt->context->proximityPosition = -1;
10631 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10632 return (total);
10633 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010634#endif /* LIBXML_XPTR_ENABLED */
10635 }
10636 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010637 "XPath: unknown precompiled operation %d\n", op->op);
10638 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010639}
10640
10641/**
10642 * xmlXPathRunEval:
10643 * @ctxt: the XPath parser context with the compiled expression
10644 *
10645 * Evaluate the Precompiled XPath expression in the given context.
10646 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010647static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010648xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10649 xmlXPathCompExprPtr comp;
10650
10651 if ((ctxt == NULL) || (ctxt->comp == NULL))
10652 return;
10653
10654 if (ctxt->valueTab == NULL) {
10655 /* Allocate the value stack */
10656 ctxt->valueTab = (xmlXPathObjectPtr *)
10657 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10658 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010659 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010660 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010661 }
10662 ctxt->valueNr = 0;
10663 ctxt->valueMax = 10;
10664 ctxt->value = NULL;
10665 }
10666 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010667 if(comp->last < 0) {
10668 xmlGenericError(xmlGenericErrorContext,
10669 "xmlXPathRunEval: last is less than zero\n");
10670 return;
10671 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010672 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10673}
10674
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010675/************************************************************************
10676 * *
10677 * Public interfaces *
10678 * *
10679 ************************************************************************/
10680
10681/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010682 * xmlXPathEvalPredicate:
10683 * @ctxt: the XPath context
10684 * @res: the Predicate Expression evaluation result
10685 *
10686 * Evaluate a predicate result for the current node.
10687 * A PredicateExpr is evaluated by evaluating the Expr and converting
10688 * the result to a boolean. If the result is a number, the result will
10689 * be converted to true if the number is equal to the position of the
10690 * context node in the context node list (as returned by the position
10691 * function) and will be converted to false otherwise; if the result
10692 * is not a number, then the result will be converted as if by a call
10693 * to the boolean function.
10694 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010695 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010696 */
10697int
10698xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10699 if (res == NULL) return(0);
10700 switch (res->type) {
10701 case XPATH_BOOLEAN:
10702 return(res->boolval);
10703 case XPATH_NUMBER:
10704 return(res->floatval == ctxt->proximityPosition);
10705 case XPATH_NODESET:
10706 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010707 if (res->nodesetval == NULL)
10708 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010709 return(res->nodesetval->nodeNr != 0);
10710 case XPATH_STRING:
10711 return((res->stringval != NULL) &&
10712 (xmlStrlen(res->stringval) != 0));
10713 default:
10714 STRANGE
10715 }
10716 return(0);
10717}
10718
10719/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010720 * xmlXPathEvaluatePredicateResult:
10721 * @ctxt: the XPath Parser context
10722 * @res: the Predicate Expression evaluation result
10723 *
10724 * Evaluate a predicate result for the current node.
10725 * A PredicateExpr is evaluated by evaluating the Expr and converting
10726 * the result to a boolean. If the result is a number, the result will
10727 * be converted to true if the number is equal to the position of the
10728 * context node in the context node list (as returned by the position
10729 * function) and will be converted to false otherwise; if the result
10730 * is not a number, then the result will be converted as if by a call
10731 * to the boolean function.
10732 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010733 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010734 */
10735int
10736xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10737 xmlXPathObjectPtr res) {
10738 if (res == NULL) return(0);
10739 switch (res->type) {
10740 case XPATH_BOOLEAN:
10741 return(res->boolval);
10742 case XPATH_NUMBER:
10743 return(res->floatval == ctxt->context->proximityPosition);
10744 case XPATH_NODESET:
10745 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010746 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010747 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010748 return(res->nodesetval->nodeNr != 0);
10749 case XPATH_STRING:
10750 return((res->stringval != NULL) &&
10751 (xmlStrlen(res->stringval) != 0));
10752 default:
10753 STRANGE
10754 }
10755 return(0);
10756}
10757
10758/**
10759 * xmlXPathCompile:
10760 * @str: the XPath expression
10761 *
10762 * Compile an XPath expression
10763 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010764 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010765 * the caller has to free the object.
10766 */
10767xmlXPathCompExprPtr
10768xmlXPathCompile(const xmlChar *str) {
10769 xmlXPathParserContextPtr ctxt;
10770 xmlXPathCompExprPtr comp;
10771
10772 xmlXPathInit();
10773
10774 ctxt = xmlXPathNewParserContext(str, NULL);
10775 xmlXPathCompileExpr(ctxt);
Daniel Veillardae9733a2003-10-28 19:02:21 +000010776
10777 if( ctxt->error != XPATH_EXPRESSION_OK )
10778 {
10779 xmlXPathFreeParserContext(ctxt);
10780 return (0);
10781 }
10782
Daniel Veillard40af6492001-04-22 08:50:55 +000010783 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010784 /*
10785 * aleksey: in some cases this line prints *second* error message
10786 * (see bug #78858) and probably this should be fixed.
10787 * However, we are not sure that all error messages are printed
10788 * out in other places. It's not critical so we leave it as-is for now
10789 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010790 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10791 comp = NULL;
10792 } else {
10793 comp = ctxt->comp;
10794 ctxt->comp = NULL;
10795 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010796 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010797 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010798 comp->expr = xmlStrdup(str);
10799#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010800 comp->string = xmlStrdup(str);
10801 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010802#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010803 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010804 return(comp);
10805}
10806
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010807/**
10808 * xmlXPathCompiledEval:
10809 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010810 * @ctx: the XPath context
10811 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010812 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010813 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010814 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010815 * the caller has to free the object.
10816 */
10817xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010818xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010819 xmlXPathParserContextPtr ctxt;
10820 xmlXPathObjectPtr res, tmp, init = NULL;
10821 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010822#ifndef LIBXML_THREAD_ENABLED
10823 static int reentance = 0;
10824#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010825
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010826 if ((comp == NULL) || (ctx == NULL))
10827 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010828 xmlXPathInit();
10829
10830 CHECK_CONTEXT(ctx)
10831
Daniel Veillard81463942001-10-16 12:34:39 +000010832#ifndef LIBXML_THREAD_ENABLED
10833 reentance++;
10834 if (reentance > 1)
10835 xmlXPathDisableOptimizer = 1;
10836#endif
10837
Daniel Veillardf06307e2001-07-03 10:35:50 +000010838#ifdef DEBUG_EVAL_COUNTS
10839 comp->nb++;
10840 if ((comp->string != NULL) && (comp->nb > 100)) {
10841 fprintf(stderr, "100 x %s\n", comp->string);
10842 comp->nb = 0;
10843 }
10844#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010845 ctxt = xmlXPathCompParserContext(comp, ctx);
10846 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010847
10848 if (ctxt->value == NULL) {
10849 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010850 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010851 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010852 } else {
10853 res = valuePop(ctxt);
10854 }
10855
Daniel Veillardf06307e2001-07-03 10:35:50 +000010856
Owen Taylor3473f882001-02-23 17:55:21 +000010857 do {
10858 tmp = valuePop(ctxt);
10859 if (tmp != NULL) {
10860 if (tmp != init)
10861 stack++;
10862 xmlXPathFreeObject(tmp);
10863 }
10864 } while (tmp != NULL);
10865 if ((stack != 0) && (res != NULL)) {
10866 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010867 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010868 stack);
10869 }
10870 if (ctxt->error != XPATH_EXPRESSION_OK) {
10871 xmlXPathFreeObject(res);
10872 res = NULL;
10873 }
10874
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010875
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010876 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010877 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010878#ifndef LIBXML_THREAD_ENABLED
10879 reentance--;
10880#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010881 return(res);
10882}
10883
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010884/**
10885 * xmlXPathEvalExpr:
10886 * @ctxt: the XPath Parser context
10887 *
10888 * Parse and evaluate an XPath expression in the given context,
10889 * then push the result on the context stack
10890 */
10891void
10892xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10893 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010894 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010895 xmlXPathRunEval(ctxt);
10896}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010897
10898/**
10899 * xmlXPathEval:
10900 * @str: the XPath expression
10901 * @ctx: the XPath context
10902 *
10903 * Evaluate the XPath Location Path in the given context.
10904 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010905 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010906 * the caller has to free the object.
10907 */
10908xmlXPathObjectPtr
10909xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10910 xmlXPathParserContextPtr ctxt;
10911 xmlXPathObjectPtr res, tmp, init = NULL;
10912 int stack = 0;
10913
10914 xmlXPathInit();
10915
10916 CHECK_CONTEXT(ctx)
10917
10918 ctxt = xmlXPathNewParserContext(str, ctx);
10919 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010920
10921 if (ctxt->value == NULL) {
10922 xmlGenericError(xmlGenericErrorContext,
10923 "xmlXPathEval: evaluation failed\n");
10924 res = NULL;
10925 } else if (*ctxt->cur != 0) {
10926 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10927 res = NULL;
10928 } else {
10929 res = valuePop(ctxt);
10930 }
10931
10932 do {
10933 tmp = valuePop(ctxt);
10934 if (tmp != NULL) {
10935 if (tmp != init)
10936 stack++;
10937 xmlXPathFreeObject(tmp);
10938 }
10939 } while (tmp != NULL);
10940 if ((stack != 0) && (res != NULL)) {
10941 xmlGenericError(xmlGenericErrorContext,
10942 "xmlXPathEval: %d object left on the stack\n",
10943 stack);
10944 }
10945 if (ctxt->error != XPATH_EXPRESSION_OK) {
10946 xmlXPathFreeObject(res);
10947 res = NULL;
10948 }
10949
Owen Taylor3473f882001-02-23 17:55:21 +000010950 xmlXPathFreeParserContext(ctxt);
10951 return(res);
10952}
10953
10954/**
10955 * xmlXPathEvalExpression:
10956 * @str: the XPath expression
10957 * @ctxt: the XPath context
10958 *
10959 * Evaluate the XPath expression in the given context.
10960 *
10961 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10962 * the caller has to free the object.
10963 */
10964xmlXPathObjectPtr
10965xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10966 xmlXPathParserContextPtr pctxt;
10967 xmlXPathObjectPtr res, tmp;
10968 int stack = 0;
10969
10970 xmlXPathInit();
10971
10972 CHECK_CONTEXT(ctxt)
10973
10974 pctxt = xmlXPathNewParserContext(str, ctxt);
10975 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010976
10977 if (*pctxt->cur != 0) {
10978 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10979 res = NULL;
10980 } else {
10981 res = valuePop(pctxt);
10982 }
10983 do {
10984 tmp = valuePop(pctxt);
10985 if (tmp != NULL) {
10986 xmlXPathFreeObject(tmp);
10987 stack++;
10988 }
10989 } while (tmp != NULL);
10990 if ((stack != 0) && (res != NULL)) {
10991 xmlGenericError(xmlGenericErrorContext,
10992 "xmlXPathEvalExpression: %d object left on the stack\n",
10993 stack);
10994 }
10995 xmlXPathFreeParserContext(pctxt);
10996 return(res);
10997}
10998
Daniel Veillard42766c02002-08-22 20:52:17 +000010999/************************************************************************
11000 * *
11001 * Extra functions not pertaining to the XPath spec *
11002 * *
11003 ************************************************************************/
11004/**
11005 * xmlXPathEscapeUriFunction:
11006 * @ctxt: the XPath Parser context
11007 * @nargs: the number of arguments
11008 *
11009 * Implement the escape-uri() XPath function
11010 * string escape-uri(string $str, bool $escape-reserved)
11011 *
11012 * This function applies the URI escaping rules defined in section 2 of [RFC
11013 * 2396] to the string supplied as $uri-part, which typically represents all
11014 * or part of a URI. The effect of the function is to replace any special
11015 * character in the string by an escape sequence of the form %xx%yy...,
11016 * where xxyy... is the hexadecimal representation of the octets used to
11017 * represent the character in UTF-8.
11018 *
11019 * The set of characters that are escaped depends on the setting of the
11020 * boolean argument $escape-reserved.
11021 *
11022 * If $escape-reserved is true, all characters are escaped other than lower
11023 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11024 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11025 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11026 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11027 * A-F).
11028 *
11029 * If $escape-reserved is false, the behavior differs in that characters
11030 * referred to in [RFC 2396] as reserved characters are not escaped. These
11031 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11032 *
11033 * [RFC 2396] does not define whether escaped URIs should use lower case or
11034 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11035 * compared using string comparison functions, this function must always use
11036 * the upper-case letters A-F.
11037 *
11038 * Generally, $escape-reserved should be set to true when escaping a string
11039 * that is to form a single part of a URI, and to false when escaping an
11040 * entire URI or URI reference.
11041 *
11042 * In the case of non-ascii characters, the string is encoded according to
11043 * utf-8 and then converted according to RFC 2396.
11044 *
11045 * Examples
11046 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11047 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11048 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11049 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11050 *
11051 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011052static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011053xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11054 xmlXPathObjectPtr str;
11055 int escape_reserved;
11056 xmlBufferPtr target;
11057 xmlChar *cptr;
11058 xmlChar escape[4];
11059
11060 CHECK_ARITY(2);
11061
11062 escape_reserved = xmlXPathPopBoolean(ctxt);
11063
11064 CAST_TO_STRING;
11065 str = valuePop(ctxt);
11066
11067 target = xmlBufferCreate();
11068
11069 escape[0] = '%';
11070 escape[3] = 0;
11071
11072 if (target) {
11073 for (cptr = str->stringval; *cptr; cptr++) {
11074 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11075 (*cptr >= 'a' && *cptr <= 'z') ||
11076 (*cptr >= '0' && *cptr <= '9') ||
11077 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11078 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11079 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11080 (*cptr == '%' &&
11081 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11082 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11083 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11084 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11085 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11086 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11087 (!escape_reserved &&
11088 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11089 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11090 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11091 *cptr == ','))) {
11092 xmlBufferAdd(target, cptr, 1);
11093 } else {
11094 if ((*cptr >> 4) < 10)
11095 escape[1] = '0' + (*cptr >> 4);
11096 else
11097 escape[1] = 'A' - 10 + (*cptr >> 4);
11098 if ((*cptr & 0xF) < 10)
11099 escape[2] = '0' + (*cptr & 0xF);
11100 else
11101 escape[2] = 'A' - 10 + (*cptr & 0xF);
11102
11103 xmlBufferAdd(target, &escape[0], 3);
11104 }
11105 }
11106 }
11107 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11108 xmlBufferFree(target);
11109 xmlXPathFreeObject(str);
11110}
11111
Owen Taylor3473f882001-02-23 17:55:21 +000011112/**
11113 * xmlXPathRegisterAllFunctions:
11114 * @ctxt: the XPath context
11115 *
11116 * Registers all default XPath functions in this context
11117 */
11118void
11119xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11120{
11121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11122 xmlXPathBooleanFunction);
11123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11124 xmlXPathCeilingFunction);
11125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11126 xmlXPathCountFunction);
11127 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11128 xmlXPathConcatFunction);
11129 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11130 xmlXPathContainsFunction);
11131 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11132 xmlXPathIdFunction);
11133 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11134 xmlXPathFalseFunction);
11135 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11136 xmlXPathFloorFunction);
11137 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11138 xmlXPathLastFunction);
11139 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11140 xmlXPathLangFunction);
11141 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11142 xmlXPathLocalNameFunction);
11143 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11144 xmlXPathNotFunction);
11145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11146 xmlXPathNameFunction);
11147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11148 xmlXPathNamespaceURIFunction);
11149 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11150 xmlXPathNormalizeFunction);
11151 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11152 xmlXPathNumberFunction);
11153 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11154 xmlXPathPositionFunction);
11155 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11156 xmlXPathRoundFunction);
11157 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11158 xmlXPathStringFunction);
11159 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11160 xmlXPathStringLengthFunction);
11161 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11162 xmlXPathStartsWithFunction);
11163 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11164 xmlXPathSubstringFunction);
11165 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11166 xmlXPathSubstringBeforeFunction);
11167 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11168 xmlXPathSubstringAfterFunction);
11169 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11170 xmlXPathSumFunction);
11171 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11172 xmlXPathTrueFunction);
11173 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11174 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011175
11176 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11177 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11178 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011179}
11180
11181#endif /* LIBXML_XPATH_ENABLED */