blob: 6b5f1569a3fb9b7253463da2047bf2f7464359d1 [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);
2712 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2713}
2714
2715/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002716 * xmlXPathRegisterFuncLookup:
2717 * @ctxt: the XPath context
2718 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002719 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002720 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002721 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002722 */
2723void
2724xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2725 xmlXPathFuncLookupFunc f,
2726 void *funcCtxt) {
2727 if (ctxt == NULL)
2728 return;
2729 ctxt->funcLookupFunc = (void *) f;
2730 ctxt->funcLookupData = funcCtxt;
2731}
2732
2733/**
Owen Taylor3473f882001-02-23 17:55:21 +00002734 * xmlXPathFunctionLookup:
2735 * @ctxt: the XPath context
2736 * @name: the function name
2737 *
2738 * Search in the Function array of the context for the given
2739 * function.
2740 *
2741 * Returns the xmlXPathFunction or NULL if not found
2742 */
2743xmlXPathFunction
2744xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002745 if (ctxt == NULL)
2746 return (NULL);
2747
2748 if (ctxt->funcLookupFunc != NULL) {
2749 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002750 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002751
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002752 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002753 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002754 if (ret != NULL)
2755 return(ret);
2756 }
Owen Taylor3473f882001-02-23 17:55:21 +00002757 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2758}
2759
2760/**
2761 * xmlXPathFunctionLookupNS:
2762 * @ctxt: the XPath context
2763 * @name: the function name
2764 * @ns_uri: the function namespace URI
2765 *
2766 * Search in the Function array of the context for the given
2767 * function.
2768 *
2769 * Returns the xmlXPathFunction or NULL if not found
2770 */
2771xmlXPathFunction
2772xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2773 const xmlChar *ns_uri) {
2774 if (ctxt == NULL)
2775 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002776 if (name == NULL)
2777 return(NULL);
2778
Thomas Broyerba4ad322001-07-26 16:55:21 +00002779 if (ctxt->funcLookupFunc != NULL) {
2780 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002781 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002782
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002783 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002784 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002785 if (ret != NULL)
2786 return(ret);
2787 }
2788
2789 if (ctxt->funcHash == NULL)
2790 return(NULL);
2791
Owen Taylor3473f882001-02-23 17:55:21 +00002792 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2793}
2794
2795/**
2796 * xmlXPathRegisteredFuncsCleanup:
2797 * @ctxt: the XPath context
2798 *
2799 * Cleanup the XPath context data associated to registered functions
2800 */
2801void
2802xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2803 if (ctxt == NULL)
2804 return;
2805
2806 xmlHashFree(ctxt->funcHash, NULL);
2807 ctxt->funcHash = NULL;
2808}
2809
2810/************************************************************************
2811 * *
2812 * Routines to handle Variable *
2813 * *
2814 ************************************************************************/
2815
2816/**
2817 * xmlXPathRegisterVariable:
2818 * @ctxt: the XPath context
2819 * @name: the variable name
2820 * @value: the variable value or NULL
2821 *
2822 * Register a new variable value. If @value is NULL it unregisters
2823 * the variable
2824 *
2825 * Returns 0 in case of success, -1 in case of error
2826 */
2827int
2828xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2829 xmlXPathObjectPtr value) {
2830 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2831}
2832
2833/**
2834 * xmlXPathRegisterVariableNS:
2835 * @ctxt: the XPath context
2836 * @name: the variable name
2837 * @ns_uri: the variable namespace URI
2838 * @value: the variable value or NULL
2839 *
2840 * Register a new variable value. If @value is NULL it unregisters
2841 * the variable
2842 *
2843 * Returns 0 in case of success, -1 in case of error
2844 */
2845int
2846xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2847 const xmlChar *ns_uri,
2848 xmlXPathObjectPtr value) {
2849 if (ctxt == NULL)
2850 return(-1);
2851 if (name == NULL)
2852 return(-1);
2853
2854 if (ctxt->varHash == NULL)
2855 ctxt->varHash = xmlHashCreate(0);
2856 if (ctxt->varHash == NULL)
2857 return(-1);
2858 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2859 (void *) value,
2860 (xmlHashDeallocator)xmlXPathFreeObject));
2861}
2862
2863/**
2864 * xmlXPathRegisterVariableLookup:
2865 * @ctxt: the XPath context
2866 * @f: the lookup function
2867 * @data: the lookup data
2868 *
2869 * register an external mechanism to do variable lookup
2870 */
2871void
2872xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2873 xmlXPathVariableLookupFunc f, void *data) {
2874 if (ctxt == NULL)
2875 return;
2876 ctxt->varLookupFunc = (void *) f;
2877 ctxt->varLookupData = data;
2878}
2879
2880/**
2881 * xmlXPathVariableLookup:
2882 * @ctxt: the XPath context
2883 * @name: the variable name
2884 *
2885 * Search in the Variable array of the context for the given
2886 * variable value.
2887 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002888 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002889 */
2890xmlXPathObjectPtr
2891xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2892 if (ctxt == NULL)
2893 return(NULL);
2894
2895 if (ctxt->varLookupFunc != NULL) {
2896 xmlXPathObjectPtr ret;
2897
2898 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2899 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002900 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002901 }
2902 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2903}
2904
2905/**
2906 * xmlXPathVariableLookupNS:
2907 * @ctxt: the XPath context
2908 * @name: the variable name
2909 * @ns_uri: the variable namespace URI
2910 *
2911 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002912 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002913 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002914 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002915 */
2916xmlXPathObjectPtr
2917xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2918 const xmlChar *ns_uri) {
2919 if (ctxt == NULL)
2920 return(NULL);
2921
2922 if (ctxt->varLookupFunc != NULL) {
2923 xmlXPathObjectPtr ret;
2924
2925 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2926 (ctxt->varLookupData, name, ns_uri);
2927 if (ret != NULL) return(ret);
2928 }
2929
2930 if (ctxt->varHash == NULL)
2931 return(NULL);
2932 if (name == NULL)
2933 return(NULL);
2934
Daniel Veillard8c357d52001-07-03 23:43:33 +00002935 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2936 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002937}
2938
2939/**
2940 * xmlXPathRegisteredVariablesCleanup:
2941 * @ctxt: the XPath context
2942 *
2943 * Cleanup the XPath context data associated to registered variables
2944 */
2945void
2946xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2947 if (ctxt == NULL)
2948 return;
2949
Daniel Veillard76d66f42001-05-16 21:05:17 +00002950 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002951 ctxt->varHash = NULL;
2952}
2953
2954/**
2955 * xmlXPathRegisterNs:
2956 * @ctxt: the XPath context
2957 * @prefix: the namespace prefix
2958 * @ns_uri: the namespace name
2959 *
2960 * Register a new namespace. If @ns_uri is NULL it unregisters
2961 * the namespace
2962 *
2963 * Returns 0 in case of success, -1 in case of error
2964 */
2965int
2966xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2967 const xmlChar *ns_uri) {
2968 if (ctxt == NULL)
2969 return(-1);
2970 if (prefix == NULL)
2971 return(-1);
2972
2973 if (ctxt->nsHash == NULL)
2974 ctxt->nsHash = xmlHashCreate(10);
2975 if (ctxt->nsHash == NULL)
2976 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002977 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002978 (xmlHashDeallocator)xmlFree));
2979}
2980
2981/**
2982 * xmlXPathNsLookup:
2983 * @ctxt: the XPath context
2984 * @prefix: the namespace prefix value
2985 *
2986 * Search in the namespace declaration array of the context for the given
2987 * namespace name associated to the given prefix
2988 *
2989 * Returns the value or NULL if not found
2990 */
2991const xmlChar *
2992xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2993 if (ctxt == NULL)
2994 return(NULL);
2995 if (prefix == NULL)
2996 return(NULL);
2997
2998#ifdef XML_XML_NAMESPACE
2999 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3000 return(XML_XML_NAMESPACE);
3001#endif
3002
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003003 if (ctxt->namespaces != NULL) {
3004 int i;
3005
3006 for (i = 0;i < ctxt->nsNr;i++) {
3007 if ((ctxt->namespaces[i] != NULL) &&
3008 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3009 return(ctxt->namespaces[i]->href);
3010 }
3011 }
Owen Taylor3473f882001-02-23 17:55:21 +00003012
3013 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3014}
3015
3016/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003017 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003018 * @ctxt: the XPath context
3019 *
3020 * Cleanup the XPath context data associated to registered variables
3021 */
3022void
3023xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3024 if (ctxt == NULL)
3025 return;
3026
Daniel Veillard42766c02002-08-22 20:52:17 +00003027 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003028 ctxt->nsHash = NULL;
3029}
3030
3031/************************************************************************
3032 * *
3033 * Routines to handle Values *
3034 * *
3035 ************************************************************************/
3036
3037/* Allocations are terrible, one need to optimize all this !!! */
3038
3039/**
3040 * xmlXPathNewFloat:
3041 * @val: the double value
3042 *
3043 * Create a new xmlXPathObjectPtr of type double and of value @val
3044 *
3045 * Returns the newly created object.
3046 */
3047xmlXPathObjectPtr
3048xmlXPathNewFloat(double val) {
3049 xmlXPathObjectPtr ret;
3050
3051 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3052 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003053 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003054 return(NULL);
3055 }
3056 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3057 ret->type = XPATH_NUMBER;
3058 ret->floatval = val;
3059 return(ret);
3060}
3061
3062/**
3063 * xmlXPathNewBoolean:
3064 * @val: the boolean value
3065 *
3066 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3067 *
3068 * Returns the newly created object.
3069 */
3070xmlXPathObjectPtr
3071xmlXPathNewBoolean(int val) {
3072 xmlXPathObjectPtr ret;
3073
3074 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3075 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003076 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003077 return(NULL);
3078 }
3079 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3080 ret->type = XPATH_BOOLEAN;
3081 ret->boolval = (val != 0);
3082 return(ret);
3083}
3084
3085/**
3086 * xmlXPathNewString:
3087 * @val: the xmlChar * value
3088 *
3089 * Create a new xmlXPathObjectPtr of type string and of value @val
3090 *
3091 * Returns the newly created object.
3092 */
3093xmlXPathObjectPtr
3094xmlXPathNewString(const xmlChar *val) {
3095 xmlXPathObjectPtr ret;
3096
3097 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3098 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003099 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003100 return(NULL);
3101 }
3102 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3103 ret->type = XPATH_STRING;
3104 if (val != NULL)
3105 ret->stringval = xmlStrdup(val);
3106 else
3107 ret->stringval = xmlStrdup((const xmlChar *)"");
3108 return(ret);
3109}
3110
3111/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003112 * xmlXPathWrapString:
3113 * @val: the xmlChar * value
3114 *
3115 * Wraps the @val string into an XPath object.
3116 *
3117 * Returns the newly created object.
3118 */
3119xmlXPathObjectPtr
3120xmlXPathWrapString (xmlChar *val) {
3121 xmlXPathObjectPtr ret;
3122
3123 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3124 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003125 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003126 return(NULL);
3127 }
3128 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3129 ret->type = XPATH_STRING;
3130 ret->stringval = val;
3131 return(ret);
3132}
3133
3134/**
Owen Taylor3473f882001-02-23 17:55:21 +00003135 * xmlXPathNewCString:
3136 * @val: the char * value
3137 *
3138 * Create a new xmlXPathObjectPtr of type string and of value @val
3139 *
3140 * Returns the newly created object.
3141 */
3142xmlXPathObjectPtr
3143xmlXPathNewCString(const char *val) {
3144 xmlXPathObjectPtr ret;
3145
3146 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3147 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003148 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003149 return(NULL);
3150 }
3151 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3152 ret->type = XPATH_STRING;
3153 ret->stringval = xmlStrdup(BAD_CAST val);
3154 return(ret);
3155}
3156
3157/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003158 * xmlXPathWrapCString:
3159 * @val: the char * value
3160 *
3161 * Wraps a string into an XPath object.
3162 *
3163 * Returns the newly created object.
3164 */
3165xmlXPathObjectPtr
3166xmlXPathWrapCString (char * val) {
3167 return(xmlXPathWrapString((xmlChar *)(val)));
3168}
3169
3170/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003171 * xmlXPathWrapExternal:
3172 * @val: the user data
3173 *
3174 * Wraps the @val data into an XPath object.
3175 *
3176 * Returns the newly created object.
3177 */
3178xmlXPathObjectPtr
3179xmlXPathWrapExternal (void *val) {
3180 xmlXPathObjectPtr ret;
3181
3182 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3183 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003184 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003185 return(NULL);
3186 }
3187 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3188 ret->type = XPATH_USERS;
3189 ret->user = val;
3190 return(ret);
3191}
3192
3193/**
Owen Taylor3473f882001-02-23 17:55:21 +00003194 * xmlXPathObjectCopy:
3195 * @val: the original object
3196 *
3197 * allocate a new copy of a given object
3198 *
3199 * Returns the newly created object.
3200 */
3201xmlXPathObjectPtr
3202xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3203 xmlXPathObjectPtr ret;
3204
3205 if (val == NULL)
3206 return(NULL);
3207
3208 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3209 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003210 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003211 return(NULL);
3212 }
3213 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3214 switch (val->type) {
3215 case XPATH_BOOLEAN:
3216 case XPATH_NUMBER:
3217 case XPATH_POINT:
3218 case XPATH_RANGE:
3219 break;
3220 case XPATH_STRING:
3221 ret->stringval = xmlStrdup(val->stringval);
3222 break;
3223 case XPATH_XSLT_TREE:
3224 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003225 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003226 xmlNodePtr cur, tmp;
3227 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003228
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003229 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003230 top = xmlNewDoc(NULL);
3231 top->name = (char *)
3232 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003233 ret->user = top;
3234 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003235 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003236 cur = val->nodesetval->nodeTab[0]->children;
3237 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003238 tmp = xmlDocCopyNode(cur, top, 1);
3239 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003240 cur = cur->next;
3241 }
3242 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003243 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003244 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003245 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003246 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003247 break;
3248 case XPATH_NODESET:
3249 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003250 /* Do not deallocate the copied tree value */
3251 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003252 break;
3253 case XPATH_LOCATIONSET:
3254#ifdef LIBXML_XPTR_ENABLED
3255 {
3256 xmlLocationSetPtr loc = val->user;
3257 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3258 break;
3259 }
3260#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003261 case XPATH_USERS:
3262 ret->user = val->user;
3263 break;
3264 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003265 xmlGenericError(xmlGenericErrorContext,
3266 "xmlXPathObjectCopy: unsupported type %d\n",
3267 val->type);
3268 break;
3269 }
3270 return(ret);
3271}
3272
3273/**
3274 * xmlXPathFreeObject:
3275 * @obj: the object to free
3276 *
3277 * Free up an xmlXPathObjectPtr object.
3278 */
3279void
3280xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3281 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003282 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003283 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003284 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003285 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003286 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003287 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003288 xmlXPathFreeValueTree(obj->nodesetval);
3289 } else {
3290 if (obj->nodesetval != NULL)
3291 xmlXPathFreeNodeSet(obj->nodesetval);
3292 }
Owen Taylor3473f882001-02-23 17:55:21 +00003293#ifdef LIBXML_XPTR_ENABLED
3294 } else if (obj->type == XPATH_LOCATIONSET) {
3295 if (obj->user != NULL)
3296 xmlXPtrFreeLocationSet(obj->user);
3297#endif
3298 } else if (obj->type == XPATH_STRING) {
3299 if (obj->stringval != NULL)
3300 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003301 }
3302
Owen Taylor3473f882001-02-23 17:55:21 +00003303 xmlFree(obj);
3304}
3305
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003306
3307/************************************************************************
3308 * *
3309 * Type Casting Routines *
3310 * *
3311 ************************************************************************/
3312
3313/**
3314 * xmlXPathCastBooleanToString:
3315 * @val: a boolean
3316 *
3317 * Converts a boolean to its string value.
3318 *
3319 * Returns a newly allocated string.
3320 */
3321xmlChar *
3322xmlXPathCastBooleanToString (int val) {
3323 xmlChar *ret;
3324 if (val)
3325 ret = xmlStrdup((const xmlChar *) "true");
3326 else
3327 ret = xmlStrdup((const xmlChar *) "false");
3328 return(ret);
3329}
3330
3331/**
3332 * xmlXPathCastNumberToString:
3333 * @val: a number
3334 *
3335 * Converts a number to its string value.
3336 *
3337 * Returns a newly allocated string.
3338 */
3339xmlChar *
3340xmlXPathCastNumberToString (double val) {
3341 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003342 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003343 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003344 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003345 break;
3346 case -1:
3347 ret = xmlStrdup((const xmlChar *) "-Infinity");
3348 break;
3349 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003350 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003351 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003352 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3353 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003354 } else {
3355 /* could be improved */
3356 char buf[100];
3357 xmlXPathFormatNumber(val, buf, 100);
3358 ret = xmlStrdup((const xmlChar *) buf);
3359 }
3360 }
3361 return(ret);
3362}
3363
3364/**
3365 * xmlXPathCastNodeToString:
3366 * @node: a node
3367 *
3368 * Converts a node to its string value.
3369 *
3370 * Returns a newly allocated string.
3371 */
3372xmlChar *
3373xmlXPathCastNodeToString (xmlNodePtr node) {
3374 return(xmlNodeGetContent(node));
3375}
3376
3377/**
3378 * xmlXPathCastNodeSetToString:
3379 * @ns: a node-set
3380 *
3381 * Converts a node-set to its string value.
3382 *
3383 * Returns a newly allocated string.
3384 */
3385xmlChar *
3386xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3387 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3388 return(xmlStrdup((const xmlChar *) ""));
3389
3390 xmlXPathNodeSetSort(ns);
3391 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3392}
3393
3394/**
3395 * xmlXPathCastToString:
3396 * @val: an XPath object
3397 *
3398 * Converts an existing object to its string() equivalent
3399 *
3400 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003401 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003402 * string object).
3403 */
3404xmlChar *
3405xmlXPathCastToString(xmlXPathObjectPtr val) {
3406 xmlChar *ret = NULL;
3407
3408 if (val == NULL)
3409 return(xmlStrdup((const xmlChar *) ""));
3410 switch (val->type) {
3411 case XPATH_UNDEFINED:
3412#ifdef DEBUG_EXPR
3413 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3414#endif
3415 ret = xmlStrdup((const xmlChar *) "");
3416 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003417 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003418 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003419 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3420 break;
3421 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003422 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003423 case XPATH_BOOLEAN:
3424 ret = xmlXPathCastBooleanToString(val->boolval);
3425 break;
3426 case XPATH_NUMBER: {
3427 ret = xmlXPathCastNumberToString(val->floatval);
3428 break;
3429 }
3430 case XPATH_USERS:
3431 case XPATH_POINT:
3432 case XPATH_RANGE:
3433 case XPATH_LOCATIONSET:
3434 TODO
3435 ret = xmlStrdup((const xmlChar *) "");
3436 break;
3437 }
3438 return(ret);
3439}
3440
3441/**
3442 * xmlXPathConvertString:
3443 * @val: an XPath object
3444 *
3445 * Converts an existing object to its string() equivalent
3446 *
3447 * Returns the new object, the old one is freed (or the operation
3448 * is done directly on @val)
3449 */
3450xmlXPathObjectPtr
3451xmlXPathConvertString(xmlXPathObjectPtr val) {
3452 xmlChar *res = NULL;
3453
3454 if (val == NULL)
3455 return(xmlXPathNewCString(""));
3456
3457 switch (val->type) {
3458 case XPATH_UNDEFINED:
3459#ifdef DEBUG_EXPR
3460 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3461#endif
3462 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003463 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003464 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003465 res = xmlXPathCastNodeSetToString(val->nodesetval);
3466 break;
3467 case XPATH_STRING:
3468 return(val);
3469 case XPATH_BOOLEAN:
3470 res = xmlXPathCastBooleanToString(val->boolval);
3471 break;
3472 case XPATH_NUMBER:
3473 res = xmlXPathCastNumberToString(val->floatval);
3474 break;
3475 case XPATH_USERS:
3476 case XPATH_POINT:
3477 case XPATH_RANGE:
3478 case XPATH_LOCATIONSET:
3479 TODO;
3480 break;
3481 }
3482 xmlXPathFreeObject(val);
3483 if (res == NULL)
3484 return(xmlXPathNewCString(""));
3485 return(xmlXPathWrapString(res));
3486}
3487
3488/**
3489 * xmlXPathCastBooleanToNumber:
3490 * @val: a boolean
3491 *
3492 * Converts a boolean to its number value
3493 *
3494 * Returns the number value
3495 */
3496double
3497xmlXPathCastBooleanToNumber(int val) {
3498 if (val)
3499 return(1.0);
3500 return(0.0);
3501}
3502
3503/**
3504 * xmlXPathCastStringToNumber:
3505 * @val: a string
3506 *
3507 * Converts a string to its number value
3508 *
3509 * Returns the number value
3510 */
3511double
3512xmlXPathCastStringToNumber(const xmlChar * val) {
3513 return(xmlXPathStringEvalNumber(val));
3514}
3515
3516/**
3517 * xmlXPathCastNodeToNumber:
3518 * @node: a node
3519 *
3520 * Converts a node to its number value
3521 *
3522 * Returns the number value
3523 */
3524double
3525xmlXPathCastNodeToNumber (xmlNodePtr node) {
3526 xmlChar *strval;
3527 double ret;
3528
3529 if (node == NULL)
3530 return(xmlXPathNAN);
3531 strval = xmlXPathCastNodeToString(node);
3532 if (strval == NULL)
3533 return(xmlXPathNAN);
3534 ret = xmlXPathCastStringToNumber(strval);
3535 xmlFree(strval);
3536
3537 return(ret);
3538}
3539
3540/**
3541 * xmlXPathCastNodeSetToNumber:
3542 * @ns: a node-set
3543 *
3544 * Converts a node-set to its number value
3545 *
3546 * Returns the number value
3547 */
3548double
3549xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3550 xmlChar *str;
3551 double ret;
3552
3553 if (ns == NULL)
3554 return(xmlXPathNAN);
3555 str = xmlXPathCastNodeSetToString(ns);
3556 ret = xmlXPathCastStringToNumber(str);
3557 xmlFree(str);
3558 return(ret);
3559}
3560
3561/**
3562 * xmlXPathCastToNumber:
3563 * @val: an XPath object
3564 *
3565 * Converts an XPath object to its number value
3566 *
3567 * Returns the number value
3568 */
3569double
3570xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3571 double ret = 0.0;
3572
3573 if (val == NULL)
3574 return(xmlXPathNAN);
3575 switch (val->type) {
3576 case XPATH_UNDEFINED:
3577#ifdef DEGUB_EXPR
3578 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3579#endif
3580 ret = xmlXPathNAN;
3581 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003582 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003583 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003584 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3585 break;
3586 case XPATH_STRING:
3587 ret = xmlXPathCastStringToNumber(val->stringval);
3588 break;
3589 case XPATH_NUMBER:
3590 ret = val->floatval;
3591 break;
3592 case XPATH_BOOLEAN:
3593 ret = xmlXPathCastBooleanToNumber(val->boolval);
3594 break;
3595 case XPATH_USERS:
3596 case XPATH_POINT:
3597 case XPATH_RANGE:
3598 case XPATH_LOCATIONSET:
3599 TODO;
3600 ret = xmlXPathNAN;
3601 break;
3602 }
3603 return(ret);
3604}
3605
3606/**
3607 * xmlXPathConvertNumber:
3608 * @val: an XPath object
3609 *
3610 * Converts an existing object to its number() equivalent
3611 *
3612 * Returns the new object, the old one is freed (or the operation
3613 * is done directly on @val)
3614 */
3615xmlXPathObjectPtr
3616xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3617 xmlXPathObjectPtr ret;
3618
3619 if (val == NULL)
3620 return(xmlXPathNewFloat(0.0));
3621 if (val->type == XPATH_NUMBER)
3622 return(val);
3623 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3624 xmlXPathFreeObject(val);
3625 return(ret);
3626}
3627
3628/**
3629 * xmlXPathCastNumberToBoolean:
3630 * @val: a number
3631 *
3632 * Converts a number to its boolean value
3633 *
3634 * Returns the boolean value
3635 */
3636int
3637xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003638 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003639 return(0);
3640 return(1);
3641}
3642
3643/**
3644 * xmlXPathCastStringToBoolean:
3645 * @val: a string
3646 *
3647 * Converts a string to its boolean value
3648 *
3649 * Returns the boolean value
3650 */
3651int
3652xmlXPathCastStringToBoolean (const xmlChar *val) {
3653 if ((val == NULL) || (xmlStrlen(val) == 0))
3654 return(0);
3655 return(1);
3656}
3657
3658/**
3659 * xmlXPathCastNodeSetToBoolean:
3660 * @ns: a node-set
3661 *
3662 * Converts a node-set to its boolean value
3663 *
3664 * Returns the boolean value
3665 */
3666int
3667xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3668 if ((ns == NULL) || (ns->nodeNr == 0))
3669 return(0);
3670 return(1);
3671}
3672
3673/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003674 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003675 * @val: an XPath object
3676 *
3677 * Converts an XPath object to its boolean value
3678 *
3679 * Returns the boolean value
3680 */
3681int
3682xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3683 int ret = 0;
3684
3685 if (val == NULL)
3686 return(0);
3687 switch (val->type) {
3688 case XPATH_UNDEFINED:
3689#ifdef DEBUG_EXPR
3690 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3691#endif
3692 ret = 0;
3693 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003694 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003695 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003696 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3697 break;
3698 case XPATH_STRING:
3699 ret = xmlXPathCastStringToBoolean(val->stringval);
3700 break;
3701 case XPATH_NUMBER:
3702 ret = xmlXPathCastNumberToBoolean(val->floatval);
3703 break;
3704 case XPATH_BOOLEAN:
3705 ret = val->boolval;
3706 break;
3707 case XPATH_USERS:
3708 case XPATH_POINT:
3709 case XPATH_RANGE:
3710 case XPATH_LOCATIONSET:
3711 TODO;
3712 ret = 0;
3713 break;
3714 }
3715 return(ret);
3716}
3717
3718
3719/**
3720 * xmlXPathConvertBoolean:
3721 * @val: an XPath object
3722 *
3723 * Converts an existing object to its boolean() equivalent
3724 *
3725 * Returns the new object, the old one is freed (or the operation
3726 * is done directly on @val)
3727 */
3728xmlXPathObjectPtr
3729xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3730 xmlXPathObjectPtr ret;
3731
3732 if (val == NULL)
3733 return(xmlXPathNewBoolean(0));
3734 if (val->type == XPATH_BOOLEAN)
3735 return(val);
3736 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3737 xmlXPathFreeObject(val);
3738 return(ret);
3739}
3740
Owen Taylor3473f882001-02-23 17:55:21 +00003741/************************************************************************
3742 * *
3743 * Routines to handle XPath contexts *
3744 * *
3745 ************************************************************************/
3746
3747/**
3748 * xmlXPathNewContext:
3749 * @doc: the XML document
3750 *
3751 * Create a new xmlXPathContext
3752 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003753 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003754 */
3755xmlXPathContextPtr
3756xmlXPathNewContext(xmlDocPtr doc) {
3757 xmlXPathContextPtr ret;
3758
3759 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3760 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003761 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003762 return(NULL);
3763 }
3764 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3765 ret->doc = doc;
3766 ret->node = NULL;
3767
3768 ret->varHash = NULL;
3769
3770 ret->nb_types = 0;
3771 ret->max_types = 0;
3772 ret->types = NULL;
3773
3774 ret->funcHash = xmlHashCreate(0);
3775
3776 ret->nb_axis = 0;
3777 ret->max_axis = 0;
3778 ret->axis = NULL;
3779
3780 ret->nsHash = NULL;
3781 ret->user = NULL;
3782
3783 ret->contextSize = -1;
3784 ret->proximityPosition = -1;
3785
3786 xmlXPathRegisterAllFunctions(ret);
3787
3788 return(ret);
3789}
3790
3791/**
3792 * xmlXPathFreeContext:
3793 * @ctxt: the context to free
3794 *
3795 * Free up an xmlXPathContext
3796 */
3797void
3798xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3799 xmlXPathRegisteredNsCleanup(ctxt);
3800 xmlXPathRegisteredFuncsCleanup(ctxt);
3801 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003802 xmlFree(ctxt);
3803}
3804
3805/************************************************************************
3806 * *
3807 * Routines to handle XPath parser contexts *
3808 * *
3809 ************************************************************************/
3810
3811#define CHECK_CTXT(ctxt) \
3812 if (ctxt == NULL) { \
3813 xmlGenericError(xmlGenericErrorContext, \
3814 "%s:%d Internal error: ctxt == NULL\n", \
3815 __FILE__, __LINE__); \
3816 } \
3817
3818
3819#define CHECK_CONTEXT(ctxt) \
3820 if (ctxt == NULL) { \
3821 xmlGenericError(xmlGenericErrorContext, \
3822 "%s:%d Internal error: no context\n", \
3823 __FILE__, __LINE__); \
3824 } \
3825 else if (ctxt->doc == NULL) { \
3826 xmlGenericError(xmlGenericErrorContext, \
3827 "%s:%d Internal error: no document\n", \
3828 __FILE__, __LINE__); \
3829 } \
3830 else if (ctxt->doc->children == NULL) { \
3831 xmlGenericError(xmlGenericErrorContext, \
3832 "%s:%d Internal error: document without root\n", \
3833 __FILE__, __LINE__); \
3834 } \
3835
3836
3837/**
3838 * xmlXPathNewParserContext:
3839 * @str: the XPath expression
3840 * @ctxt: the XPath context
3841 *
3842 * Create a new xmlXPathParserContext
3843 *
3844 * Returns the xmlXPathParserContext just allocated.
3845 */
3846xmlXPathParserContextPtr
3847xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3848 xmlXPathParserContextPtr ret;
3849
3850 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3851 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003852 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003853 return(NULL);
3854 }
3855 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3856 ret->cur = ret->base = str;
3857 ret->context = ctxt;
3858
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003859 ret->comp = xmlXPathNewCompExpr();
3860 if (ret->comp == NULL) {
3861 xmlFree(ret->valueTab);
3862 xmlFree(ret);
3863 return(NULL);
3864 }
3865
3866 return(ret);
3867}
3868
3869/**
3870 * xmlXPathCompParserContext:
3871 * @comp: the XPath compiled expression
3872 * @ctxt: the XPath context
3873 *
3874 * Create a new xmlXPathParserContext when processing a compiled expression
3875 *
3876 * Returns the xmlXPathParserContext just allocated.
3877 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003878static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003879xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3880 xmlXPathParserContextPtr ret;
3881
3882 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3883 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003884 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003885 return(NULL);
3886 }
3887 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3888
Owen Taylor3473f882001-02-23 17:55:21 +00003889 /* Allocate the value stack */
3890 ret->valueTab = (xmlXPathObjectPtr *)
3891 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003892 if (ret->valueTab == NULL) {
3893 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003894 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003895 return(NULL);
3896 }
Owen Taylor3473f882001-02-23 17:55:21 +00003897 ret->valueNr = 0;
3898 ret->valueMax = 10;
3899 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003900
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003901 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003902 ret->comp = comp;
3903
Owen Taylor3473f882001-02-23 17:55:21 +00003904 return(ret);
3905}
3906
3907/**
3908 * xmlXPathFreeParserContext:
3909 * @ctxt: the context to free
3910 *
3911 * Free up an xmlXPathParserContext
3912 */
3913void
3914xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3915 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003916 xmlFree(ctxt->valueTab);
3917 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003918 if (ctxt->comp)
3919 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003920 xmlFree(ctxt);
3921}
3922
3923/************************************************************************
3924 * *
3925 * The implicit core function library *
3926 * *
3927 ************************************************************************/
3928
Owen Taylor3473f882001-02-23 17:55:21 +00003929/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003930 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003931 * @node: a node pointer
3932 *
3933 * Function computing the beginning of the string value of the node,
3934 * used to speed up comparisons
3935 *
3936 * Returns an int usable as a hash
3937 */
3938static unsigned int
3939xmlXPathNodeValHash(xmlNodePtr node) {
3940 int len = 2;
3941 const xmlChar * string = NULL;
3942 xmlNodePtr tmp = NULL;
3943 unsigned int ret = 0;
3944
3945 if (node == NULL)
3946 return(0);
3947
Daniel Veillard9adc0462003-03-24 18:39:54 +00003948 if (node->type == XML_DOCUMENT_NODE) {
3949 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3950 if (tmp == NULL)
3951 node = node->children;
3952 else
3953 node = tmp;
3954
3955 if (node == NULL)
3956 return(0);
3957 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003958
3959 switch (node->type) {
3960 case XML_COMMENT_NODE:
3961 case XML_PI_NODE:
3962 case XML_CDATA_SECTION_NODE:
3963 case XML_TEXT_NODE:
3964 string = node->content;
3965 if (string == NULL)
3966 return(0);
3967 if (string[0] == 0)
3968 return(0);
3969 return(((unsigned int) string[0]) +
3970 (((unsigned int) string[1]) << 8));
3971 case XML_NAMESPACE_DECL:
3972 string = ((xmlNsPtr)node)->href;
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_ATTRIBUTE_NODE:
3980 tmp = ((xmlAttrPtr) node)->children;
3981 break;
3982 case XML_ELEMENT_NODE:
3983 tmp = node->children;
3984 break;
3985 default:
3986 return(0);
3987 }
3988 while (tmp != NULL) {
3989 switch (tmp->type) {
3990 case XML_COMMENT_NODE:
3991 case XML_PI_NODE:
3992 case XML_CDATA_SECTION_NODE:
3993 case XML_TEXT_NODE:
3994 string = tmp->content;
3995 break;
3996 case XML_NAMESPACE_DECL:
3997 string = ((xmlNsPtr)tmp)->href;
3998 break;
3999 default:
4000 break;
4001 }
4002 if ((string != NULL) && (string[0] != 0)) {
4003 if (string[0] == 0)
4004 return(0);
4005 if (len == 1) {
4006 return(ret + (((unsigned int) string[0]) << 8));
4007 }
4008 if (string[1] == 0) {
4009 len = 1;
4010 ret = (unsigned int) string[0];
4011 } else {
4012 return(((unsigned int) string[0]) +
4013 (((unsigned int) string[1]) << 8));
4014 }
4015 }
4016 /*
4017 * Skip to next node
4018 */
4019 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4020 if (tmp->children->type != XML_ENTITY_DECL) {
4021 tmp = tmp->children;
4022 continue;
4023 }
4024 }
4025 if (tmp == node)
4026 break;
4027
4028 if (tmp->next != NULL) {
4029 tmp = tmp->next;
4030 continue;
4031 }
4032
4033 do {
4034 tmp = tmp->parent;
4035 if (tmp == NULL)
4036 break;
4037 if (tmp == node) {
4038 tmp = NULL;
4039 break;
4040 }
4041 if (tmp->next != NULL) {
4042 tmp = tmp->next;
4043 break;
4044 }
4045 } while (tmp != NULL);
4046 }
4047 return(ret);
4048}
4049
4050/**
4051 * xmlXPathStringHash:
4052 * @string: a string
4053 *
4054 * Function computing the beginning of the string value of the node,
4055 * used to speed up comparisons
4056 *
4057 * Returns an int usable as a hash
4058 */
4059static unsigned int
4060xmlXPathStringHash(const xmlChar * string) {
4061 if (string == NULL)
4062 return((unsigned int) 0);
4063 if (string[0] == 0)
4064 return(0);
4065 return(((unsigned int) string[0]) +
4066 (((unsigned int) string[1]) << 8));
4067}
4068
4069/**
Owen Taylor3473f882001-02-23 17:55:21 +00004070 * xmlXPathCompareNodeSetFloat:
4071 * @ctxt: the XPath Parser context
4072 * @inf: less than (1) or greater than (0)
4073 * @strict: is the comparison strict
4074 * @arg: the node set
4075 * @f: the value
4076 *
4077 * Implement the compare operation between a nodeset and a number
4078 * @ns < @val (1, 1, ...
4079 * @ns <= @val (1, 0, ...
4080 * @ns > @val (0, 1, ...
4081 * @ns >= @val (0, 0, ...
4082 *
4083 * If one object to be compared is a node-set and the other is a number,
4084 * then the comparison will be true if and only if there is a node in the
4085 * node-set such that the result of performing the comparison on the number
4086 * to be compared and on the result of converting the string-value of that
4087 * node to a number using the number function is true.
4088 *
4089 * Returns 0 or 1 depending on the results of the test.
4090 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004091static int
Owen Taylor3473f882001-02-23 17:55:21 +00004092xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4093 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4094 int i, ret = 0;
4095 xmlNodeSetPtr ns;
4096 xmlChar *str2;
4097
4098 if ((f == NULL) || (arg == NULL) ||
4099 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4100 xmlXPathFreeObject(arg);
4101 xmlXPathFreeObject(f);
4102 return(0);
4103 }
4104 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004105 if (ns != NULL) {
4106 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004107 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004108 if (str2 != NULL) {
4109 valuePush(ctxt,
4110 xmlXPathNewString(str2));
4111 xmlFree(str2);
4112 xmlXPathNumberFunction(ctxt, 1);
4113 valuePush(ctxt, xmlXPathObjectCopy(f));
4114 ret = xmlXPathCompareValues(ctxt, inf, strict);
4115 if (ret)
4116 break;
4117 }
4118 }
Owen Taylor3473f882001-02-23 17:55:21 +00004119 }
4120 xmlXPathFreeObject(arg);
4121 xmlXPathFreeObject(f);
4122 return(ret);
4123}
4124
4125/**
4126 * xmlXPathCompareNodeSetString:
4127 * @ctxt: the XPath Parser context
4128 * @inf: less than (1) or greater than (0)
4129 * @strict: is the comparison strict
4130 * @arg: the node set
4131 * @s: the value
4132 *
4133 * Implement the compare operation between a nodeset and a string
4134 * @ns < @val (1, 1, ...
4135 * @ns <= @val (1, 0, ...
4136 * @ns > @val (0, 1, ...
4137 * @ns >= @val (0, 0, ...
4138 *
4139 * If one object to be compared is a node-set and the other is a string,
4140 * then the comparison will be true if and only if there is a node in
4141 * the node-set such that the result of performing the comparison on the
4142 * string-value of the node and the other string is true.
4143 *
4144 * Returns 0 or 1 depending on the results of the test.
4145 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004146static int
Owen Taylor3473f882001-02-23 17:55:21 +00004147xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4148 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4149 int i, ret = 0;
4150 xmlNodeSetPtr ns;
4151 xmlChar *str2;
4152
4153 if ((s == NULL) || (arg == NULL) ||
4154 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4155 xmlXPathFreeObject(arg);
4156 xmlXPathFreeObject(s);
4157 return(0);
4158 }
4159 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004160 if (ns != NULL) {
4161 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004162 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004163 if (str2 != NULL) {
4164 valuePush(ctxt,
4165 xmlXPathNewString(str2));
4166 xmlFree(str2);
4167 valuePush(ctxt, xmlXPathObjectCopy(s));
4168 ret = xmlXPathCompareValues(ctxt, inf, strict);
4169 if (ret)
4170 break;
4171 }
4172 }
Owen Taylor3473f882001-02-23 17:55:21 +00004173 }
4174 xmlXPathFreeObject(arg);
4175 xmlXPathFreeObject(s);
4176 return(ret);
4177}
4178
4179/**
4180 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004181 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004182 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004183 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004184 * @arg2: the second node set object
4185 *
4186 * Implement the compare operation on nodesets:
4187 *
4188 * If both objects to be compared are node-sets, then the comparison
4189 * will be true if and only if there is a node in the first node-set
4190 * and a node in the second node-set such that the result of performing
4191 * the comparison on the string-values of the two nodes is true.
4192 * ....
4193 * When neither object to be compared is a node-set and the operator
4194 * is <=, <, >= or >, then the objects are compared by converting both
4195 * objects to numbers and comparing the numbers according to IEEE 754.
4196 * ....
4197 * The number function converts its argument to a number as follows:
4198 * - a string that consists of optional whitespace followed by an
4199 * optional minus sign followed by a Number followed by whitespace
4200 * is converted to the IEEE 754 number that is nearest (according
4201 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4202 * represented by the string; any other string is converted to NaN
4203 *
4204 * Conclusion all nodes need to be converted first to their string value
4205 * and then the comparison must be done when possible
4206 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004207static int
4208xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004209 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4210 int i, j, init = 0;
4211 double val1;
4212 double *values2;
4213 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004214 xmlNodeSetPtr ns1;
4215 xmlNodeSetPtr ns2;
4216
4217 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004218 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4219 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004220 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004221 }
Owen Taylor3473f882001-02-23 17:55:21 +00004222 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004223 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4224 xmlXPathFreeObject(arg1);
4225 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004226 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004227 }
Owen Taylor3473f882001-02-23 17:55:21 +00004228
4229 ns1 = arg1->nodesetval;
4230 ns2 = arg2->nodesetval;
4231
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004232 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004233 xmlXPathFreeObject(arg1);
4234 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004235 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004236 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004237 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004238 xmlXPathFreeObject(arg1);
4239 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004240 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004241 }
Owen Taylor3473f882001-02-23 17:55:21 +00004242
4243 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4244 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004245 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004246 xmlXPathFreeObject(arg1);
4247 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004248 return(0);
4249 }
4250 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004251 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004252 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004253 continue;
4254 for (j = 0;j < ns2->nodeNr;j++) {
4255 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004256 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004257 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004258 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004259 continue;
4260 if (inf && strict)
4261 ret = (val1 < values2[j]);
4262 else if (inf && !strict)
4263 ret = (val1 <= values2[j]);
4264 else if (!inf && strict)
4265 ret = (val1 > values2[j]);
4266 else if (!inf && !strict)
4267 ret = (val1 >= values2[j]);
4268 if (ret)
4269 break;
4270 }
4271 if (ret)
4272 break;
4273 init = 1;
4274 }
4275 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004276 xmlXPathFreeObject(arg1);
4277 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004278 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004279}
4280
4281/**
4282 * xmlXPathCompareNodeSetValue:
4283 * @ctxt: the XPath Parser context
4284 * @inf: less than (1) or greater than (0)
4285 * @strict: is the comparison strict
4286 * @arg: the node set
4287 * @val: the value
4288 *
4289 * Implement the compare operation between a nodeset and a value
4290 * @ns < @val (1, 1, ...
4291 * @ns <= @val (1, 0, ...
4292 * @ns > @val (0, 1, ...
4293 * @ns >= @val (0, 0, ...
4294 *
4295 * If one object to be compared is a node-set and the other is a boolean,
4296 * then the comparison will be true if and only if the result of performing
4297 * the comparison on the boolean and on the result of converting
4298 * the node-set to a boolean using the boolean function is true.
4299 *
4300 * Returns 0 or 1 depending on the results of the test.
4301 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004302static int
Owen Taylor3473f882001-02-23 17:55:21 +00004303xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4304 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4305 if ((val == NULL) || (arg == NULL) ||
4306 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4307 return(0);
4308
4309 switch(val->type) {
4310 case XPATH_NUMBER:
4311 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4312 case XPATH_NODESET:
4313 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004314 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004315 case XPATH_STRING:
4316 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4317 case XPATH_BOOLEAN:
4318 valuePush(ctxt, arg);
4319 xmlXPathBooleanFunction(ctxt, 1);
4320 valuePush(ctxt, val);
4321 return(xmlXPathCompareValues(ctxt, inf, strict));
4322 default:
4323 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004324 }
4325 return(0);
4326}
4327
4328/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004329 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004330 * @arg: the nodeset object argument
4331 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004332 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004333 *
4334 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4335 * If one object to be compared is a node-set and the other is a string,
4336 * then the comparison will be true if and only if there is a node in
4337 * the node-set such that the result of performing the comparison on the
4338 * string-value of the node and the other string is true.
4339 *
4340 * Returns 0 or 1 depending on the results of the test.
4341 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004342static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004343xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004344{
Owen Taylor3473f882001-02-23 17:55:21 +00004345 int i;
4346 xmlNodeSetPtr ns;
4347 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004348 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004349
4350 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004351 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4352 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004353 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004354 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004355 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004356 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004357 if (ns->nodeNr <= 0) {
4358 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004359 return(neq ^ 1);
4360 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004361 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004362 for (i = 0; i < ns->nodeNr; i++) {
4363 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4364 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4365 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4366 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004367 if (neq)
4368 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004369 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004370 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4371 if (neq)
4372 continue;
4373 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004374 } else if (neq) {
4375 if (str2 != NULL)
4376 xmlFree(str2);
4377 return (1);
4378 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004379 if (str2 != NULL)
4380 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004381 } else if (neq)
4382 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004383 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004384 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004385}
4386
4387/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004388 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004389 * @arg: the nodeset object argument
4390 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004391 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004392 *
4393 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4394 * If one object to be compared is a node-set and the other is a number,
4395 * then the comparison will be true if and only if there is a node in
4396 * the node-set such that the result of performing the comparison on the
4397 * number to be compared and on the result of converting the string-value
4398 * of that node to a number using the number function is true.
4399 *
4400 * Returns 0 or 1 depending on the results of the test.
4401 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004402static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004403xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4404 xmlXPathObjectPtr arg, double f, int neq) {
4405 int i, ret=0;
4406 xmlNodeSetPtr ns;
4407 xmlChar *str2;
4408 xmlXPathObjectPtr val;
4409 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004410
4411 if ((arg == NULL) ||
4412 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4413 return(0);
4414
William M. Brack0c022ad2002-07-12 00:56:01 +00004415 ns = arg->nodesetval;
4416 if (ns != NULL) {
4417 for (i=0;i<ns->nodeNr;i++) {
4418 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4419 if (str2 != NULL) {
4420 valuePush(ctxt, xmlXPathNewString(str2));
4421 xmlFree(str2);
4422 xmlXPathNumberFunction(ctxt, 1);
4423 val = valuePop(ctxt);
4424 v = val->floatval;
4425 xmlXPathFreeObject(val);
4426 if (!xmlXPathIsNaN(v)) {
4427 if ((!neq) && (v==f)) {
4428 ret = 1;
4429 break;
4430 } else if ((neq) && (v!=f)) {
4431 ret = 1;
4432 break;
4433 }
4434 }
4435 }
4436 }
4437 }
4438
4439 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004440}
4441
4442
4443/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004444 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004445 * @arg1: first nodeset object argument
4446 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004447 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004448 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004449 * Implement the equal / not equal operation on XPath nodesets:
4450 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004451 * If both objects to be compared are node-sets, then the comparison
4452 * will be true if and only if there is a node in the first node-set and
4453 * a node in the second node-set such that the result of performing the
4454 * comparison on the string-values of the two nodes is true.
4455 *
4456 * (needless to say, this is a costly operation)
4457 *
4458 * Returns 0 or 1 depending on the results of the test.
4459 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004460static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004461xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004462 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004463 unsigned int *hashs1;
4464 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004465 xmlChar **values1;
4466 xmlChar **values2;
4467 int ret = 0;
4468 xmlNodeSetPtr ns1;
4469 xmlNodeSetPtr ns2;
4470
4471 if ((arg1 == NULL) ||
4472 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4473 return(0);
4474 if ((arg2 == NULL) ||
4475 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4476 return(0);
4477
4478 ns1 = arg1->nodesetval;
4479 ns2 = arg2->nodesetval;
4480
Daniel Veillard911f49a2001-04-07 15:39:35 +00004481 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004482 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004483 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004484 return(0);
4485
4486 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004487 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004488 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004489 if (neq == 0)
4490 for (i = 0;i < ns1->nodeNr;i++)
4491 for (j = 0;j < ns2->nodeNr;j++)
4492 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4493 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004494
4495 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004496 if (values1 == NULL) {
4497 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004498 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004499 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004500 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4501 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004502 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004503 xmlFree(values1);
4504 return(0);
4505 }
Owen Taylor3473f882001-02-23 17:55:21 +00004506 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4507 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4508 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004509 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004510 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004511 xmlFree(values1);
4512 return(0);
4513 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004514 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4515 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004516 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004517 xmlFree(hashs1);
4518 xmlFree(values1);
4519 xmlFree(values2);
4520 return(0);
4521 }
Owen Taylor3473f882001-02-23 17:55:21 +00004522 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4523 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004524 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004525 for (j = 0;j < ns2->nodeNr;j++) {
4526 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004527 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004528 if (hashs1[i] != hashs2[j]) {
4529 if (neq) {
4530 ret = 1;
4531 break;
4532 }
4533 }
4534 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004535 if (values1[i] == NULL)
4536 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4537 if (values2[j] == NULL)
4538 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004539 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004540 if (ret)
4541 break;
4542 }
Owen Taylor3473f882001-02-23 17:55:21 +00004543 }
4544 if (ret)
4545 break;
4546 }
4547 for (i = 0;i < ns1->nodeNr;i++)
4548 if (values1[i] != NULL)
4549 xmlFree(values1[i]);
4550 for (j = 0;j < ns2->nodeNr;j++)
4551 if (values2[j] != NULL)
4552 xmlFree(values2[j]);
4553 xmlFree(values1);
4554 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004555 xmlFree(hashs1);
4556 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004557 return(ret);
4558}
4559
William M. Brack0c022ad2002-07-12 00:56:01 +00004560static int
4561xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4562 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004563 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004564 /*
4565 *At this point we are assured neither arg1 nor arg2
4566 *is a nodeset, so we can just pick the appropriate routine.
4567 */
Owen Taylor3473f882001-02-23 17:55:21 +00004568 switch (arg1->type) {
4569 case XPATH_UNDEFINED:
4570#ifdef DEBUG_EXPR
4571 xmlGenericError(xmlGenericErrorContext,
4572 "Equal: undefined\n");
4573#endif
4574 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004575 case XPATH_BOOLEAN:
4576 switch (arg2->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#ifdef DEBUG_EXPR
4585 xmlGenericError(xmlGenericErrorContext,
4586 "Equal: %d boolean %d \n",
4587 arg1->boolval, arg2->boolval);
4588#endif
4589 ret = (arg1->boolval == arg2->boolval);
4590 break;
4591 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004592 ret = (arg1->boolval ==
4593 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004594 break;
4595 case XPATH_STRING:
4596 if ((arg2->stringval == NULL) ||
4597 (arg2->stringval[0] == 0)) ret = 0;
4598 else
4599 ret = 1;
4600 ret = (arg1->boolval == ret);
4601 break;
4602 case XPATH_USERS:
4603 case XPATH_POINT:
4604 case XPATH_RANGE:
4605 case XPATH_LOCATIONSET:
4606 TODO
4607 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004608 case XPATH_NODESET:
4609 case XPATH_XSLT_TREE:
4610 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004611 }
4612 break;
4613 case XPATH_NUMBER:
4614 switch (arg2->type) {
4615 case XPATH_UNDEFINED:
4616#ifdef DEBUG_EXPR
4617 xmlGenericError(xmlGenericErrorContext,
4618 "Equal: undefined\n");
4619#endif
4620 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004621 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004622 ret = (arg2->boolval==
4623 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004624 break;
4625 case XPATH_STRING:
4626 valuePush(ctxt, arg2);
4627 xmlXPathNumberFunction(ctxt, 1);
4628 arg2 = valuePop(ctxt);
4629 /* no break on purpose */
4630 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004631 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004632 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4633 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004634 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4635 if (xmlXPathIsInf(arg2->floatval) == 1)
4636 ret = 1;
4637 else
4638 ret = 0;
4639 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4640 if (xmlXPathIsInf(arg2->floatval) == -1)
4641 ret = 1;
4642 else
4643 ret = 0;
4644 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4645 if (xmlXPathIsInf(arg1->floatval) == 1)
4646 ret = 1;
4647 else
4648 ret = 0;
4649 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4650 if (xmlXPathIsInf(arg1->floatval) == -1)
4651 ret = 1;
4652 else
4653 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004654 } else {
4655 ret = (arg1->floatval == arg2->floatval);
4656 }
Owen Taylor3473f882001-02-23 17:55:21 +00004657 break;
4658 case XPATH_USERS:
4659 case XPATH_POINT:
4660 case XPATH_RANGE:
4661 case XPATH_LOCATIONSET:
4662 TODO
4663 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004664 case XPATH_NODESET:
4665 case XPATH_XSLT_TREE:
4666 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004667 }
4668 break;
4669 case XPATH_STRING:
4670 switch (arg2->type) {
4671 case XPATH_UNDEFINED:
4672#ifdef DEBUG_EXPR
4673 xmlGenericError(xmlGenericErrorContext,
4674 "Equal: undefined\n");
4675#endif
4676 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004677 case XPATH_BOOLEAN:
4678 if ((arg1->stringval == NULL) ||
4679 (arg1->stringval[0] == 0)) ret = 0;
4680 else
4681 ret = 1;
4682 ret = (arg2->boolval == ret);
4683 break;
4684 case XPATH_STRING:
4685 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4686 break;
4687 case XPATH_NUMBER:
4688 valuePush(ctxt, arg1);
4689 xmlXPathNumberFunction(ctxt, 1);
4690 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004691 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004692 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4693 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004694 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4695 if (xmlXPathIsInf(arg2->floatval) == 1)
4696 ret = 1;
4697 else
4698 ret = 0;
4699 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4700 if (xmlXPathIsInf(arg2->floatval) == -1)
4701 ret = 1;
4702 else
4703 ret = 0;
4704 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4705 if (xmlXPathIsInf(arg1->floatval) == 1)
4706 ret = 1;
4707 else
4708 ret = 0;
4709 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4710 if (xmlXPathIsInf(arg1->floatval) == -1)
4711 ret = 1;
4712 else
4713 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004714 } else {
4715 ret = (arg1->floatval == arg2->floatval);
4716 }
Owen Taylor3473f882001-02-23 17:55:21 +00004717 break;
4718 case XPATH_USERS:
4719 case XPATH_POINT:
4720 case XPATH_RANGE:
4721 case XPATH_LOCATIONSET:
4722 TODO
4723 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004724 case XPATH_NODESET:
4725 case XPATH_XSLT_TREE:
4726 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004727 }
4728 break;
4729 case XPATH_USERS:
4730 case XPATH_POINT:
4731 case XPATH_RANGE:
4732 case XPATH_LOCATIONSET:
4733 TODO
4734 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004735 case XPATH_NODESET:
4736 case XPATH_XSLT_TREE:
4737 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004738 }
4739 xmlXPathFreeObject(arg1);
4740 xmlXPathFreeObject(arg2);
4741 return(ret);
4742}
4743
William M. Brack0c022ad2002-07-12 00:56:01 +00004744/**
4745 * xmlXPathEqualValues:
4746 * @ctxt: the XPath Parser context
4747 *
4748 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4749 *
4750 * Returns 0 or 1 depending on the results of the test.
4751 */
4752int
4753xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4754 xmlXPathObjectPtr arg1, arg2, argtmp;
4755 int ret = 0;
4756
4757 arg2 = valuePop(ctxt);
4758 arg1 = valuePop(ctxt);
4759 if ((arg1 == NULL) || (arg2 == NULL)) {
4760 if (arg1 != NULL)
4761 xmlXPathFreeObject(arg1);
4762 else
4763 xmlXPathFreeObject(arg2);
4764 XP_ERROR0(XPATH_INVALID_OPERAND);
4765 }
4766
4767 if (arg1 == arg2) {
4768#ifdef DEBUG_EXPR
4769 xmlGenericError(xmlGenericErrorContext,
4770 "Equal: by pointer\n");
4771#endif
4772 return(1);
4773 }
4774
4775 /*
4776 *If either argument is a nodeset, it's a 'special case'
4777 */
4778 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4779 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4780 /*
4781 *Hack it to assure arg1 is the nodeset
4782 */
4783 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4784 argtmp = arg2;
4785 arg2 = arg1;
4786 arg1 = argtmp;
4787 }
4788 switch (arg2->type) {
4789 case XPATH_UNDEFINED:
4790#ifdef DEBUG_EXPR
4791 xmlGenericError(xmlGenericErrorContext,
4792 "Equal: undefined\n");
4793#endif
4794 break;
4795 case XPATH_NODESET:
4796 case XPATH_XSLT_TREE:
4797 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4798 break;
4799 case XPATH_BOOLEAN:
4800 if ((arg1->nodesetval == NULL) ||
4801 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4802 else
4803 ret = 1;
4804 ret = (ret == arg2->boolval);
4805 break;
4806 case XPATH_NUMBER:
4807 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4808 break;
4809 case XPATH_STRING:
4810 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4811 break;
4812 case XPATH_USERS:
4813 case XPATH_POINT:
4814 case XPATH_RANGE:
4815 case XPATH_LOCATIONSET:
4816 TODO
4817 break;
4818 }
4819 xmlXPathFreeObject(arg1);
4820 xmlXPathFreeObject(arg2);
4821 return(ret);
4822 }
4823
4824 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4825}
4826
4827/**
4828 * xmlXPathNotEqualValues:
4829 * @ctxt: the XPath Parser context
4830 *
4831 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4832 *
4833 * Returns 0 or 1 depending on the results of the test.
4834 */
4835int
4836xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4837 xmlXPathObjectPtr arg1, arg2, argtmp;
4838 int ret = 0;
4839
4840 arg2 = valuePop(ctxt);
4841 arg1 = valuePop(ctxt);
4842 if ((arg1 == NULL) || (arg2 == NULL)) {
4843 if (arg1 != NULL)
4844 xmlXPathFreeObject(arg1);
4845 else
4846 xmlXPathFreeObject(arg2);
4847 XP_ERROR0(XPATH_INVALID_OPERAND);
4848 }
4849
4850 if (arg1 == arg2) {
4851#ifdef DEBUG_EXPR
4852 xmlGenericError(xmlGenericErrorContext,
4853 "NotEqual: by pointer\n");
4854#endif
4855 return(0);
4856 }
4857
4858 /*
4859 *If either argument is a nodeset, it's a 'special case'
4860 */
4861 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4862 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4863 /*
4864 *Hack it to assure arg1 is the nodeset
4865 */
4866 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4867 argtmp = arg2;
4868 arg2 = arg1;
4869 arg1 = argtmp;
4870 }
4871 switch (arg2->type) {
4872 case XPATH_UNDEFINED:
4873#ifdef DEBUG_EXPR
4874 xmlGenericError(xmlGenericErrorContext,
4875 "NotEqual: undefined\n");
4876#endif
4877 break;
4878 case XPATH_NODESET:
4879 case XPATH_XSLT_TREE:
4880 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4881 break;
4882 case XPATH_BOOLEAN:
4883 if ((arg1->nodesetval == NULL) ||
4884 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4885 else
4886 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004887 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004888 break;
4889 case XPATH_NUMBER:
4890 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4891 break;
4892 case XPATH_STRING:
4893 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4894 break;
4895 case XPATH_USERS:
4896 case XPATH_POINT:
4897 case XPATH_RANGE:
4898 case XPATH_LOCATIONSET:
4899 TODO
4900 break;
4901 }
4902 xmlXPathFreeObject(arg1);
4903 xmlXPathFreeObject(arg2);
4904 return(ret);
4905 }
4906
4907 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4908}
Owen Taylor3473f882001-02-23 17:55:21 +00004909
4910/**
4911 * xmlXPathCompareValues:
4912 * @ctxt: the XPath Parser context
4913 * @inf: less than (1) or greater than (0)
4914 * @strict: is the comparison strict
4915 *
4916 * Implement the compare operation on XPath objects:
4917 * @arg1 < @arg2 (1, 1, ...
4918 * @arg1 <= @arg2 (1, 0, ...
4919 * @arg1 > @arg2 (0, 1, ...
4920 * @arg1 >= @arg2 (0, 0, ...
4921 *
4922 * When neither object to be compared is a node-set and the operator is
4923 * <=, <, >=, >, then the objects are compared by converted both objects
4924 * to numbers and comparing the numbers according to IEEE 754. The <
4925 * comparison will be true if and only if the first number is less than the
4926 * second number. The <= comparison will be true if and only if the first
4927 * number is less than or equal to the second number. The > comparison
4928 * will be true if and only if the first number is greater than the second
4929 * number. The >= comparison will be true if and only if the first number
4930 * is greater than or equal to the second number.
4931 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004932 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004933 */
4934int
4935xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004936 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004937 xmlXPathObjectPtr arg1, arg2;
4938
William M. Brack0c022ad2002-07-12 00:56:01 +00004939 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004940 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004941 if ((arg1 == NULL) || (arg2 == NULL)) {
4942 if (arg1 != NULL)
4943 xmlXPathFreeObject(arg1);
4944 else
4945 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004946 XP_ERROR0(XPATH_INVALID_OPERAND);
4947 }
4948
William M. Brack0c022ad2002-07-12 00:56:01 +00004949 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4950 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4951 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4952 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004953 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004954 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004955 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004956 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4957 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004958 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004959 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4960 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004961 }
4962 }
4963 return(ret);
4964 }
4965
4966 if (arg1->type != XPATH_NUMBER) {
4967 valuePush(ctxt, arg1);
4968 xmlXPathNumberFunction(ctxt, 1);
4969 arg1 = valuePop(ctxt);
4970 }
4971 if (arg1->type != XPATH_NUMBER) {
4972 xmlXPathFreeObject(arg1);
4973 xmlXPathFreeObject(arg2);
4974 XP_ERROR0(XPATH_INVALID_OPERAND);
4975 }
4976 if (arg2->type != XPATH_NUMBER) {
4977 valuePush(ctxt, arg2);
4978 xmlXPathNumberFunction(ctxt, 1);
4979 arg2 = valuePop(ctxt);
4980 }
4981 if (arg2->type != XPATH_NUMBER) {
4982 xmlXPathFreeObject(arg1);
4983 xmlXPathFreeObject(arg2);
4984 XP_ERROR0(XPATH_INVALID_OPERAND);
4985 }
4986 /*
4987 * Add tests for infinity and nan
4988 * => feedback on 3.4 for Inf and NaN
4989 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004990 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004991 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004992 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004993 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004994 arg1i=xmlXPathIsInf(arg1->floatval);
4995 arg2i=xmlXPathIsInf(arg2->floatval);
4996 if (inf && strict) {
4997 if ((arg1i == -1 && arg2i != -1) ||
4998 (arg2i == 1 && arg1i != 1)) {
4999 ret = 1;
5000 } else if (arg1i == 0 && arg2i == 0) {
5001 ret = (arg1->floatval < arg2->floatval);
5002 } else {
5003 ret = 0;
5004 }
5005 }
5006 else if (inf && !strict) {
5007 if (arg1i == -1 || arg2i == 1) {
5008 ret = 1;
5009 } else if (arg1i == 0 && arg2i == 0) {
5010 ret = (arg1->floatval <= arg2->floatval);
5011 } else {
5012 ret = 0;
5013 }
5014 }
5015 else if (!inf && strict) {
5016 if ((arg1i == 1 && arg2i != 1) ||
5017 (arg2i == -1 && arg1i != -1)) {
5018 ret = 1;
5019 } else if (arg1i == 0 && arg2i == 0) {
5020 ret = (arg1->floatval > arg2->floatval);
5021 } else {
5022 ret = 0;
5023 }
5024 }
5025 else if (!inf && !strict) {
5026 if (arg1i == 1 || arg2i == -1) {
5027 ret = 1;
5028 } else if (arg1i == 0 && arg2i == 0) {
5029 ret = (arg1->floatval >= arg2->floatval);
5030 } else {
5031 ret = 0;
5032 }
5033 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005034 }
Owen Taylor3473f882001-02-23 17:55:21 +00005035 xmlXPathFreeObject(arg1);
5036 xmlXPathFreeObject(arg2);
5037 return(ret);
5038}
5039
5040/**
5041 * xmlXPathValueFlipSign:
5042 * @ctxt: the XPath Parser context
5043 *
5044 * Implement the unary - operation on an XPath object
5045 * The numeric operators convert their operands to numbers as if
5046 * by calling the number function.
5047 */
5048void
5049xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005050 CAST_TO_NUMBER;
5051 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005052 if (xmlXPathIsNaN(ctxt->value->floatval))
5053 ctxt->value->floatval=xmlXPathNAN;
5054 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5055 ctxt->value->floatval=xmlXPathNINF;
5056 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5057 ctxt->value->floatval=xmlXPathPINF;
5058 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005059 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5060 ctxt->value->floatval = xmlXPathNZERO;
5061 else
5062 ctxt->value->floatval = 0;
5063 }
5064 else
5065 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005066}
5067
5068/**
5069 * xmlXPathAddValues:
5070 * @ctxt: the XPath Parser context
5071 *
5072 * Implement the add operation on XPath objects:
5073 * The numeric operators convert their operands to numbers as if
5074 * by calling the number function.
5075 */
5076void
5077xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5078 xmlXPathObjectPtr arg;
5079 double val;
5080
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005081 arg = valuePop(ctxt);
5082 if (arg == NULL)
5083 XP_ERROR(XPATH_INVALID_OPERAND);
5084 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005085 xmlXPathFreeObject(arg);
5086
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005087 CAST_TO_NUMBER;
5088 CHECK_TYPE(XPATH_NUMBER);
5089 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005090}
5091
5092/**
5093 * xmlXPathSubValues:
5094 * @ctxt: the XPath Parser context
5095 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005096 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005097 * The numeric operators convert their operands to numbers as if
5098 * by calling the number function.
5099 */
5100void
5101xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5102 xmlXPathObjectPtr arg;
5103 double val;
5104
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005105 arg = valuePop(ctxt);
5106 if (arg == NULL)
5107 XP_ERROR(XPATH_INVALID_OPERAND);
5108 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005109 xmlXPathFreeObject(arg);
5110
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005111 CAST_TO_NUMBER;
5112 CHECK_TYPE(XPATH_NUMBER);
5113 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005114}
5115
5116/**
5117 * xmlXPathMultValues:
5118 * @ctxt: the XPath Parser context
5119 *
5120 * Implement the multiply operation on XPath objects:
5121 * The numeric operators convert their operands to numbers as if
5122 * by calling the number function.
5123 */
5124void
5125xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5126 xmlXPathObjectPtr arg;
5127 double val;
5128
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005129 arg = valuePop(ctxt);
5130 if (arg == NULL)
5131 XP_ERROR(XPATH_INVALID_OPERAND);
5132 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005133 xmlXPathFreeObject(arg);
5134
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005135 CAST_TO_NUMBER;
5136 CHECK_TYPE(XPATH_NUMBER);
5137 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005138}
5139
5140/**
5141 * xmlXPathDivValues:
5142 * @ctxt: the XPath Parser context
5143 *
5144 * Implement the div operation on XPath objects @arg1 / @arg2:
5145 * The numeric operators convert their operands to numbers as if
5146 * by calling the number function.
5147 */
5148void
5149xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5150 xmlXPathObjectPtr arg;
5151 double val;
5152
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005153 arg = valuePop(ctxt);
5154 if (arg == NULL)
5155 XP_ERROR(XPATH_INVALID_OPERAND);
5156 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005157 xmlXPathFreeObject(arg);
5158
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005159 CAST_TO_NUMBER;
5160 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005161 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5162 ctxt->value->floatval = xmlXPathNAN;
5163 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005164 if (ctxt->value->floatval == 0)
5165 ctxt->value->floatval = xmlXPathNAN;
5166 else if (ctxt->value->floatval > 0)
5167 ctxt->value->floatval = xmlXPathNINF;
5168 else if (ctxt->value->floatval < 0)
5169 ctxt->value->floatval = xmlXPathPINF;
5170 }
5171 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005172 if (ctxt->value->floatval == 0)
5173 ctxt->value->floatval = xmlXPathNAN;
5174 else if (ctxt->value->floatval > 0)
5175 ctxt->value->floatval = xmlXPathPINF;
5176 else if (ctxt->value->floatval < 0)
5177 ctxt->value->floatval = xmlXPathNINF;
5178 } else
5179 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005180}
5181
5182/**
5183 * xmlXPathModValues:
5184 * @ctxt: the XPath Parser context
5185 *
5186 * Implement the mod operation on XPath objects: @arg1 / @arg2
5187 * The numeric operators convert their operands to numbers as if
5188 * by calling the number function.
5189 */
5190void
5191xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5192 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005193 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005194
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005195 arg = valuePop(ctxt);
5196 if (arg == NULL)
5197 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005198 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005199 xmlXPathFreeObject(arg);
5200
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005201 CAST_TO_NUMBER;
5202 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005203 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005204 if (arg2 == 0)
5205 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005206 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005207 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005208 }
Owen Taylor3473f882001-02-23 17:55:21 +00005209}
5210
5211/************************************************************************
5212 * *
5213 * The traversal functions *
5214 * *
5215 ************************************************************************/
5216
Owen Taylor3473f882001-02-23 17:55:21 +00005217/*
5218 * A traversal function enumerates nodes along an axis.
5219 * Initially it must be called with NULL, and it indicates
5220 * termination on the axis by returning NULL.
5221 */
5222typedef xmlNodePtr (*xmlXPathTraversalFunction)
5223 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5224
5225/**
5226 * xmlXPathNextSelf:
5227 * @ctxt: the XPath Parser context
5228 * @cur: the current node in the traversal
5229 *
5230 * Traversal function for the "self" direction
5231 * The self axis contains just the context node itself
5232 *
5233 * Returns the next element following that axis
5234 */
5235xmlNodePtr
5236xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5237 if (cur == NULL)
5238 return(ctxt->context->node);
5239 return(NULL);
5240}
5241
5242/**
5243 * xmlXPathNextChild:
5244 * @ctxt: the XPath Parser context
5245 * @cur: the current node in the traversal
5246 *
5247 * Traversal function for the "child" direction
5248 * The child axis contains the children of the context node in document order.
5249 *
5250 * Returns the next element following that axis
5251 */
5252xmlNodePtr
5253xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5254 if (cur == NULL) {
5255 if (ctxt->context->node == NULL) return(NULL);
5256 switch (ctxt->context->node->type) {
5257 case XML_ELEMENT_NODE:
5258 case XML_TEXT_NODE:
5259 case XML_CDATA_SECTION_NODE:
5260 case XML_ENTITY_REF_NODE:
5261 case XML_ENTITY_NODE:
5262 case XML_PI_NODE:
5263 case XML_COMMENT_NODE:
5264 case XML_NOTATION_NODE:
5265 case XML_DTD_NODE:
5266 return(ctxt->context->node->children);
5267 case XML_DOCUMENT_NODE:
5268 case XML_DOCUMENT_TYPE_NODE:
5269 case XML_DOCUMENT_FRAG_NODE:
5270 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005271#ifdef LIBXML_DOCB_ENABLED
5272 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005273#endif
5274 return(((xmlDocPtr) ctxt->context->node)->children);
5275 case XML_ELEMENT_DECL:
5276 case XML_ATTRIBUTE_DECL:
5277 case XML_ENTITY_DECL:
5278 case XML_ATTRIBUTE_NODE:
5279 case XML_NAMESPACE_DECL:
5280 case XML_XINCLUDE_START:
5281 case XML_XINCLUDE_END:
5282 return(NULL);
5283 }
5284 return(NULL);
5285 }
5286 if ((cur->type == XML_DOCUMENT_NODE) ||
5287 (cur->type == XML_HTML_DOCUMENT_NODE))
5288 return(NULL);
5289 return(cur->next);
5290}
5291
5292/**
5293 * xmlXPathNextDescendant:
5294 * @ctxt: the XPath Parser context
5295 * @cur: the current node in the traversal
5296 *
5297 * Traversal function for the "descendant" direction
5298 * the descendant axis contains the descendants of the context node in document
5299 * order; a descendant is a child or a child of a child and so on.
5300 *
5301 * Returns the next element following that axis
5302 */
5303xmlNodePtr
5304xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5305 if (cur == NULL) {
5306 if (ctxt->context->node == NULL)
5307 return(NULL);
5308 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5309 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5310 return(NULL);
5311
5312 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5313 return(ctxt->context->doc->children);
5314 return(ctxt->context->node->children);
5315 }
5316
Daniel Veillard567e1b42001-08-01 15:53:47 +00005317 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005318 /*
5319 * Do not descend on entities declarations
5320 */
5321 if (cur->children->type != XML_ENTITY_DECL) {
5322 cur = cur->children;
5323 /*
5324 * Skip DTDs
5325 */
5326 if (cur->type != XML_DTD_NODE)
5327 return(cur);
5328 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005329 }
5330
5331 if (cur == ctxt->context->node) return(NULL);
5332
Daniel Veillard68e9e742002-11-16 15:35:11 +00005333 while (cur->next != NULL) {
5334 cur = cur->next;
5335 if ((cur->type != XML_ENTITY_DECL) &&
5336 (cur->type != XML_DTD_NODE))
5337 return(cur);
5338 }
Owen Taylor3473f882001-02-23 17:55:21 +00005339
5340 do {
5341 cur = cur->parent;
5342 if (cur == NULL) return(NULL);
5343 if (cur == ctxt->context->node) return(NULL);
5344 if (cur->next != NULL) {
5345 cur = cur->next;
5346 return(cur);
5347 }
5348 } while (cur != NULL);
5349 return(cur);
5350}
5351
5352/**
5353 * xmlXPathNextDescendantOrSelf:
5354 * @ctxt: the XPath Parser context
5355 * @cur: the current node in the traversal
5356 *
5357 * Traversal function for the "descendant-or-self" direction
5358 * the descendant-or-self axis contains the context node and the descendants
5359 * of the context node in document order; thus the context node is the first
5360 * node on the axis, and the first child of the context node is the second node
5361 * on the axis
5362 *
5363 * Returns the next element following that axis
5364 */
5365xmlNodePtr
5366xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5367 if (cur == NULL) {
5368 if (ctxt->context->node == NULL)
5369 return(NULL);
5370 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5371 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5372 return(NULL);
5373 return(ctxt->context->node);
5374 }
5375
5376 return(xmlXPathNextDescendant(ctxt, cur));
5377}
5378
5379/**
5380 * xmlXPathNextParent:
5381 * @ctxt: the XPath Parser context
5382 * @cur: the current node in the traversal
5383 *
5384 * Traversal function for the "parent" direction
5385 * The parent axis contains the parent of the context node, if there is one.
5386 *
5387 * Returns the next element following that axis
5388 */
5389xmlNodePtr
5390xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5391 /*
5392 * the parent of an attribute or namespace node is the element
5393 * to which the attribute or namespace node is attached
5394 * Namespace handling !!!
5395 */
5396 if (cur == NULL) {
5397 if (ctxt->context->node == NULL) return(NULL);
5398 switch (ctxt->context->node->type) {
5399 case XML_ELEMENT_NODE:
5400 case XML_TEXT_NODE:
5401 case XML_CDATA_SECTION_NODE:
5402 case XML_ENTITY_REF_NODE:
5403 case XML_ENTITY_NODE:
5404 case XML_PI_NODE:
5405 case XML_COMMENT_NODE:
5406 case XML_NOTATION_NODE:
5407 case XML_DTD_NODE:
5408 case XML_ELEMENT_DECL:
5409 case XML_ATTRIBUTE_DECL:
5410 case XML_XINCLUDE_START:
5411 case XML_XINCLUDE_END:
5412 case XML_ENTITY_DECL:
5413 if (ctxt->context->node->parent == NULL)
5414 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005415 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005416 ((ctxt->context->node->parent->name[0] == ' ') ||
5417 (xmlStrEqual(ctxt->context->node->parent->name,
5418 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005419 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005420 return(ctxt->context->node->parent);
5421 case XML_ATTRIBUTE_NODE: {
5422 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5423
5424 return(att->parent);
5425 }
5426 case XML_DOCUMENT_NODE:
5427 case XML_DOCUMENT_TYPE_NODE:
5428 case XML_DOCUMENT_FRAG_NODE:
5429 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005430#ifdef LIBXML_DOCB_ENABLED
5431 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005432#endif
5433 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005434 case XML_NAMESPACE_DECL: {
5435 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5436
5437 if ((ns->next != NULL) &&
5438 (ns->next->type != XML_NAMESPACE_DECL))
5439 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005440 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005441 }
Owen Taylor3473f882001-02-23 17:55:21 +00005442 }
5443 }
5444 return(NULL);
5445}
5446
5447/**
5448 * xmlXPathNextAncestor:
5449 * @ctxt: the XPath Parser context
5450 * @cur: the current node in the traversal
5451 *
5452 * Traversal function for the "ancestor" direction
5453 * the ancestor axis contains the ancestors of the context node; the ancestors
5454 * of the context node consist of the parent of context node and the parent's
5455 * parent and so on; the nodes are ordered in reverse document order; thus the
5456 * parent is the first node on the axis, and the parent's parent is the second
5457 * node on the axis
5458 *
5459 * Returns the next element following that axis
5460 */
5461xmlNodePtr
5462xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5463 /*
5464 * the parent of an attribute or namespace node is the element
5465 * to which the attribute or namespace node is attached
5466 * !!!!!!!!!!!!!
5467 */
5468 if (cur == NULL) {
5469 if (ctxt->context->node == NULL) return(NULL);
5470 switch (ctxt->context->node->type) {
5471 case XML_ELEMENT_NODE:
5472 case XML_TEXT_NODE:
5473 case XML_CDATA_SECTION_NODE:
5474 case XML_ENTITY_REF_NODE:
5475 case XML_ENTITY_NODE:
5476 case XML_PI_NODE:
5477 case XML_COMMENT_NODE:
5478 case XML_DTD_NODE:
5479 case XML_ELEMENT_DECL:
5480 case XML_ATTRIBUTE_DECL:
5481 case XML_ENTITY_DECL:
5482 case XML_NOTATION_NODE:
5483 case XML_XINCLUDE_START:
5484 case XML_XINCLUDE_END:
5485 if (ctxt->context->node->parent == NULL)
5486 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005487 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005488 ((ctxt->context->node->parent->name[0] == ' ') ||
5489 (xmlStrEqual(ctxt->context->node->parent->name,
5490 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005491 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005492 return(ctxt->context->node->parent);
5493 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005494 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005495
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005496 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005497 }
5498 case XML_DOCUMENT_NODE:
5499 case XML_DOCUMENT_TYPE_NODE:
5500 case XML_DOCUMENT_FRAG_NODE:
5501 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005502#ifdef LIBXML_DOCB_ENABLED
5503 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005504#endif
5505 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005506 case XML_NAMESPACE_DECL: {
5507 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5508
5509 if ((ns->next != NULL) &&
5510 (ns->next->type != XML_NAMESPACE_DECL))
5511 return((xmlNodePtr) ns->next);
5512 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005513 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005514 }
Owen Taylor3473f882001-02-23 17:55:21 +00005515 }
5516 return(NULL);
5517 }
5518 if (cur == ctxt->context->doc->children)
5519 return((xmlNodePtr) ctxt->context->doc);
5520 if (cur == (xmlNodePtr) ctxt->context->doc)
5521 return(NULL);
5522 switch (cur->type) {
5523 case XML_ELEMENT_NODE:
5524 case XML_TEXT_NODE:
5525 case XML_CDATA_SECTION_NODE:
5526 case XML_ENTITY_REF_NODE:
5527 case XML_ENTITY_NODE:
5528 case XML_PI_NODE:
5529 case XML_COMMENT_NODE:
5530 case XML_NOTATION_NODE:
5531 case XML_DTD_NODE:
5532 case XML_ELEMENT_DECL:
5533 case XML_ATTRIBUTE_DECL:
5534 case XML_ENTITY_DECL:
5535 case XML_XINCLUDE_START:
5536 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005537 if (cur->parent == NULL)
5538 return(NULL);
5539 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005540 ((cur->parent->name[0] == ' ') ||
5541 (xmlStrEqual(cur->parent->name,
5542 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005543 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005544 return(cur->parent);
5545 case XML_ATTRIBUTE_NODE: {
5546 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5547
5548 return(att->parent);
5549 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005550 case XML_NAMESPACE_DECL: {
5551 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5552
5553 if ((ns->next != NULL) &&
5554 (ns->next->type != XML_NAMESPACE_DECL))
5555 return((xmlNodePtr) ns->next);
5556 /* Bad, how did that namespace ended-up there ? */
5557 return(NULL);
5558 }
Owen Taylor3473f882001-02-23 17:55:21 +00005559 case XML_DOCUMENT_NODE:
5560 case XML_DOCUMENT_TYPE_NODE:
5561 case XML_DOCUMENT_FRAG_NODE:
5562 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005563#ifdef LIBXML_DOCB_ENABLED
5564 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005565#endif
5566 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005567 }
5568 return(NULL);
5569}
5570
5571/**
5572 * xmlXPathNextAncestorOrSelf:
5573 * @ctxt: the XPath Parser context
5574 * @cur: the current node in the traversal
5575 *
5576 * Traversal function for the "ancestor-or-self" direction
5577 * he ancestor-or-self axis contains the context node and ancestors of
5578 * the context node in reverse document order; thus the context node is
5579 * the first node on the axis, and the context node's parent the second;
5580 * parent here is defined the same as with the parent axis.
5581 *
5582 * Returns the next element following that axis
5583 */
5584xmlNodePtr
5585xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5586 if (cur == NULL)
5587 return(ctxt->context->node);
5588 return(xmlXPathNextAncestor(ctxt, cur));
5589}
5590
5591/**
5592 * xmlXPathNextFollowingSibling:
5593 * @ctxt: the XPath Parser context
5594 * @cur: the current node in the traversal
5595 *
5596 * Traversal function for the "following-sibling" direction
5597 * The following-sibling axis contains the following siblings of the context
5598 * node in document order.
5599 *
5600 * Returns the next element following that axis
5601 */
5602xmlNodePtr
5603xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5604 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5605 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5606 return(NULL);
5607 if (cur == (xmlNodePtr) ctxt->context->doc)
5608 return(NULL);
5609 if (cur == NULL)
5610 return(ctxt->context->node->next);
5611 return(cur->next);
5612}
5613
5614/**
5615 * xmlXPathNextPrecedingSibling:
5616 * @ctxt: the XPath Parser context
5617 * @cur: the current node in the traversal
5618 *
5619 * Traversal function for the "preceding-sibling" direction
5620 * The preceding-sibling axis contains the preceding siblings of the context
5621 * node in reverse document order; the first preceding sibling is first on the
5622 * axis; the sibling preceding that node is the second on the axis and so on.
5623 *
5624 * Returns the next element following that axis
5625 */
5626xmlNodePtr
5627xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5628 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5629 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5630 return(NULL);
5631 if (cur == (xmlNodePtr) ctxt->context->doc)
5632 return(NULL);
5633 if (cur == NULL)
5634 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005635 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5636 cur = cur->prev;
5637 if (cur == NULL)
5638 return(ctxt->context->node->prev);
5639 }
Owen Taylor3473f882001-02-23 17:55:21 +00005640 return(cur->prev);
5641}
5642
5643/**
5644 * xmlXPathNextFollowing:
5645 * @ctxt: the XPath Parser context
5646 * @cur: the current node in the traversal
5647 *
5648 * Traversal function for the "following" direction
5649 * The following axis contains all nodes in the same document as the context
5650 * node that are after the context node in document order, excluding any
5651 * descendants and excluding attribute nodes and namespace nodes; the nodes
5652 * are ordered in document order
5653 *
5654 * Returns the next element following that axis
5655 */
5656xmlNodePtr
5657xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5658 if (cur != NULL && cur->children != NULL)
5659 return cur->children ;
5660 if (cur == NULL) cur = ctxt->context->node;
5661 if (cur == NULL) return(NULL) ; /* ERROR */
5662 if (cur->next != NULL) return(cur->next) ;
5663 do {
5664 cur = cur->parent;
5665 if (cur == NULL) return(NULL);
5666 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5667 if (cur->next != NULL) return(cur->next);
5668 } while (cur != NULL);
5669 return(cur);
5670}
5671
5672/*
5673 * xmlXPathIsAncestor:
5674 * @ancestor: the ancestor node
5675 * @node: the current node
5676 *
5677 * Check that @ancestor is a @node's ancestor
5678 *
5679 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5680 */
5681static int
5682xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5683 if ((ancestor == NULL) || (node == NULL)) return(0);
5684 /* nodes need to be in the same document */
5685 if (ancestor->doc != node->doc) return(0);
5686 /* avoid searching if ancestor or node is the root node */
5687 if (ancestor == (xmlNodePtr) node->doc) return(1);
5688 if (node == (xmlNodePtr) ancestor->doc) return(0);
5689 while (node->parent != NULL) {
5690 if (node->parent == ancestor)
5691 return(1);
5692 node = node->parent;
5693 }
5694 return(0);
5695}
5696
5697/**
5698 * xmlXPathNextPreceding:
5699 * @ctxt: the XPath Parser context
5700 * @cur: the current node in the traversal
5701 *
5702 * Traversal function for the "preceding" direction
5703 * the preceding axis contains all nodes in the same document as the context
5704 * node that are before the context node in document order, excluding any
5705 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5706 * ordered in reverse document order
5707 *
5708 * Returns the next element following that axis
5709 */
5710xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005711xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5712{
Owen Taylor3473f882001-02-23 17:55:21 +00005713 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005714 cur = ctxt->context->node;
5715 if (cur == NULL)
5716 return (NULL);
5717 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5718 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005719 do {
5720 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005721 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5722 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005723 }
5724
5725 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005726 if (cur == NULL)
5727 return (NULL);
5728 if (cur == ctxt->context->doc->children)
5729 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005730 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005731 return (cur);
5732}
5733
5734/**
5735 * xmlXPathNextPrecedingInternal:
5736 * @ctxt: the XPath Parser context
5737 * @cur: the current node in the traversal
5738 *
5739 * Traversal function for the "preceding" direction
5740 * the preceding axis contains all nodes in the same document as the context
5741 * node that are before the context node in document order, excluding any
5742 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5743 * ordered in reverse document order
5744 * This is a faster implementation but internal only since it requires a
5745 * state kept in the parser context: ctxt->ancestor.
5746 *
5747 * Returns the next element following that axis
5748 */
5749static xmlNodePtr
5750xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5751 xmlNodePtr cur)
5752{
5753 if (cur == NULL) {
5754 cur = ctxt->context->node;
5755 if (cur == NULL)
5756 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005757 if (cur->type == XML_NAMESPACE_DECL)
5758 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005759 ctxt->ancestor = cur->parent;
5760 }
5761 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5762 cur = cur->prev;
5763 while (cur->prev == NULL) {
5764 cur = cur->parent;
5765 if (cur == NULL)
5766 return (NULL);
5767 if (cur == ctxt->context->doc->children)
5768 return (NULL);
5769 if (cur != ctxt->ancestor)
5770 return (cur);
5771 ctxt->ancestor = cur->parent;
5772 }
5773 cur = cur->prev;
5774 while (cur->last != NULL)
5775 cur = cur->last;
5776 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005777}
5778
5779/**
5780 * xmlXPathNextNamespace:
5781 * @ctxt: the XPath Parser context
5782 * @cur: the current attribute in the traversal
5783 *
5784 * Traversal function for the "namespace" direction
5785 * the namespace axis contains the namespace nodes of the context node;
5786 * the order of nodes on this axis is implementation-defined; the axis will
5787 * be empty unless the context node is an element
5788 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005789 * We keep the XML namespace node at the end of the list.
5790 *
Owen Taylor3473f882001-02-23 17:55:21 +00005791 * Returns the next element following that axis
5792 */
5793xmlNodePtr
5794xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5795 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005796 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005797 if (ctxt->context->tmpNsList != NULL)
5798 xmlFree(ctxt->context->tmpNsList);
5799 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005800 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005801 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005802 if (ctxt->context->tmpNsList != NULL) {
5803 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5804 ctxt->context->tmpNsNr++;
5805 }
5806 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005807 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005808 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005809 if (ctxt->context->tmpNsNr > 0) {
5810 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5811 } else {
5812 if (ctxt->context->tmpNsList != NULL)
5813 xmlFree(ctxt->context->tmpNsList);
5814 ctxt->context->tmpNsList = NULL;
5815 return(NULL);
5816 }
Owen Taylor3473f882001-02-23 17:55:21 +00005817}
5818
5819/**
5820 * xmlXPathNextAttribute:
5821 * @ctxt: the XPath Parser context
5822 * @cur: the current attribute in the traversal
5823 *
5824 * Traversal function for the "attribute" direction
5825 * TODO: support DTD inherited default attributes
5826 *
5827 * Returns the next element following that axis
5828 */
5829xmlNodePtr
5830xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005831 if (ctxt->context->node == NULL)
5832 return(NULL);
5833 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5834 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005835 if (cur == NULL) {
5836 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5837 return(NULL);
5838 return((xmlNodePtr)ctxt->context->node->properties);
5839 }
5840 return((xmlNodePtr)cur->next);
5841}
5842
5843/************************************************************************
5844 * *
5845 * NodeTest Functions *
5846 * *
5847 ************************************************************************/
5848
Owen Taylor3473f882001-02-23 17:55:21 +00005849#define IS_FUNCTION 200
5850
Owen Taylor3473f882001-02-23 17:55:21 +00005851
5852/************************************************************************
5853 * *
5854 * Implicit tree core function library *
5855 * *
5856 ************************************************************************/
5857
5858/**
5859 * xmlXPathRoot:
5860 * @ctxt: the XPath Parser context
5861 *
5862 * Initialize the context to the root of the document
5863 */
5864void
5865xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5866 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5867 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5868}
5869
5870/************************************************************************
5871 * *
5872 * The explicit core function library *
5873 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5874 * *
5875 ************************************************************************/
5876
5877
5878/**
5879 * xmlXPathLastFunction:
5880 * @ctxt: the XPath Parser context
5881 * @nargs: the number of arguments
5882 *
5883 * Implement the last() XPath function
5884 * number last()
5885 * The last function returns the number of nodes in the context node list.
5886 */
5887void
5888xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5889 CHECK_ARITY(0);
5890 if (ctxt->context->contextSize >= 0) {
5891 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5892#ifdef DEBUG_EXPR
5893 xmlGenericError(xmlGenericErrorContext,
5894 "last() : %d\n", ctxt->context->contextSize);
5895#endif
5896 } else {
5897 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5898 }
5899}
5900
5901/**
5902 * xmlXPathPositionFunction:
5903 * @ctxt: the XPath Parser context
5904 * @nargs: the number of arguments
5905 *
5906 * Implement the position() XPath function
5907 * number position()
5908 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005909 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005910 * will be equal to last().
5911 */
5912void
5913xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5914 CHECK_ARITY(0);
5915 if (ctxt->context->proximityPosition >= 0) {
5916 valuePush(ctxt,
5917 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5918#ifdef DEBUG_EXPR
5919 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5920 ctxt->context->proximityPosition);
5921#endif
5922 } else {
5923 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5924 }
5925}
5926
5927/**
5928 * xmlXPathCountFunction:
5929 * @ctxt: the XPath Parser context
5930 * @nargs: the number of arguments
5931 *
5932 * Implement the count() XPath function
5933 * number count(node-set)
5934 */
5935void
5936xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5937 xmlXPathObjectPtr cur;
5938
5939 CHECK_ARITY(1);
5940 if ((ctxt->value == NULL) ||
5941 ((ctxt->value->type != XPATH_NODESET) &&
5942 (ctxt->value->type != XPATH_XSLT_TREE)))
5943 XP_ERROR(XPATH_INVALID_TYPE);
5944 cur = valuePop(ctxt);
5945
Daniel Veillard911f49a2001-04-07 15:39:35 +00005946 if ((cur == NULL) || (cur->nodesetval == NULL))
5947 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005948 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005949 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005950 } else {
5951 if ((cur->nodesetval->nodeNr != 1) ||
5952 (cur->nodesetval->nodeTab == NULL)) {
5953 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5954 } else {
5955 xmlNodePtr tmp;
5956 int i = 0;
5957
5958 tmp = cur->nodesetval->nodeTab[0];
5959 if (tmp != NULL) {
5960 tmp = tmp->children;
5961 while (tmp != NULL) {
5962 tmp = tmp->next;
5963 i++;
5964 }
5965 }
5966 valuePush(ctxt, xmlXPathNewFloat((double) i));
5967 }
5968 }
Owen Taylor3473f882001-02-23 17:55:21 +00005969 xmlXPathFreeObject(cur);
5970}
5971
5972/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005973 * xmlXPathGetElementsByIds:
5974 * @doc: the document
5975 * @ids: a whitespace separated list of IDs
5976 *
5977 * Selects elements by their unique ID.
5978 *
5979 * Returns a node-set of selected elements.
5980 */
5981static xmlNodeSetPtr
5982xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5983 xmlNodeSetPtr ret;
5984 const xmlChar *cur = ids;
5985 xmlChar *ID;
5986 xmlAttrPtr attr;
5987 xmlNodePtr elem = NULL;
5988
Daniel Veillard7a985a12003-07-06 17:57:42 +00005989 if (ids == NULL) return(NULL);
5990
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005991 ret = xmlXPathNodeSetCreate(NULL);
5992
William M. Brack76e95df2003-10-18 16:20:14 +00005993 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005994 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00005995 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00005996 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005997
5998 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00005999 if (ID != NULL) {
6000 if (xmlValidateNCName(ID, 1) == 0) {
6001 attr = xmlGetID(doc, ID);
6002 if (attr != NULL) {
6003 if (attr->type == XML_ATTRIBUTE_NODE)
6004 elem = attr->parent;
6005 else if (attr->type == XML_ELEMENT_NODE)
6006 elem = (xmlNodePtr) attr;
6007 else
6008 elem = NULL;
6009 if (elem != NULL)
6010 xmlXPathNodeSetAdd(ret, elem);
6011 }
6012 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006013 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006014 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006015
William M. Brack76e95df2003-10-18 16:20:14 +00006016 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006017 ids = cur;
6018 }
6019 return(ret);
6020}
6021
6022/**
Owen Taylor3473f882001-02-23 17:55:21 +00006023 * xmlXPathIdFunction:
6024 * @ctxt: the XPath Parser context
6025 * @nargs: the number of arguments
6026 *
6027 * Implement the id() XPath function
6028 * node-set id(object)
6029 * The id function selects elements by their unique ID
6030 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6031 * then the result is the union of the result of applying id to the
6032 * string value of each of the nodes in the argument node-set. When the
6033 * argument to id is of any other type, the argument is converted to a
6034 * string as if by a call to the string function; the string is split
6035 * into a whitespace-separated list of tokens (whitespace is any sequence
6036 * of characters matching the production S); the result is a node-set
6037 * containing the elements in the same document as the context node that
6038 * have a unique ID equal to any of the tokens in the list.
6039 */
6040void
6041xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006042 xmlChar *tokens;
6043 xmlNodeSetPtr ret;
6044 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006045
6046 CHECK_ARITY(1);
6047 obj = valuePop(ctxt);
6048 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006049 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006050 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006051 int i;
6052
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006053 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006054
Daniel Veillard911f49a2001-04-07 15:39:35 +00006055 if (obj->nodesetval != NULL) {
6056 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006057 tokens =
6058 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6059 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6060 ret = xmlXPathNodeSetMerge(ret, ns);
6061 xmlXPathFreeNodeSet(ns);
6062 if (tokens != NULL)
6063 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006064 }
Owen Taylor3473f882001-02-23 17:55:21 +00006065 }
6066
6067 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006068 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006069 return;
6070 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006071 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006072
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006073 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6074 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006075
Owen Taylor3473f882001-02-23 17:55:21 +00006076 xmlXPathFreeObject(obj);
6077 return;
6078}
6079
6080/**
6081 * xmlXPathLocalNameFunction:
6082 * @ctxt: the XPath Parser context
6083 * @nargs: the number of arguments
6084 *
6085 * Implement the local-name() XPath function
6086 * string local-name(node-set?)
6087 * The local-name function returns a string containing the local part
6088 * of the name of the node in the argument node-set that is first in
6089 * document order. If the node-set is empty or the first node has no
6090 * name, an empty string is returned. If the argument is omitted it
6091 * defaults to the context node.
6092 */
6093void
6094xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6095 xmlXPathObjectPtr cur;
6096
6097 if (nargs == 0) {
6098 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6099 nargs = 1;
6100 }
6101
6102 CHECK_ARITY(1);
6103 if ((ctxt->value == NULL) ||
6104 ((ctxt->value->type != XPATH_NODESET) &&
6105 (ctxt->value->type != XPATH_XSLT_TREE)))
6106 XP_ERROR(XPATH_INVALID_TYPE);
6107 cur = valuePop(ctxt);
6108
Daniel Veillard911f49a2001-04-07 15:39:35 +00006109 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006110 valuePush(ctxt, xmlXPathNewCString(""));
6111 } else {
6112 int i = 0; /* Should be first in document order !!!!! */
6113 switch (cur->nodesetval->nodeTab[i]->type) {
6114 case XML_ELEMENT_NODE:
6115 case XML_ATTRIBUTE_NODE:
6116 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006117 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6118 valuePush(ctxt, xmlXPathNewCString(""));
6119 else
6120 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006121 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6122 break;
6123 case XML_NAMESPACE_DECL:
6124 valuePush(ctxt, xmlXPathNewString(
6125 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6126 break;
6127 default:
6128 valuePush(ctxt, xmlXPathNewCString(""));
6129 }
6130 }
6131 xmlXPathFreeObject(cur);
6132}
6133
6134/**
6135 * xmlXPathNamespaceURIFunction:
6136 * @ctxt: the XPath Parser context
6137 * @nargs: the number of arguments
6138 *
6139 * Implement the namespace-uri() XPath function
6140 * string namespace-uri(node-set?)
6141 * The namespace-uri function returns a string containing the
6142 * namespace URI of the expanded name of the node in the argument
6143 * node-set that is first in document order. If the node-set is empty,
6144 * the first node has no name, or the expanded name has no namespace
6145 * URI, an empty string is returned. If the argument is omitted it
6146 * defaults to the context node.
6147 */
6148void
6149xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6150 xmlXPathObjectPtr cur;
6151
6152 if (nargs == 0) {
6153 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6154 nargs = 1;
6155 }
6156 CHECK_ARITY(1);
6157 if ((ctxt->value == NULL) ||
6158 ((ctxt->value->type != XPATH_NODESET) &&
6159 (ctxt->value->type != XPATH_XSLT_TREE)))
6160 XP_ERROR(XPATH_INVALID_TYPE);
6161 cur = valuePop(ctxt);
6162
Daniel Veillard911f49a2001-04-07 15:39:35 +00006163 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006164 valuePush(ctxt, xmlXPathNewCString(""));
6165 } else {
6166 int i = 0; /* Should be first in document order !!!!! */
6167 switch (cur->nodesetval->nodeTab[i]->type) {
6168 case XML_ELEMENT_NODE:
6169 case XML_ATTRIBUTE_NODE:
6170 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6171 valuePush(ctxt, xmlXPathNewCString(""));
6172 else
6173 valuePush(ctxt, xmlXPathNewString(
6174 cur->nodesetval->nodeTab[i]->ns->href));
6175 break;
6176 default:
6177 valuePush(ctxt, xmlXPathNewCString(""));
6178 }
6179 }
6180 xmlXPathFreeObject(cur);
6181}
6182
6183/**
6184 * xmlXPathNameFunction:
6185 * @ctxt: the XPath Parser context
6186 * @nargs: the number of arguments
6187 *
6188 * Implement the name() XPath function
6189 * string name(node-set?)
6190 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006191 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006192 * order. The QName must represent the name with respect to the namespace
6193 * declarations in effect on the node whose name is being represented.
6194 * Typically, this will be the form in which the name occurred in the XML
6195 * source. This need not be the case if there are namespace declarations
6196 * in effect on the node that associate multiple prefixes with the same
6197 * namespace. However, an implementation may include information about
6198 * the original prefix in its representation of nodes; in this case, an
6199 * implementation can ensure that the returned string is always the same
6200 * as the QName used in the XML source. If the argument it omitted it
6201 * defaults to the context node.
6202 * Libxml keep the original prefix so the "real qualified name" used is
6203 * returned.
6204 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006205static void
Daniel Veillard04383752001-07-08 14:27:15 +00006206xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6207{
Owen Taylor3473f882001-02-23 17:55:21 +00006208 xmlXPathObjectPtr cur;
6209
6210 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006211 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6212 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006213 }
6214
6215 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006216 if ((ctxt->value == NULL) ||
6217 ((ctxt->value->type != XPATH_NODESET) &&
6218 (ctxt->value->type != XPATH_XSLT_TREE)))
6219 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006220 cur = valuePop(ctxt);
6221
Daniel Veillard911f49a2001-04-07 15:39:35 +00006222 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006223 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006224 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006225 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006226
Daniel Veillard04383752001-07-08 14:27:15 +00006227 switch (cur->nodesetval->nodeTab[i]->type) {
6228 case XML_ELEMENT_NODE:
6229 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006230 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6231 valuePush(ctxt, xmlXPathNewCString(""));
6232 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6233 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006234 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006235 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006236
Daniel Veillard652d8a92003-02-04 19:28:49 +00006237 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006238 xmlChar *fullname;
6239
6240 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6241 cur->nodesetval->nodeTab[i]->ns->prefix,
6242 NULL, 0);
6243 if (fullname == cur->nodesetval->nodeTab[i]->name)
6244 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6245 if (fullname == NULL) {
6246 XP_ERROR(XPATH_MEMORY_ERROR);
6247 }
6248 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006249 }
6250 break;
6251 default:
6252 valuePush(ctxt,
6253 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6254 xmlXPathLocalNameFunction(ctxt, 1);
6255 }
Owen Taylor3473f882001-02-23 17:55:21 +00006256 }
6257 xmlXPathFreeObject(cur);
6258}
6259
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006260
6261/**
Owen Taylor3473f882001-02-23 17:55:21 +00006262 * xmlXPathStringFunction:
6263 * @ctxt: the XPath Parser context
6264 * @nargs: the number of arguments
6265 *
6266 * Implement the string() XPath function
6267 * string string(object?)
6268 * he string function converts an object to a string as follows:
6269 * - A node-set is converted to a string by returning the value of
6270 * the node in the node-set that is first in document order.
6271 * If the node-set is empty, an empty string is returned.
6272 * - A number is converted to a string as follows
6273 * + NaN is converted to the string NaN
6274 * + positive zero is converted to the string 0
6275 * + negative zero is converted to the string 0
6276 * + positive infinity is converted to the string Infinity
6277 * + negative infinity is converted to the string -Infinity
6278 * + if the number is an integer, the number is represented in
6279 * decimal form as a Number with no decimal point and no leading
6280 * zeros, preceded by a minus sign (-) if the number is negative
6281 * + otherwise, the number is represented in decimal form as a
6282 * Number including a decimal point with at least one digit
6283 * before the decimal point and at least one digit after the
6284 * decimal point, preceded by a minus sign (-) if the number
6285 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006286 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006287 * before the decimal point; beyond the one required digit
6288 * after the decimal point there must be as many, but only as
6289 * many, more digits as are needed to uniquely distinguish the
6290 * number from all other IEEE 754 numeric values.
6291 * - The boolean false value is converted to the string false.
6292 * The boolean true value is converted to the string true.
6293 *
6294 * If the argument is omitted, it defaults to a node-set with the
6295 * context node as its only member.
6296 */
6297void
6298xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6299 xmlXPathObjectPtr cur;
6300
6301 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006302 valuePush(ctxt,
6303 xmlXPathWrapString(
6304 xmlXPathCastNodeToString(ctxt->context->node)));
6305 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006306 }
6307
6308 CHECK_ARITY(1);
6309 cur = valuePop(ctxt);
6310 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006311 cur = xmlXPathConvertString(cur);
6312 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006313}
6314
6315/**
6316 * xmlXPathStringLengthFunction:
6317 * @ctxt: the XPath Parser context
6318 * @nargs: the number of arguments
6319 *
6320 * Implement the string-length() XPath function
6321 * number string-length(string?)
6322 * The string-length returns the number of characters in the string
6323 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6324 * the context node converted to a string, in other words the value
6325 * of the context node.
6326 */
6327void
6328xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6329 xmlXPathObjectPtr cur;
6330
6331 if (nargs == 0) {
6332 if (ctxt->context->node == NULL) {
6333 valuePush(ctxt, xmlXPathNewFloat(0));
6334 } else {
6335 xmlChar *content;
6336
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006337 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006338 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006339 xmlFree(content);
6340 }
6341 return;
6342 }
6343 CHECK_ARITY(1);
6344 CAST_TO_STRING;
6345 CHECK_TYPE(XPATH_STRING);
6346 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006347 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006348 xmlXPathFreeObject(cur);
6349}
6350
6351/**
6352 * xmlXPathConcatFunction:
6353 * @ctxt: the XPath Parser context
6354 * @nargs: the number of arguments
6355 *
6356 * Implement the concat() XPath function
6357 * string concat(string, string, string*)
6358 * The concat function returns the concatenation of its arguments.
6359 */
6360void
6361xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6362 xmlXPathObjectPtr cur, newobj;
6363 xmlChar *tmp;
6364
6365 if (nargs < 2) {
6366 CHECK_ARITY(2);
6367 }
6368
6369 CAST_TO_STRING;
6370 cur = valuePop(ctxt);
6371 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6372 xmlXPathFreeObject(cur);
6373 return;
6374 }
6375 nargs--;
6376
6377 while (nargs > 0) {
6378 CAST_TO_STRING;
6379 newobj = valuePop(ctxt);
6380 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6381 xmlXPathFreeObject(newobj);
6382 xmlXPathFreeObject(cur);
6383 XP_ERROR(XPATH_INVALID_TYPE);
6384 }
6385 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6386 newobj->stringval = cur->stringval;
6387 cur->stringval = tmp;
6388
6389 xmlXPathFreeObject(newobj);
6390 nargs--;
6391 }
6392 valuePush(ctxt, cur);
6393}
6394
6395/**
6396 * xmlXPathContainsFunction:
6397 * @ctxt: the XPath Parser context
6398 * @nargs: the number of arguments
6399 *
6400 * Implement the contains() XPath function
6401 * boolean contains(string, string)
6402 * The contains function returns true if the first argument string
6403 * contains the second argument string, and otherwise returns false.
6404 */
6405void
6406xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6407 xmlXPathObjectPtr hay, needle;
6408
6409 CHECK_ARITY(2);
6410 CAST_TO_STRING;
6411 CHECK_TYPE(XPATH_STRING);
6412 needle = valuePop(ctxt);
6413 CAST_TO_STRING;
6414 hay = valuePop(ctxt);
6415 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6416 xmlXPathFreeObject(hay);
6417 xmlXPathFreeObject(needle);
6418 XP_ERROR(XPATH_INVALID_TYPE);
6419 }
6420 if (xmlStrstr(hay->stringval, needle->stringval))
6421 valuePush(ctxt, xmlXPathNewBoolean(1));
6422 else
6423 valuePush(ctxt, xmlXPathNewBoolean(0));
6424 xmlXPathFreeObject(hay);
6425 xmlXPathFreeObject(needle);
6426}
6427
6428/**
6429 * xmlXPathStartsWithFunction:
6430 * @ctxt: the XPath Parser context
6431 * @nargs: the number of arguments
6432 *
6433 * Implement the starts-with() XPath function
6434 * boolean starts-with(string, string)
6435 * The starts-with function returns true if the first argument string
6436 * starts with the second argument string, and otherwise returns false.
6437 */
6438void
6439xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6440 xmlXPathObjectPtr hay, needle;
6441 int n;
6442
6443 CHECK_ARITY(2);
6444 CAST_TO_STRING;
6445 CHECK_TYPE(XPATH_STRING);
6446 needle = valuePop(ctxt);
6447 CAST_TO_STRING;
6448 hay = valuePop(ctxt);
6449 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6450 xmlXPathFreeObject(hay);
6451 xmlXPathFreeObject(needle);
6452 XP_ERROR(XPATH_INVALID_TYPE);
6453 }
6454 n = xmlStrlen(needle->stringval);
6455 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6456 valuePush(ctxt, xmlXPathNewBoolean(0));
6457 else
6458 valuePush(ctxt, xmlXPathNewBoolean(1));
6459 xmlXPathFreeObject(hay);
6460 xmlXPathFreeObject(needle);
6461}
6462
6463/**
6464 * xmlXPathSubstringFunction:
6465 * @ctxt: the XPath Parser context
6466 * @nargs: the number of arguments
6467 *
6468 * Implement the substring() XPath function
6469 * string substring(string, number, number?)
6470 * The substring function returns the substring of the first argument
6471 * starting at the position specified in the second argument with
6472 * length specified in the third argument. For example,
6473 * substring("12345",2,3) returns "234". If the third argument is not
6474 * specified, it returns the substring starting at the position specified
6475 * in the second argument and continuing to the end of the string. For
6476 * example, substring("12345",2) returns "2345". More precisely, each
6477 * character in the string (see [3.6 Strings]) is considered to have a
6478 * numeric position: the position of the first character is 1, the position
6479 * of the second character is 2 and so on. The returned substring contains
6480 * those characters for which the position of the character is greater than
6481 * or equal to the second argument and, if the third argument is specified,
6482 * less than the sum of the second and third arguments; the comparisons
6483 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6484 * - substring("12345", 1.5, 2.6) returns "234"
6485 * - substring("12345", 0, 3) returns "12"
6486 * - substring("12345", 0 div 0, 3) returns ""
6487 * - substring("12345", 1, 0 div 0) returns ""
6488 * - substring("12345", -42, 1 div 0) returns "12345"
6489 * - substring("12345", -1 div 0, 1 div 0) returns ""
6490 */
6491void
6492xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6493 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006494 double le=0, in;
6495 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006496 xmlChar *ret;
6497
Owen Taylor3473f882001-02-23 17:55:21 +00006498 if (nargs < 2) {
6499 CHECK_ARITY(2);
6500 }
6501 if (nargs > 3) {
6502 CHECK_ARITY(3);
6503 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006504 /*
6505 * take care of possible last (position) argument
6506 */
Owen Taylor3473f882001-02-23 17:55:21 +00006507 if (nargs == 3) {
6508 CAST_TO_NUMBER;
6509 CHECK_TYPE(XPATH_NUMBER);
6510 len = valuePop(ctxt);
6511 le = len->floatval;
6512 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006513 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006514
Owen Taylor3473f882001-02-23 17:55:21 +00006515 CAST_TO_NUMBER;
6516 CHECK_TYPE(XPATH_NUMBER);
6517 start = valuePop(ctxt);
6518 in = start->floatval;
6519 xmlXPathFreeObject(start);
6520 CAST_TO_STRING;
6521 CHECK_TYPE(XPATH_STRING);
6522 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006523 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006524
Daniel Veillard97ac1312001-05-30 19:14:17 +00006525 /*
6526 * If last pos not present, calculate last position
6527 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006528 if (nargs != 3) {
6529 le = (double)m;
6530 if (in < 1.0)
6531 in = 1.0;
6532 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006533
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006534 /* Need to check for the special cases where either
6535 * the index is NaN, the length is NaN, or both
6536 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006537 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006538 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006539 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006540 * To meet the requirements of the spec, the arguments
6541 * must be converted to integer format before
6542 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006543 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006544 * First we go to integer form, rounding up
6545 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006546 */
6547 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006548 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006549
Daniel Veillard9e412302002-06-10 15:59:44 +00006550 if (xmlXPathIsInf(le) == 1) {
6551 l = m;
6552 if (i < 1)
6553 i = 1;
6554 }
6555 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6556 l = 0;
6557 else {
6558 l = (int) le;
6559 if (((double)l)+0.5 <= le) l++;
6560 }
6561
6562 /* Now we normalize inidices */
6563 i -= 1;
6564 l += i;
6565 if (i < 0)
6566 i = 0;
6567 if (l > m)
6568 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006569
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006570 /* number of chars to copy */
6571 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006572
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006573 ret = xmlUTF8Strsub(str->stringval, i, l);
6574 }
6575 else {
6576 ret = NULL;
6577 }
6578
Owen Taylor3473f882001-02-23 17:55:21 +00006579 if (ret == NULL)
6580 valuePush(ctxt, xmlXPathNewCString(""));
6581 else {
6582 valuePush(ctxt, xmlXPathNewString(ret));
6583 xmlFree(ret);
6584 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006585
Owen Taylor3473f882001-02-23 17:55:21 +00006586 xmlXPathFreeObject(str);
6587}
6588
6589/**
6590 * xmlXPathSubstringBeforeFunction:
6591 * @ctxt: the XPath Parser context
6592 * @nargs: the number of arguments
6593 *
6594 * Implement the substring-before() XPath function
6595 * string substring-before(string, string)
6596 * The substring-before function returns the substring of the first
6597 * argument string that precedes the first occurrence of the second
6598 * argument string in the first argument string, or the empty string
6599 * if the first argument string does not contain the second argument
6600 * string. For example, substring-before("1999/04/01","/") returns 1999.
6601 */
6602void
6603xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6604 xmlXPathObjectPtr str;
6605 xmlXPathObjectPtr find;
6606 xmlBufferPtr target;
6607 const xmlChar *point;
6608 int offset;
6609
6610 CHECK_ARITY(2);
6611 CAST_TO_STRING;
6612 find = valuePop(ctxt);
6613 CAST_TO_STRING;
6614 str = valuePop(ctxt);
6615
6616 target = xmlBufferCreate();
6617 if (target) {
6618 point = xmlStrstr(str->stringval, find->stringval);
6619 if (point) {
6620 offset = (int)(point - str->stringval);
6621 xmlBufferAdd(target, str->stringval, offset);
6622 }
6623 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6624 xmlBufferFree(target);
6625 }
6626
6627 xmlXPathFreeObject(str);
6628 xmlXPathFreeObject(find);
6629}
6630
6631/**
6632 * xmlXPathSubstringAfterFunction:
6633 * @ctxt: the XPath Parser context
6634 * @nargs: the number of arguments
6635 *
6636 * Implement the substring-after() XPath function
6637 * string substring-after(string, string)
6638 * The substring-after function returns the substring of the first
6639 * argument string that follows the first occurrence of the second
6640 * argument string in the first argument string, or the empty stringi
6641 * if the first argument string does not contain the second argument
6642 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6643 * and substring-after("1999/04/01","19") returns 99/04/01.
6644 */
6645void
6646xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6647 xmlXPathObjectPtr str;
6648 xmlXPathObjectPtr find;
6649 xmlBufferPtr target;
6650 const xmlChar *point;
6651 int offset;
6652
6653 CHECK_ARITY(2);
6654 CAST_TO_STRING;
6655 find = valuePop(ctxt);
6656 CAST_TO_STRING;
6657 str = valuePop(ctxt);
6658
6659 target = xmlBufferCreate();
6660 if (target) {
6661 point = xmlStrstr(str->stringval, find->stringval);
6662 if (point) {
6663 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6664 xmlBufferAdd(target, &str->stringval[offset],
6665 xmlStrlen(str->stringval) - offset);
6666 }
6667 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6668 xmlBufferFree(target);
6669 }
6670
6671 xmlXPathFreeObject(str);
6672 xmlXPathFreeObject(find);
6673}
6674
6675/**
6676 * xmlXPathNormalizeFunction:
6677 * @ctxt: the XPath Parser context
6678 * @nargs: the number of arguments
6679 *
6680 * Implement the normalize-space() XPath function
6681 * string normalize-space(string?)
6682 * The normalize-space function returns the argument string with white
6683 * space normalized by stripping leading and trailing whitespace
6684 * and replacing sequences of whitespace characters by a single
6685 * space. Whitespace characters are the same allowed by the S production
6686 * in XML. If the argument is omitted, it defaults to the context
6687 * node converted to a string, in other words the value of the context node.
6688 */
6689void
6690xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6691 xmlXPathObjectPtr obj = NULL;
6692 xmlChar *source = NULL;
6693 xmlBufferPtr target;
6694 xmlChar blank;
6695
6696 if (nargs == 0) {
6697 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006698 valuePush(ctxt,
6699 xmlXPathWrapString(
6700 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006701 nargs = 1;
6702 }
6703
6704 CHECK_ARITY(1);
6705 CAST_TO_STRING;
6706 CHECK_TYPE(XPATH_STRING);
6707 obj = valuePop(ctxt);
6708 source = obj->stringval;
6709
6710 target = xmlBufferCreate();
6711 if (target && source) {
6712
6713 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006714 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006715 source++;
6716
6717 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6718 blank = 0;
6719 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006720 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006721 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006722 } else {
6723 if (blank) {
6724 xmlBufferAdd(target, &blank, 1);
6725 blank = 0;
6726 }
6727 xmlBufferAdd(target, source, 1);
6728 }
6729 source++;
6730 }
6731
6732 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6733 xmlBufferFree(target);
6734 }
6735 xmlXPathFreeObject(obj);
6736}
6737
6738/**
6739 * xmlXPathTranslateFunction:
6740 * @ctxt: the XPath Parser context
6741 * @nargs: the number of arguments
6742 *
6743 * Implement the translate() XPath function
6744 * string translate(string, string, string)
6745 * The translate function returns the first argument string with
6746 * occurrences of characters in the second argument string replaced
6747 * by the character at the corresponding position in the third argument
6748 * string. For example, translate("bar","abc","ABC") returns the string
6749 * BAr. If there is a character in the second argument string with no
6750 * character at a corresponding position in the third argument string
6751 * (because the second argument string is longer than the third argument
6752 * string), then occurrences of that character in the first argument
6753 * string are removed. For example, translate("--aaa--","abc-","ABC")
6754 * returns "AAA". If a character occurs more than once in second
6755 * argument string, then the first occurrence determines the replacement
6756 * character. If the third argument string is longer than the second
6757 * argument string, then excess characters are ignored.
6758 */
6759void
6760xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006761 xmlXPathObjectPtr str;
6762 xmlXPathObjectPtr from;
6763 xmlXPathObjectPtr to;
6764 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006765 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006766 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006767 xmlChar *point;
6768 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006769
Daniel Veillarde043ee12001-04-16 14:08:07 +00006770 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006771
Daniel Veillarde043ee12001-04-16 14:08:07 +00006772 CAST_TO_STRING;
6773 to = valuePop(ctxt);
6774 CAST_TO_STRING;
6775 from = valuePop(ctxt);
6776 CAST_TO_STRING;
6777 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006778
Daniel Veillarde043ee12001-04-16 14:08:07 +00006779 target = xmlBufferCreate();
6780 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006781 max = xmlUTF8Strlen(to->stringval);
6782 for (cptr = str->stringval; (ch=*cptr); ) {
6783 offset = xmlUTF8Strloc(from->stringval, cptr);
6784 if (offset >= 0) {
6785 if (offset < max) {
6786 point = xmlUTF8Strpos(to->stringval, offset);
6787 if (point)
6788 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6789 }
6790 } else
6791 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6792
6793 /* Step to next character in input */
6794 cptr++;
6795 if ( ch & 0x80 ) {
6796 /* if not simple ascii, verify proper format */
6797 if ( (ch & 0xc0) != 0xc0 ) {
6798 xmlGenericError(xmlGenericErrorContext,
6799 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6800 break;
6801 }
6802 /* then skip over remaining bytes for this char */
6803 while ( (ch <<= 1) & 0x80 )
6804 if ( (*cptr++ & 0xc0) != 0x80 ) {
6805 xmlGenericError(xmlGenericErrorContext,
6806 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6807 break;
6808 }
6809 if (ch & 0x80) /* must have had error encountered */
6810 break;
6811 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006812 }
Owen Taylor3473f882001-02-23 17:55:21 +00006813 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006814 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6815 xmlBufferFree(target);
6816 xmlXPathFreeObject(str);
6817 xmlXPathFreeObject(from);
6818 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006819}
6820
6821/**
6822 * xmlXPathBooleanFunction:
6823 * @ctxt: the XPath Parser context
6824 * @nargs: the number of arguments
6825 *
6826 * Implement the boolean() XPath function
6827 * boolean boolean(object)
6828 * he boolean function converts its argument to a boolean as follows:
6829 * - a number is true if and only if it is neither positive or
6830 * negative zero nor NaN
6831 * - a node-set is true if and only if it is non-empty
6832 * - a string is true if and only if its length is non-zero
6833 */
6834void
6835xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6836 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006837
6838 CHECK_ARITY(1);
6839 cur = valuePop(ctxt);
6840 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006841 cur = xmlXPathConvertBoolean(cur);
6842 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006843}
6844
6845/**
6846 * xmlXPathNotFunction:
6847 * @ctxt: the XPath Parser context
6848 * @nargs: the number of arguments
6849 *
6850 * Implement the not() XPath function
6851 * boolean not(boolean)
6852 * The not function returns true if its argument is false,
6853 * and false otherwise.
6854 */
6855void
6856xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6857 CHECK_ARITY(1);
6858 CAST_TO_BOOLEAN;
6859 CHECK_TYPE(XPATH_BOOLEAN);
6860 ctxt->value->boolval = ! ctxt->value->boolval;
6861}
6862
6863/**
6864 * xmlXPathTrueFunction:
6865 * @ctxt: the XPath Parser context
6866 * @nargs: the number of arguments
6867 *
6868 * Implement the true() XPath function
6869 * boolean true()
6870 */
6871void
6872xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6873 CHECK_ARITY(0);
6874 valuePush(ctxt, xmlXPathNewBoolean(1));
6875}
6876
6877/**
6878 * xmlXPathFalseFunction:
6879 * @ctxt: the XPath Parser context
6880 * @nargs: the number of arguments
6881 *
6882 * Implement the false() XPath function
6883 * boolean false()
6884 */
6885void
6886xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6887 CHECK_ARITY(0);
6888 valuePush(ctxt, xmlXPathNewBoolean(0));
6889}
6890
6891/**
6892 * xmlXPathLangFunction:
6893 * @ctxt: the XPath Parser context
6894 * @nargs: the number of arguments
6895 *
6896 * Implement the lang() XPath function
6897 * boolean lang(string)
6898 * The lang function returns true or false depending on whether the
6899 * language of the context node as specified by xml:lang attributes
6900 * is the same as or is a sublanguage of the language specified by
6901 * the argument string. The language of the context node is determined
6902 * by the value of the xml:lang attribute on the context node, or, if
6903 * the context node has no xml:lang attribute, by the value of the
6904 * xml:lang attribute on the nearest ancestor of the context node that
6905 * has an xml:lang attribute. If there is no such attribute, then lang
6906 * returns false. If there is such an attribute, then lang returns
6907 * true if the attribute value is equal to the argument ignoring case,
6908 * or if there is some suffix starting with - such that the attribute
6909 * value is equal to the argument ignoring that suffix of the attribute
6910 * value and ignoring case.
6911 */
6912void
6913xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6914 xmlXPathObjectPtr val;
6915 const xmlChar *theLang;
6916 const xmlChar *lang;
6917 int ret = 0;
6918 int i;
6919
6920 CHECK_ARITY(1);
6921 CAST_TO_STRING;
6922 CHECK_TYPE(XPATH_STRING);
6923 val = valuePop(ctxt);
6924 lang = val->stringval;
6925 theLang = xmlNodeGetLang(ctxt->context->node);
6926 if ((theLang != NULL) && (lang != NULL)) {
6927 for (i = 0;lang[i] != 0;i++)
6928 if (toupper(lang[i]) != toupper(theLang[i]))
6929 goto not_equal;
6930 ret = 1;
6931 }
6932not_equal:
6933 xmlXPathFreeObject(val);
6934 valuePush(ctxt, xmlXPathNewBoolean(ret));
6935}
6936
6937/**
6938 * xmlXPathNumberFunction:
6939 * @ctxt: the XPath Parser context
6940 * @nargs: the number of arguments
6941 *
6942 * Implement the number() XPath function
6943 * number number(object?)
6944 */
6945void
6946xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6947 xmlXPathObjectPtr cur;
6948 double res;
6949
6950 if (nargs == 0) {
6951 if (ctxt->context->node == NULL) {
6952 valuePush(ctxt, xmlXPathNewFloat(0.0));
6953 } else {
6954 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6955
6956 res = xmlXPathStringEvalNumber(content);
6957 valuePush(ctxt, xmlXPathNewFloat(res));
6958 xmlFree(content);
6959 }
6960 return;
6961 }
6962
6963 CHECK_ARITY(1);
6964 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006965 cur = xmlXPathConvertNumber(cur);
6966 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006967}
6968
6969/**
6970 * xmlXPathSumFunction:
6971 * @ctxt: the XPath Parser context
6972 * @nargs: the number of arguments
6973 *
6974 * Implement the sum() XPath function
6975 * number sum(node-set)
6976 * The sum function returns the sum of the values of the nodes in
6977 * the argument node-set.
6978 */
6979void
6980xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6981 xmlXPathObjectPtr cur;
6982 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006983 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006984
6985 CHECK_ARITY(1);
6986 if ((ctxt->value == NULL) ||
6987 ((ctxt->value->type != XPATH_NODESET) &&
6988 (ctxt->value->type != XPATH_XSLT_TREE)))
6989 XP_ERROR(XPATH_INVALID_TYPE);
6990 cur = valuePop(ctxt);
6991
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006992 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006993 valuePush(ctxt, xmlXPathNewFloat(0.0));
6994 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006995 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6996 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006997 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006998 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006999 }
7000 xmlXPathFreeObject(cur);
7001}
7002
7003/**
7004 * xmlXPathFloorFunction:
7005 * @ctxt: the XPath Parser context
7006 * @nargs: the number of arguments
7007 *
7008 * Implement the floor() XPath function
7009 * number floor(number)
7010 * The floor function returns the largest (closest to positive infinity)
7011 * number that is not greater than the argument and that is an integer.
7012 */
7013void
7014xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007015 double f;
7016
Owen Taylor3473f882001-02-23 17:55:21 +00007017 CHECK_ARITY(1);
7018 CAST_TO_NUMBER;
7019 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007020
7021 f = (double)((int) ctxt->value->floatval);
7022 if (f != ctxt->value->floatval) {
7023 if (ctxt->value->floatval > 0)
7024 ctxt->value->floatval = f;
7025 else
7026 ctxt->value->floatval = f - 1;
7027 }
Owen Taylor3473f882001-02-23 17:55:21 +00007028}
7029
7030/**
7031 * xmlXPathCeilingFunction:
7032 * @ctxt: the XPath Parser context
7033 * @nargs: the number of arguments
7034 *
7035 * Implement the ceiling() XPath function
7036 * number ceiling(number)
7037 * The ceiling function returns the smallest (closest to negative infinity)
7038 * number that is not less than the argument and that is an integer.
7039 */
7040void
7041xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7042 double f;
7043
7044 CHECK_ARITY(1);
7045 CAST_TO_NUMBER;
7046 CHECK_TYPE(XPATH_NUMBER);
7047
7048#if 0
7049 ctxt->value->floatval = ceil(ctxt->value->floatval);
7050#else
7051 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007052 if (f != ctxt->value->floatval) {
7053 if (ctxt->value->floatval > 0)
7054 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007055 else {
7056 if (ctxt->value->floatval < 0 && f == 0)
7057 ctxt->value->floatval = xmlXPathNZERO;
7058 else
7059 ctxt->value->floatval = f;
7060 }
7061
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007062 }
Owen Taylor3473f882001-02-23 17:55:21 +00007063#endif
7064}
7065
7066/**
7067 * xmlXPathRoundFunction:
7068 * @ctxt: the XPath Parser context
7069 * @nargs: the number of arguments
7070 *
7071 * Implement the round() XPath function
7072 * number round(number)
7073 * The round function returns the number that is closest to the
7074 * argument and that is an integer. If there are two such numbers,
7075 * then the one that is even is returned.
7076 */
7077void
7078xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7079 double f;
7080
7081 CHECK_ARITY(1);
7082 CAST_TO_NUMBER;
7083 CHECK_TYPE(XPATH_NUMBER);
7084
Daniel Veillardcda96922001-08-21 10:56:31 +00007085 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7086 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7087 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007088 (ctxt->value->floatval == 0.0))
7089 return;
7090
Owen Taylor3473f882001-02-23 17:55:21 +00007091 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007092 if (ctxt->value->floatval < 0) {
7093 if (ctxt->value->floatval < f - 0.5)
7094 ctxt->value->floatval = f - 1;
7095 else
7096 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007097 if (ctxt->value->floatval == 0)
7098 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007099 } else {
7100 if (ctxt->value->floatval < f + 0.5)
7101 ctxt->value->floatval = f;
7102 else
7103 ctxt->value->floatval = f + 1;
7104 }
Owen Taylor3473f882001-02-23 17:55:21 +00007105}
7106
7107/************************************************************************
7108 * *
7109 * The Parser *
7110 * *
7111 ************************************************************************/
7112
7113/*
7114 * a couple of forward declarations since we use a recursive call based
7115 * implementation.
7116 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007117static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007118static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007119static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007120static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007121static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7122 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007123
7124/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007125 * xmlXPathCurrentChar:
7126 * @ctxt: the XPath parser context
7127 * @cur: pointer to the beginning of the char
7128 * @len: pointer to the length of the char read
7129 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007130 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007131 * bytes in the input buffer.
7132 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007133 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007134 */
7135
7136static int
7137xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7138 unsigned char c;
7139 unsigned int val;
7140 const xmlChar *cur;
7141
7142 if (ctxt == NULL)
7143 return(0);
7144 cur = ctxt->cur;
7145
7146 /*
7147 * We are supposed to handle UTF8, check it's valid
7148 * From rfc2044: encoding of the Unicode values on UTF-8:
7149 *
7150 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7151 * 0000 0000-0000 007F 0xxxxxxx
7152 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7153 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7154 *
7155 * Check for the 0x110000 limit too
7156 */
7157 c = *cur;
7158 if (c & 0x80) {
7159 if ((cur[1] & 0xc0) != 0x80)
7160 goto encoding_error;
7161 if ((c & 0xe0) == 0xe0) {
7162
7163 if ((cur[2] & 0xc0) != 0x80)
7164 goto encoding_error;
7165 if ((c & 0xf0) == 0xf0) {
7166 if (((c & 0xf8) != 0xf0) ||
7167 ((cur[3] & 0xc0) != 0x80))
7168 goto encoding_error;
7169 /* 4-byte code */
7170 *len = 4;
7171 val = (cur[0] & 0x7) << 18;
7172 val |= (cur[1] & 0x3f) << 12;
7173 val |= (cur[2] & 0x3f) << 6;
7174 val |= cur[3] & 0x3f;
7175 } else {
7176 /* 3-byte code */
7177 *len = 3;
7178 val = (cur[0] & 0xf) << 12;
7179 val |= (cur[1] & 0x3f) << 6;
7180 val |= cur[2] & 0x3f;
7181 }
7182 } else {
7183 /* 2-byte code */
7184 *len = 2;
7185 val = (cur[0] & 0x1f) << 6;
7186 val |= cur[1] & 0x3f;
7187 }
7188 if (!IS_CHAR(val)) {
7189 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7190 }
7191 return(val);
7192 } else {
7193 /* 1-byte code */
7194 *len = 1;
7195 return((int) *cur);
7196 }
7197encoding_error:
7198 /*
7199 * If we detect an UTF8 error that probably mean that the
7200 * input encoding didn't get properly advertized in the
7201 * declaration header. Report the error and switch the encoding
7202 * to ISO-Latin-1 (if you don't like this policy, just declare the
7203 * encoding !)
7204 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007205 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007206 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007207}
7208
7209/**
Owen Taylor3473f882001-02-23 17:55:21 +00007210 * xmlXPathParseNCName:
7211 * @ctxt: the XPath Parser context
7212 *
7213 * parse an XML namespace non qualified name.
7214 *
7215 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7216 *
7217 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7218 * CombiningChar | Extender
7219 *
7220 * Returns the namespace name or NULL
7221 */
7222
7223xmlChar *
7224xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007225 const xmlChar *in;
7226 xmlChar *ret;
7227 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007228
Daniel Veillard2156a562001-04-28 12:24:34 +00007229 /*
7230 * Accelerator for simple ASCII names
7231 */
7232 in = ctxt->cur;
7233 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7234 ((*in >= 0x41) && (*in <= 0x5A)) ||
7235 (*in == '_')) {
7236 in++;
7237 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7238 ((*in >= 0x41) && (*in <= 0x5A)) ||
7239 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007240 (*in == '_') || (*in == '.') ||
7241 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007242 in++;
7243 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7244 (*in == '[') || (*in == ']') || (*in == ':') ||
7245 (*in == '@') || (*in == '*')) {
7246 count = in - ctxt->cur;
7247 if (count == 0)
7248 return(NULL);
7249 ret = xmlStrndup(ctxt->cur, count);
7250 ctxt->cur = in;
7251 return(ret);
7252 }
7253 }
7254 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007255}
7256
Daniel Veillard2156a562001-04-28 12:24:34 +00007257
Owen Taylor3473f882001-02-23 17:55:21 +00007258/**
7259 * xmlXPathParseQName:
7260 * @ctxt: the XPath Parser context
7261 * @prefix: a xmlChar **
7262 *
7263 * parse an XML qualified name
7264 *
7265 * [NS 5] QName ::= (Prefix ':')? LocalPart
7266 *
7267 * [NS 6] Prefix ::= NCName
7268 *
7269 * [NS 7] LocalPart ::= NCName
7270 *
7271 * Returns the function returns the local part, and prefix is updated
7272 * to get the Prefix if any.
7273 */
7274
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007275static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007276xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7277 xmlChar *ret = NULL;
7278
7279 *prefix = NULL;
7280 ret = xmlXPathParseNCName(ctxt);
7281 if (CUR == ':') {
7282 *prefix = ret;
7283 NEXT;
7284 ret = xmlXPathParseNCName(ctxt);
7285 }
7286 return(ret);
7287}
7288
7289/**
7290 * xmlXPathParseName:
7291 * @ctxt: the XPath Parser context
7292 *
7293 * parse an XML name
7294 *
7295 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7296 * CombiningChar | Extender
7297 *
7298 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7299 *
7300 * Returns the namespace name or NULL
7301 */
7302
7303xmlChar *
7304xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007305 const xmlChar *in;
7306 xmlChar *ret;
7307 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007308
Daniel Veillard61d80a22001-04-27 17:13:01 +00007309 /*
7310 * Accelerator for simple ASCII names
7311 */
7312 in = ctxt->cur;
7313 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7314 ((*in >= 0x41) && (*in <= 0x5A)) ||
7315 (*in == '_') || (*in == ':')) {
7316 in++;
7317 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7318 ((*in >= 0x41) && (*in <= 0x5A)) ||
7319 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007320 (*in == '_') || (*in == '-') ||
7321 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007322 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007323 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007324 count = in - ctxt->cur;
7325 ret = xmlStrndup(ctxt->cur, count);
7326 ctxt->cur = in;
7327 return(ret);
7328 }
7329 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007330 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007331}
7332
Daniel Veillard61d80a22001-04-27 17:13:01 +00007333static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007334xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007335 xmlChar buf[XML_MAX_NAMELEN + 5];
7336 int len = 0, l;
7337 int c;
7338
7339 /*
7340 * Handler for more complex cases
7341 */
7342 c = CUR_CHAR(l);
7343 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007344 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7345 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007346 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007347 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007348 return(NULL);
7349 }
7350
7351 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7352 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7353 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007354 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007355 (IS_COMBINING(c)) ||
7356 (IS_EXTENDER(c)))) {
7357 COPY_BUF(l,buf,len,c);
7358 NEXTL(l);
7359 c = CUR_CHAR(l);
7360 if (len >= XML_MAX_NAMELEN) {
7361 /*
7362 * Okay someone managed to make a huge name, so he's ready to pay
7363 * for the processing speed.
7364 */
7365 xmlChar *buffer;
7366 int max = len * 2;
7367
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007368 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007369 if (buffer == NULL) {
7370 XP_ERROR0(XPATH_MEMORY_ERROR);
7371 }
7372 memcpy(buffer, buf, len);
7373 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7374 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007375 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007376 (IS_COMBINING(c)) ||
7377 (IS_EXTENDER(c))) {
7378 if (len + 10 > max) {
7379 max *= 2;
7380 buffer = (xmlChar *) xmlRealloc(buffer,
7381 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007382 if (buffer == NULL) {
7383 XP_ERROR0(XPATH_MEMORY_ERROR);
7384 }
7385 }
7386 COPY_BUF(l,buffer,len,c);
7387 NEXTL(l);
7388 c = CUR_CHAR(l);
7389 }
7390 buffer[len] = 0;
7391 return(buffer);
7392 }
7393 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007394 if (len == 0)
7395 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007396 return(xmlStrndup(buf, len));
7397}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007398
7399#define MAX_FRAC 20
7400
7401static double my_pow10[MAX_FRAC] = {
7402 1.0, 10.0, 100.0, 1000.0, 10000.0,
7403 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7404 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7405 100000000000000.0,
7406 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7407 1000000000000000000.0, 10000000000000000000.0
7408};
7409
Owen Taylor3473f882001-02-23 17:55:21 +00007410/**
7411 * xmlXPathStringEvalNumber:
7412 * @str: A string to scan
7413 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007414 * [30a] Float ::= Number ('e' Digits?)?
7415 *
Owen Taylor3473f882001-02-23 17:55:21 +00007416 * [30] Number ::= Digits ('.' Digits?)?
7417 * | '.' Digits
7418 * [31] Digits ::= [0-9]+
7419 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007420 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007421 * In complement of the Number expression, this function also handles
7422 * negative values : '-' Number.
7423 *
7424 * Returns the double value.
7425 */
7426double
7427xmlXPathStringEvalNumber(const xmlChar *str) {
7428 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007429 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007430 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007431 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007432 int exponent = 0;
7433 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007434#ifdef __GNUC__
7435 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007436 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007437#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007438 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007439 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007440 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7441 return(xmlXPathNAN);
7442 }
7443 if (*cur == '-') {
7444 isneg = 1;
7445 cur++;
7446 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007447
7448#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007449 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007450 * tmp/temp is a workaround against a gcc compiler bug
7451 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007452 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007453 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007454 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007455 ret = ret * 10;
7456 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007457 ok = 1;
7458 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007459 temp = (double) tmp;
7460 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007461 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007462#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007463 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007464 while ((*cur >= '0') && (*cur <= '9')) {
7465 ret = ret * 10 + (*cur - '0');
7466 ok = 1;
7467 cur++;
7468 }
7469#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007470
Owen Taylor3473f882001-02-23 17:55:21 +00007471 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007472 int v, frac = 0;
7473 double fraction = 0;
7474
Owen Taylor3473f882001-02-23 17:55:21 +00007475 cur++;
7476 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7477 return(xmlXPathNAN);
7478 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007479 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7480 v = (*cur - '0');
7481 fraction = fraction * 10 + v;
7482 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007483 cur++;
7484 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007485 fraction /= my_pow10[frac];
7486 ret = ret + fraction;
7487 while ((*cur >= '0') && (*cur <= '9'))
7488 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007489 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007490 if ((*cur == 'e') || (*cur == 'E')) {
7491 cur++;
7492 if (*cur == '-') {
7493 is_exponent_negative = 1;
7494 cur++;
7495 }
7496 while ((*cur >= '0') && (*cur <= '9')) {
7497 exponent = exponent * 10 + (*cur - '0');
7498 cur++;
7499 }
7500 }
William M. Brack76e95df2003-10-18 16:20:14 +00007501 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007502 if (*cur != 0) return(xmlXPathNAN);
7503 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007504 if (is_exponent_negative) exponent = -exponent;
7505 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007506 return(ret);
7507}
7508
7509/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007510 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007511 * @ctxt: the XPath Parser context
7512 *
7513 * [30] Number ::= Digits ('.' Digits?)?
7514 * | '.' Digits
7515 * [31] Digits ::= [0-9]+
7516 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007517 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007518 *
7519 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007520static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007521xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7522{
Owen Taylor3473f882001-02-23 17:55:21 +00007523 double ret = 0.0;
7524 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007525 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007526 int exponent = 0;
7527 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007528#ifdef __GNUC__
7529 unsigned long tmp = 0;
7530 double temp;
7531#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007532
7533 CHECK_ERROR;
7534 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7535 XP_ERROR(XPATH_NUMBER_ERROR);
7536 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007537#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007538 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007539 * tmp/temp is a workaround against a gcc compiler bug
7540 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007541 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007542 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007543 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007544 ret = ret * 10;
7545 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007546 ok = 1;
7547 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007548 temp = (double) tmp;
7549 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007550 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007551#else
7552 ret = 0;
7553 while ((CUR >= '0') && (CUR <= '9')) {
7554 ret = ret * 10 + (CUR - '0');
7555 ok = 1;
7556 NEXT;
7557 }
7558#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007559 if (CUR == '.') {
7560 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007561 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7562 XP_ERROR(XPATH_NUMBER_ERROR);
7563 }
7564 while ((CUR >= '0') && (CUR <= '9')) {
7565 mult /= 10;
7566 ret = ret + (CUR - '0') * mult;
7567 NEXT;
7568 }
Owen Taylor3473f882001-02-23 17:55:21 +00007569 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007570 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007571 NEXT;
7572 if (CUR == '-') {
7573 is_exponent_negative = 1;
7574 NEXT;
7575 }
7576 while ((CUR >= '0') && (CUR <= '9')) {
7577 exponent = exponent * 10 + (CUR - '0');
7578 NEXT;
7579 }
7580 if (is_exponent_negative)
7581 exponent = -exponent;
7582 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007583 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007584 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007585 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007586}
7587
7588/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007589 * xmlXPathParseLiteral:
7590 * @ctxt: the XPath Parser context
7591 *
7592 * Parse a Literal
7593 *
7594 * [29] Literal ::= '"' [^"]* '"'
7595 * | "'" [^']* "'"
7596 *
7597 * Returns the value found or NULL in case of error
7598 */
7599static xmlChar *
7600xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7601 const xmlChar *q;
7602 xmlChar *ret = NULL;
7603
7604 if (CUR == '"') {
7605 NEXT;
7606 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007607 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007608 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007609 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007610 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7611 } else {
7612 ret = xmlStrndup(q, CUR_PTR - q);
7613 NEXT;
7614 }
7615 } else if (CUR == '\'') {
7616 NEXT;
7617 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007618 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007619 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007620 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007621 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7622 } else {
7623 ret = xmlStrndup(q, CUR_PTR - q);
7624 NEXT;
7625 }
7626 } else {
7627 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7628 }
7629 return(ret);
7630}
7631
7632/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007633 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007634 * @ctxt: the XPath Parser context
7635 *
7636 * Parse a Literal and push it on the stack.
7637 *
7638 * [29] Literal ::= '"' [^"]* '"'
7639 * | "'" [^']* "'"
7640 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007641 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007642 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007643static void
7644xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007645 const xmlChar *q;
7646 xmlChar *ret = NULL;
7647
7648 if (CUR == '"') {
7649 NEXT;
7650 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007651 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007652 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007653 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007654 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7655 } else {
7656 ret = xmlStrndup(q, CUR_PTR - q);
7657 NEXT;
7658 }
7659 } else if (CUR == '\'') {
7660 NEXT;
7661 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007662 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007663 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007664 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007665 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7666 } else {
7667 ret = xmlStrndup(q, CUR_PTR - q);
7668 NEXT;
7669 }
7670 } else {
7671 XP_ERROR(XPATH_START_LITERAL_ERROR);
7672 }
7673 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007674 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7675 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007676 xmlFree(ret);
7677}
7678
7679/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007680 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007681 * @ctxt: the XPath Parser context
7682 *
7683 * Parse a VariableReference, evaluate it and push it on the stack.
7684 *
7685 * The variable bindings consist of a mapping from variable names
7686 * to variable values. The value of a variable is an object, which
7687 * of any of the types that are possible for the value of an expression,
7688 * and may also be of additional types not specified here.
7689 *
7690 * Early evaluation is possible since:
7691 * The variable bindings [...] used to evaluate a subexpression are
7692 * always the same as those used to evaluate the containing expression.
7693 *
7694 * [36] VariableReference ::= '$' QName
7695 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007696static void
7697xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007698 xmlChar *name;
7699 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007700
7701 SKIP_BLANKS;
7702 if (CUR != '$') {
7703 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7704 }
7705 NEXT;
7706 name = xmlXPathParseQName(ctxt, &prefix);
7707 if (name == NULL) {
7708 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7709 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007710 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007711 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7712 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007713 SKIP_BLANKS;
7714}
7715
7716/**
7717 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007718 * @name: a name string
7719 *
7720 * Is the name given a NodeType one.
7721 *
7722 * [38] NodeType ::= 'comment'
7723 * | 'text'
7724 * | 'processing-instruction'
7725 * | 'node'
7726 *
7727 * Returns 1 if true 0 otherwise
7728 */
7729int
7730xmlXPathIsNodeType(const xmlChar *name) {
7731 if (name == NULL)
7732 return(0);
7733
Daniel Veillard1971ee22002-01-31 20:29:19 +00007734 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007735 return(1);
7736 if (xmlStrEqual(name, BAD_CAST "text"))
7737 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007738 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007739 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007740 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007741 return(1);
7742 return(0);
7743}
7744
7745/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007746 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007747 * @ctxt: the XPath Parser context
7748 *
7749 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7750 * [17] Argument ::= Expr
7751 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007752 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007753 * pushed on the stack
7754 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007755static void
7756xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007757 xmlChar *name;
7758 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007759 int nbargs = 0;
7760
7761 name = xmlXPathParseQName(ctxt, &prefix);
7762 if (name == NULL) {
7763 XP_ERROR(XPATH_EXPR_ERROR);
7764 }
7765 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007766#ifdef DEBUG_EXPR
7767 if (prefix == NULL)
7768 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7769 name);
7770 else
7771 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7772 prefix, name);
7773#endif
7774
Owen Taylor3473f882001-02-23 17:55:21 +00007775 if (CUR != '(') {
7776 XP_ERROR(XPATH_EXPR_ERROR);
7777 }
7778 NEXT;
7779 SKIP_BLANKS;
7780
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007781 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007782 if (CUR != ')') {
7783 while (CUR != 0) {
7784 int op1 = ctxt->comp->last;
7785 ctxt->comp->last = -1;
7786 xmlXPathCompileExpr(ctxt);
7787 CHECK_ERROR;
7788 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7789 nbargs++;
7790 if (CUR == ')') break;
7791 if (CUR != ',') {
7792 XP_ERROR(XPATH_EXPR_ERROR);
7793 }
7794 NEXT;
7795 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007796 }
Owen Taylor3473f882001-02-23 17:55:21 +00007797 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007798 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7799 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007800 NEXT;
7801 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007802}
7803
7804/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007805 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007806 * @ctxt: the XPath Parser context
7807 *
7808 * [15] PrimaryExpr ::= VariableReference
7809 * | '(' Expr ')'
7810 * | Literal
7811 * | Number
7812 * | FunctionCall
7813 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007814 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007815 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007816static void
7817xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007818 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007819 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007820 else if (CUR == '(') {
7821 NEXT;
7822 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007823 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007824 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007825 if (CUR != ')') {
7826 XP_ERROR(XPATH_EXPR_ERROR);
7827 }
7828 NEXT;
7829 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007830 } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007831 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007832 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007833 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007834 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007835 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007836 }
7837 SKIP_BLANKS;
7838}
7839
7840/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007841 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007842 * @ctxt: the XPath Parser context
7843 *
7844 * [20] FilterExpr ::= PrimaryExpr
7845 * | FilterExpr Predicate
7846 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007847 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007848 * Square brackets are used to filter expressions in the same way that
7849 * they are used in location paths. It is an error if the expression to
7850 * be filtered does not evaluate to a node-set. The context node list
7851 * used for evaluating the expression in square brackets is the node-set
7852 * to be filtered listed in document order.
7853 */
7854
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007855static void
7856xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7857 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007858 CHECK_ERROR;
7859 SKIP_BLANKS;
7860
7861 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007862 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007863 SKIP_BLANKS;
7864 }
7865
7866
7867}
7868
7869/**
7870 * xmlXPathScanName:
7871 * @ctxt: the XPath Parser context
7872 *
7873 * Trickery: parse an XML name but without consuming the input flow
7874 * Needed to avoid insanity in the parser state.
7875 *
7876 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7877 * CombiningChar | Extender
7878 *
7879 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7880 *
7881 * [6] Names ::= Name (S Name)*
7882 *
7883 * Returns the Name parsed or NULL
7884 */
7885
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007886static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007887xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7888 xmlChar buf[XML_MAX_NAMELEN];
7889 int len = 0;
7890
7891 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007892 if (!IS_LETTER_CH(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00007893 (CUR != ':')) {
7894 return(NULL);
7895 }
7896
William M. Brack76e95df2003-10-18 16:20:14 +00007897 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007898 (NXT(len) == '.') || (NXT(len) == '-') ||
7899 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007900 (IS_COMBINING_CH(NXT(len))) ||
7901 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007902 buf[len] = NXT(len);
7903 len++;
7904 if (len >= XML_MAX_NAMELEN) {
7905 xmlGenericError(xmlGenericErrorContext,
7906 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brack76e95df2003-10-18 16:20:14 +00007907 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007908 (NXT(len) == '.') || (NXT(len) == '-') ||
7909 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007910 (IS_COMBINING_CH(NXT(len))) ||
7911 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00007912 len++;
7913 break;
7914 }
7915 }
7916 return(xmlStrndup(buf, len));
7917}
7918
7919/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007920 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007921 * @ctxt: the XPath Parser context
7922 *
7923 * [19] PathExpr ::= LocationPath
7924 * | FilterExpr
7925 * | FilterExpr '/' RelativeLocationPath
7926 * | FilterExpr '//' RelativeLocationPath
7927 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007928 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007929 * The / operator and // operators combine an arbitrary expression
7930 * and a relative location path. It is an error if the expression
7931 * does not evaluate to a node-set.
7932 * The / operator does composition in the same way as when / is
7933 * used in a location path. As in location paths, // is short for
7934 * /descendant-or-self::node()/.
7935 */
7936
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007937static void
7938xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007939 int lc = 1; /* Should we branch to LocationPath ? */
7940 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7941
7942 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007943 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
7944 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007945 lc = 0;
7946 } else if (CUR == '*') {
7947 /* relative or absolute location path */
7948 lc = 1;
7949 } else if (CUR == '/') {
7950 /* relative or absolute location path */
7951 lc = 1;
7952 } else if (CUR == '@') {
7953 /* relative abbreviated attribute location path */
7954 lc = 1;
7955 } else if (CUR == '.') {
7956 /* relative abbreviated attribute location path */
7957 lc = 1;
7958 } else {
7959 /*
7960 * Problem is finding if we have a name here whether it's:
7961 * - a nodetype
7962 * - a function call in which case it's followed by '('
7963 * - an axis in which case it's followed by ':'
7964 * - a element name
7965 * We do an a priori analysis here rather than having to
7966 * maintain parsed token content through the recursive function
7967 * calls. This looks uglier but makes the code quite easier to
7968 * read/write/debug.
7969 */
7970 SKIP_BLANKS;
7971 name = xmlXPathScanName(ctxt);
7972 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7973#ifdef DEBUG_STEP
7974 xmlGenericError(xmlGenericErrorContext,
7975 "PathExpr: Axis\n");
7976#endif
7977 lc = 1;
7978 xmlFree(name);
7979 } else if (name != NULL) {
7980 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00007981
7982
7983 while (NXT(len) != 0) {
7984 if (NXT(len) == '/') {
7985 /* element name */
7986#ifdef DEBUG_STEP
7987 xmlGenericError(xmlGenericErrorContext,
7988 "PathExpr: AbbrRelLocation\n");
7989#endif
7990 lc = 1;
7991 break;
William M. Brack76e95df2003-10-18 16:20:14 +00007992 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00007993 /* ignore blanks */
7994 ;
Owen Taylor3473f882001-02-23 17:55:21 +00007995 } else if (NXT(len) == ':') {
7996#ifdef DEBUG_STEP
7997 xmlGenericError(xmlGenericErrorContext,
7998 "PathExpr: AbbrRelLocation\n");
7999#endif
8000 lc = 1;
8001 break;
8002 } else if ((NXT(len) == '(')) {
8003 /* Note Type or Function */
8004 if (xmlXPathIsNodeType(name)) {
8005#ifdef DEBUG_STEP
8006 xmlGenericError(xmlGenericErrorContext,
8007 "PathExpr: Type search\n");
8008#endif
8009 lc = 1;
8010 } else {
8011#ifdef DEBUG_STEP
8012 xmlGenericError(xmlGenericErrorContext,
8013 "PathExpr: function call\n");
8014#endif
8015 lc = 0;
8016 }
8017 break;
8018 } else if ((NXT(len) == '[')) {
8019 /* element name */
8020#ifdef DEBUG_STEP
8021 xmlGenericError(xmlGenericErrorContext,
8022 "PathExpr: AbbrRelLocation\n");
8023#endif
8024 lc = 1;
8025 break;
8026 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8027 (NXT(len) == '=')) {
8028 lc = 1;
8029 break;
8030 } else {
8031 lc = 1;
8032 break;
8033 }
8034 len++;
8035 }
8036 if (NXT(len) == 0) {
8037#ifdef DEBUG_STEP
8038 xmlGenericError(xmlGenericErrorContext,
8039 "PathExpr: AbbrRelLocation\n");
8040#endif
8041 /* element name */
8042 lc = 1;
8043 }
8044 xmlFree(name);
8045 } else {
8046 /* make sure all cases are covered explicitely */
8047 XP_ERROR(XPATH_EXPR_ERROR);
8048 }
8049 }
8050
8051 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008052 if (CUR == '/') {
8053 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8054 } else {
8055 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008056 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008057 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008058 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008059 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008060 CHECK_ERROR;
8061 if ((CUR == '/') && (NXT(1) == '/')) {
8062 SKIP(2);
8063 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008064
8065 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8066 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8067 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8068
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008069 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008070 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008071 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008072 }
8073 }
8074 SKIP_BLANKS;
8075}
8076
8077/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008078 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008079 * @ctxt: the XPath Parser context
8080 *
8081 * [18] UnionExpr ::= PathExpr
8082 * | UnionExpr '|' PathExpr
8083 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008084 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008085 */
8086
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008087static void
8088xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8089 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008090 CHECK_ERROR;
8091 SKIP_BLANKS;
8092 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008093 int op1 = ctxt->comp->last;
8094 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008095
8096 NEXT;
8097 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008098 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008099
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008100 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8101
Owen Taylor3473f882001-02-23 17:55:21 +00008102 SKIP_BLANKS;
8103 }
Owen Taylor3473f882001-02-23 17:55:21 +00008104}
8105
8106/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008107 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008108 * @ctxt: the XPath Parser context
8109 *
8110 * [27] UnaryExpr ::= UnionExpr
8111 * | '-' UnaryExpr
8112 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008113 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008114 */
8115
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008116static void
8117xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008118 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008119 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008120
8121 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008122 while (CUR == '-') {
8123 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008124 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008125 NEXT;
8126 SKIP_BLANKS;
8127 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008128
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008129 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008130 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008131 if (found) {
8132 if (minus)
8133 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8134 else
8135 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008136 }
8137}
8138
8139/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008140 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008141 * @ctxt: the XPath Parser context
8142 *
8143 * [26] MultiplicativeExpr ::= UnaryExpr
8144 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8145 * | MultiplicativeExpr 'div' UnaryExpr
8146 * | MultiplicativeExpr 'mod' UnaryExpr
8147 * [34] MultiplyOperator ::= '*'
8148 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008149 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008150 */
8151
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008152static void
8153xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8154 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008155 CHECK_ERROR;
8156 SKIP_BLANKS;
8157 while ((CUR == '*') ||
8158 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8159 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8160 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008161 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008162
8163 if (CUR == '*') {
8164 op = 0;
8165 NEXT;
8166 } else if (CUR == 'd') {
8167 op = 1;
8168 SKIP(3);
8169 } else if (CUR == 'm') {
8170 op = 2;
8171 SKIP(3);
8172 }
8173 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008174 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008175 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008176 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008177 SKIP_BLANKS;
8178 }
8179}
8180
8181/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008182 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008183 * @ctxt: the XPath Parser context
8184 *
8185 * [25] AdditiveExpr ::= MultiplicativeExpr
8186 * | AdditiveExpr '+' MultiplicativeExpr
8187 * | AdditiveExpr '-' MultiplicativeExpr
8188 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008189 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008190 */
8191
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008192static void
8193xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008194
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008195 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008196 CHECK_ERROR;
8197 SKIP_BLANKS;
8198 while ((CUR == '+') || (CUR == '-')) {
8199 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008200 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008201
8202 if (CUR == '+') plus = 1;
8203 else plus = 0;
8204 NEXT;
8205 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008206 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008207 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008208 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008209 SKIP_BLANKS;
8210 }
8211}
8212
8213/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008214 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008215 * @ctxt: the XPath Parser context
8216 *
8217 * [24] RelationalExpr ::= AdditiveExpr
8218 * | RelationalExpr '<' AdditiveExpr
8219 * | RelationalExpr '>' AdditiveExpr
8220 * | RelationalExpr '<=' AdditiveExpr
8221 * | RelationalExpr '>=' AdditiveExpr
8222 *
8223 * A <= B > C is allowed ? Answer from James, yes with
8224 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8225 * which is basically what got implemented.
8226 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008227 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008228 * on the stack
8229 */
8230
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008231static void
8232xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8233 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008234 CHECK_ERROR;
8235 SKIP_BLANKS;
8236 while ((CUR == '<') ||
8237 (CUR == '>') ||
8238 ((CUR == '<') && (NXT(1) == '=')) ||
8239 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008240 int inf, strict;
8241 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008242
8243 if (CUR == '<') inf = 1;
8244 else inf = 0;
8245 if (NXT(1) == '=') strict = 0;
8246 else strict = 1;
8247 NEXT;
8248 if (!strict) NEXT;
8249 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008250 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008251 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008252 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008253 SKIP_BLANKS;
8254 }
8255}
8256
8257/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008258 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008259 * @ctxt: the XPath Parser context
8260 *
8261 * [23] EqualityExpr ::= RelationalExpr
8262 * | EqualityExpr '=' RelationalExpr
8263 * | EqualityExpr '!=' RelationalExpr
8264 *
8265 * A != B != C is allowed ? Answer from James, yes with
8266 * (RelationalExpr = RelationalExpr) = RelationalExpr
8267 * (RelationalExpr != RelationalExpr) != RelationalExpr
8268 * which is basically what got implemented.
8269 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008270 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008271 *
8272 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008273static void
8274xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8275 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008276 CHECK_ERROR;
8277 SKIP_BLANKS;
8278 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008279 int eq;
8280 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008281
8282 if (CUR == '=') eq = 1;
8283 else eq = 0;
8284 NEXT;
8285 if (!eq) NEXT;
8286 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008287 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008288 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008289 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008290 SKIP_BLANKS;
8291 }
8292}
8293
8294/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008295 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008296 * @ctxt: the XPath Parser context
8297 *
8298 * [22] AndExpr ::= EqualityExpr
8299 * | AndExpr 'and' EqualityExpr
8300 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008301 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008302 *
8303 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008304static void
8305xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8306 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008307 CHECK_ERROR;
8308 SKIP_BLANKS;
8309 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008310 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008311 SKIP(3);
8312 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008313 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008314 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008315 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008316 SKIP_BLANKS;
8317 }
8318}
8319
8320/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008321 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008322 * @ctxt: the XPath Parser context
8323 *
8324 * [14] Expr ::= OrExpr
8325 * [21] OrExpr ::= AndExpr
8326 * | OrExpr 'or' AndExpr
8327 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008328 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008329 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008330static void
8331xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8332 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008333 CHECK_ERROR;
8334 SKIP_BLANKS;
8335 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008336 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008337 SKIP(2);
8338 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008339 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008340 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008341 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8342 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008343 SKIP_BLANKS;
8344 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008345 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8346 /* more ops could be optimized too */
8347 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8348 }
Owen Taylor3473f882001-02-23 17:55:21 +00008349}
8350
8351/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008352 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008353 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008354 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008355 *
8356 * [8] Predicate ::= '[' PredicateExpr ']'
8357 * [9] PredicateExpr ::= Expr
8358 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008359 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008360 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008361static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008362xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008363 int op1 = ctxt->comp->last;
8364
8365 SKIP_BLANKS;
8366 if (CUR != '[') {
8367 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8368 }
8369 NEXT;
8370 SKIP_BLANKS;
8371
8372 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008373 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008374 CHECK_ERROR;
8375
8376 if (CUR != ']') {
8377 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8378 }
8379
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008380 if (filter)
8381 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8382 else
8383 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008384
8385 NEXT;
8386 SKIP_BLANKS;
8387}
8388
8389/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008390 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008391 * @ctxt: the XPath Parser context
8392 * @test: pointer to a xmlXPathTestVal
8393 * @type: pointer to a xmlXPathTypeVal
8394 * @prefix: placeholder for a possible name prefix
8395 *
8396 * [7] NodeTest ::= NameTest
8397 * | NodeType '(' ')'
8398 * | 'processing-instruction' '(' Literal ')'
8399 *
8400 * [37] NameTest ::= '*'
8401 * | NCName ':' '*'
8402 * | QName
8403 * [38] NodeType ::= 'comment'
8404 * | 'text'
8405 * | 'processing-instruction'
8406 * | 'node'
8407 *
8408 * Returns the name found and update @test, @type and @prefix appropriately
8409 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008410static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008411xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8412 xmlXPathTypeVal *type, const xmlChar **prefix,
8413 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008414 int blanks;
8415
8416 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8417 STRANGE;
8418 return(NULL);
8419 }
William M. Brack78637da2003-07-31 14:47:38 +00008420 *type = (xmlXPathTypeVal) 0;
8421 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008422 *prefix = NULL;
8423 SKIP_BLANKS;
8424
8425 if ((name == NULL) && (CUR == '*')) {
8426 /*
8427 * All elements
8428 */
8429 NEXT;
8430 *test = NODE_TEST_ALL;
8431 return(NULL);
8432 }
8433
8434 if (name == NULL)
8435 name = xmlXPathParseNCName(ctxt);
8436 if (name == NULL) {
8437 XP_ERROR0(XPATH_EXPR_ERROR);
8438 }
8439
William M. Brack76e95df2003-10-18 16:20:14 +00008440 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008441 SKIP_BLANKS;
8442 if (CUR == '(') {
8443 NEXT;
8444 /*
8445 * NodeType or PI search
8446 */
8447 if (xmlStrEqual(name, BAD_CAST "comment"))
8448 *type = NODE_TYPE_COMMENT;
8449 else if (xmlStrEqual(name, BAD_CAST "node"))
8450 *type = NODE_TYPE_NODE;
8451 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8452 *type = NODE_TYPE_PI;
8453 else if (xmlStrEqual(name, BAD_CAST "text"))
8454 *type = NODE_TYPE_TEXT;
8455 else {
8456 if (name != NULL)
8457 xmlFree(name);
8458 XP_ERROR0(XPATH_EXPR_ERROR);
8459 }
8460
8461 *test = NODE_TEST_TYPE;
8462
8463 SKIP_BLANKS;
8464 if (*type == NODE_TYPE_PI) {
8465 /*
8466 * Specific case: search a PI by name.
8467 */
Owen Taylor3473f882001-02-23 17:55:21 +00008468 if (name != NULL)
8469 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008470 name = NULL;
8471 if (CUR != ')') {
8472 name = xmlXPathParseLiteral(ctxt);
8473 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008474 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008475 SKIP_BLANKS;
8476 }
Owen Taylor3473f882001-02-23 17:55:21 +00008477 }
8478 if (CUR != ')') {
8479 if (name != NULL)
8480 xmlFree(name);
8481 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8482 }
8483 NEXT;
8484 return(name);
8485 }
8486 *test = NODE_TEST_NAME;
8487 if ((!blanks) && (CUR == ':')) {
8488 NEXT;
8489
8490 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008491 * Since currently the parser context don't have a
8492 * namespace list associated:
8493 * The namespace name for this prefix can be computed
8494 * only at evaluation time. The compilation is done
8495 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008496 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008497#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008498 *prefix = xmlXPathNsLookup(ctxt->context, name);
8499 if (name != NULL)
8500 xmlFree(name);
8501 if (*prefix == NULL) {
8502 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8503 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008504#else
8505 *prefix = name;
8506#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008507
8508 if (CUR == '*') {
8509 /*
8510 * All elements
8511 */
8512 NEXT;
8513 *test = NODE_TEST_ALL;
8514 return(NULL);
8515 }
8516
8517 name = xmlXPathParseNCName(ctxt);
8518 if (name == NULL) {
8519 XP_ERROR0(XPATH_EXPR_ERROR);
8520 }
8521 }
8522 return(name);
8523}
8524
8525/**
8526 * xmlXPathIsAxisName:
8527 * @name: a preparsed name token
8528 *
8529 * [6] AxisName ::= 'ancestor'
8530 * | 'ancestor-or-self'
8531 * | 'attribute'
8532 * | 'child'
8533 * | 'descendant'
8534 * | 'descendant-or-self'
8535 * | 'following'
8536 * | 'following-sibling'
8537 * | 'namespace'
8538 * | 'parent'
8539 * | 'preceding'
8540 * | 'preceding-sibling'
8541 * | 'self'
8542 *
8543 * Returns the axis or 0
8544 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008545static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008546xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008547 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008548 switch (name[0]) {
8549 case 'a':
8550 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8551 ret = AXIS_ANCESTOR;
8552 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8553 ret = AXIS_ANCESTOR_OR_SELF;
8554 if (xmlStrEqual(name, BAD_CAST "attribute"))
8555 ret = AXIS_ATTRIBUTE;
8556 break;
8557 case 'c':
8558 if (xmlStrEqual(name, BAD_CAST "child"))
8559 ret = AXIS_CHILD;
8560 break;
8561 case 'd':
8562 if (xmlStrEqual(name, BAD_CAST "descendant"))
8563 ret = AXIS_DESCENDANT;
8564 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8565 ret = AXIS_DESCENDANT_OR_SELF;
8566 break;
8567 case 'f':
8568 if (xmlStrEqual(name, BAD_CAST "following"))
8569 ret = AXIS_FOLLOWING;
8570 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8571 ret = AXIS_FOLLOWING_SIBLING;
8572 break;
8573 case 'n':
8574 if (xmlStrEqual(name, BAD_CAST "namespace"))
8575 ret = AXIS_NAMESPACE;
8576 break;
8577 case 'p':
8578 if (xmlStrEqual(name, BAD_CAST "parent"))
8579 ret = AXIS_PARENT;
8580 if (xmlStrEqual(name, BAD_CAST "preceding"))
8581 ret = AXIS_PRECEDING;
8582 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8583 ret = AXIS_PRECEDING_SIBLING;
8584 break;
8585 case 's':
8586 if (xmlStrEqual(name, BAD_CAST "self"))
8587 ret = AXIS_SELF;
8588 break;
8589 }
8590 return(ret);
8591}
8592
8593/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008594 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008595 * @ctxt: the XPath Parser context
8596 *
8597 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8598 * | AbbreviatedStep
8599 *
8600 * [12] AbbreviatedStep ::= '.' | '..'
8601 *
8602 * [5] AxisSpecifier ::= AxisName '::'
8603 * | AbbreviatedAxisSpecifier
8604 *
8605 * [13] AbbreviatedAxisSpecifier ::= '@'?
8606 *
8607 * Modified for XPtr range support as:
8608 *
8609 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8610 * | AbbreviatedStep
8611 * | 'range-to' '(' Expr ')' Predicate*
8612 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008613 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008614 * A location step of . is short for self::node(). This is
8615 * particularly useful in conjunction with //. For example, the
8616 * location path .//para is short for
8617 * self::node()/descendant-or-self::node()/child::para
8618 * and so will select all para descendant elements of the context
8619 * node.
8620 * Similarly, a location step of .. is short for parent::node().
8621 * For example, ../title is short for parent::node()/child::title
8622 * and so will select the title children of the parent of the context
8623 * node.
8624 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008625static void
8626xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008627#ifdef LIBXML_XPTR_ENABLED
8628 int rangeto = 0;
8629 int op2 = -1;
8630#endif
8631
Owen Taylor3473f882001-02-23 17:55:21 +00008632 SKIP_BLANKS;
8633 if ((CUR == '.') && (NXT(1) == '.')) {
8634 SKIP(2);
8635 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008636 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8637 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008638 } else if (CUR == '.') {
8639 NEXT;
8640 SKIP_BLANKS;
8641 } else {
8642 xmlChar *name = NULL;
8643 const xmlChar *prefix = NULL;
8644 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008645 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008646 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008647 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008648
8649 /*
8650 * The modification needed for XPointer change to the production
8651 */
8652#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008653 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008654 name = xmlXPathParseNCName(ctxt);
8655 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008656 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008657 xmlFree(name);
8658 SKIP_BLANKS;
8659 if (CUR != '(') {
8660 XP_ERROR(XPATH_EXPR_ERROR);
8661 }
8662 NEXT;
8663 SKIP_BLANKS;
8664
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008665 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008666 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008667 CHECK_ERROR;
8668
8669 SKIP_BLANKS;
8670 if (CUR != ')') {
8671 XP_ERROR(XPATH_EXPR_ERROR);
8672 }
8673 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008674 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008675 goto eval_predicates;
8676 }
8677 }
8678#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008679 if (CUR == '*') {
8680 axis = AXIS_CHILD;
8681 } else {
8682 if (name == NULL)
8683 name = xmlXPathParseNCName(ctxt);
8684 if (name != NULL) {
8685 axis = xmlXPathIsAxisName(name);
8686 if (axis != 0) {
8687 SKIP_BLANKS;
8688 if ((CUR == ':') && (NXT(1) == ':')) {
8689 SKIP(2);
8690 xmlFree(name);
8691 name = NULL;
8692 } else {
8693 /* an element name can conflict with an axis one :-\ */
8694 axis = AXIS_CHILD;
8695 }
Owen Taylor3473f882001-02-23 17:55:21 +00008696 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008697 axis = AXIS_CHILD;
8698 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008699 } else if (CUR == '@') {
8700 NEXT;
8701 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008702 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008703 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008704 }
Owen Taylor3473f882001-02-23 17:55:21 +00008705 }
8706
8707 CHECK_ERROR;
8708
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008709 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008710 if (test == 0)
8711 return;
8712
8713#ifdef DEBUG_STEP
8714 xmlGenericError(xmlGenericErrorContext,
8715 "Basis : computing new set\n");
8716#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008717
Owen Taylor3473f882001-02-23 17:55:21 +00008718#ifdef DEBUG_STEP
8719 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008720 if (ctxt->value == NULL)
8721 xmlGenericError(xmlGenericErrorContext, "no value\n");
8722 else if (ctxt->value->nodesetval == NULL)
8723 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8724 else
8725 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008726#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008727
8728eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008729 op1 = ctxt->comp->last;
8730 ctxt->comp->last = -1;
8731
Owen Taylor3473f882001-02-23 17:55:21 +00008732 SKIP_BLANKS;
8733 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008734 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008735 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008736
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008737#ifdef LIBXML_XPTR_ENABLED
8738 if (rangeto) {
8739 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8740 } else
8741#endif
8742 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8743 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008744
Owen Taylor3473f882001-02-23 17:55:21 +00008745 }
8746#ifdef DEBUG_STEP
8747 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008748 if (ctxt->value == NULL)
8749 xmlGenericError(xmlGenericErrorContext, "no value\n");
8750 else if (ctxt->value->nodesetval == NULL)
8751 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8752 else
8753 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8754 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008755#endif
8756}
8757
8758/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008759 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008760 * @ctxt: the XPath Parser context
8761 *
8762 * [3] RelativeLocationPath ::= Step
8763 * | RelativeLocationPath '/' Step
8764 * | AbbreviatedRelativeLocationPath
8765 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8766 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008767 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008768 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008769static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008770xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008771(xmlXPathParserContextPtr ctxt) {
8772 SKIP_BLANKS;
8773 if ((CUR == '/') && (NXT(1) == '/')) {
8774 SKIP(2);
8775 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008776 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8777 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008778 } else if (CUR == '/') {
8779 NEXT;
8780 SKIP_BLANKS;
8781 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008782 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008783 SKIP_BLANKS;
8784 while (CUR == '/') {
8785 if ((CUR == '/') && (NXT(1) == '/')) {
8786 SKIP(2);
8787 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008788 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008789 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008790 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008791 } else if (CUR == '/') {
8792 NEXT;
8793 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008794 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008795 }
8796 SKIP_BLANKS;
8797 }
8798}
8799
8800/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008801 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008802 * @ctxt: the XPath Parser context
8803 *
8804 * [1] LocationPath ::= RelativeLocationPath
8805 * | AbsoluteLocationPath
8806 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8807 * | AbbreviatedAbsoluteLocationPath
8808 * [10] AbbreviatedAbsoluteLocationPath ::=
8809 * '//' RelativeLocationPath
8810 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008811 * Compile a location path
8812 *
Owen Taylor3473f882001-02-23 17:55:21 +00008813 * // is short for /descendant-or-self::node()/. For example,
8814 * //para is short for /descendant-or-self::node()/child::para and
8815 * so will select any para element in the document (even a para element
8816 * that is a document element will be selected by //para since the
8817 * document element node is a child of the root node); div//para is
8818 * short for div/descendant-or-self::node()/child::para and so will
8819 * select all para descendants of div children.
8820 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008821static void
8822xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008823 SKIP_BLANKS;
8824 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008825 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008826 } else {
8827 while (CUR == '/') {
8828 if ((CUR == '/') && (NXT(1) == '/')) {
8829 SKIP(2);
8830 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008831 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8832 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008833 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008834 } else if (CUR == '/') {
8835 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008836 SKIP_BLANKS;
8837 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008838 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008839 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008840 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008841 }
8842 }
8843 }
8844}
8845
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008846/************************************************************************
8847 * *
8848 * XPath precompiled expression evaluation *
8849 * *
8850 ************************************************************************/
8851
Daniel Veillardf06307e2001-07-03 10:35:50 +00008852static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008853xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8854
8855/**
8856 * xmlXPathNodeCollectAndTest:
8857 * @ctxt: the XPath Parser context
8858 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008859 * @first: pointer to the first element in document order
8860 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008861 *
8862 * This is the function implementing a step: based on the current list
8863 * of nodes, it builds up a new list, looking at all nodes under that
8864 * axis and selecting them it also do the predicate filtering
8865 *
8866 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008867 *
8868 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008869 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008870static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008871xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008872 xmlXPathStepOpPtr op,
8873 xmlNodePtr * first, xmlNodePtr * last)
8874{
William M. Brack78637da2003-07-31 14:47:38 +00008875 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8876 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8877 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008878 const xmlChar *prefix = op->value4;
8879 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008880 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008881
8882#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008883 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008884#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008885 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008886 xmlNodeSetPtr ret, list;
8887 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008888 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008889 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008890 xmlNodePtr cur = NULL;
8891 xmlXPathObjectPtr obj;
8892 xmlNodeSetPtr nodelist;
8893 xmlNodePtr tmp;
8894
Daniel Veillardf06307e2001-07-03 10:35:50 +00008895 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008896 obj = valuePop(ctxt);
8897 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008898 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008899 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008900 URI = xmlXPathNsLookup(ctxt->context, prefix);
8901 if (URI == NULL)
8902 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008903 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008904#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008905 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008906#endif
8907 switch (axis) {
8908 case AXIS_ANCESTOR:
8909#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008910 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008911#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 first = NULL;
8913 next = xmlXPathNextAncestor;
8914 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008915 case AXIS_ANCESTOR_OR_SELF:
8916#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 xmlGenericError(xmlGenericErrorContext,
8918 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008919#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008920 first = NULL;
8921 next = xmlXPathNextAncestorOrSelf;
8922 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923 case AXIS_ATTRIBUTE:
8924#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008925 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008927 first = NULL;
8928 last = NULL;
8929 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008930 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008931 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008932 case AXIS_CHILD:
8933#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008934 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008935#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008936 last = NULL;
8937 next = xmlXPathNextChild;
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_DESCENDANT:
8941#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008942 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008943#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008944 last = NULL;
8945 next = xmlXPathNextDescendant;
8946 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008947 case AXIS_DESCENDANT_OR_SELF:
8948#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008949 xmlGenericError(xmlGenericErrorContext,
8950 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008951#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008952 last = NULL;
8953 next = xmlXPathNextDescendantOrSelf;
8954 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008955 case AXIS_FOLLOWING:
8956#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008957 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008958#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008959 last = NULL;
8960 next = xmlXPathNextFollowing;
8961 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008962 case AXIS_FOLLOWING_SIBLING:
8963#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008964 xmlGenericError(xmlGenericErrorContext,
8965 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008966#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008967 last = NULL;
8968 next = xmlXPathNextFollowingSibling;
8969 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970 case AXIS_NAMESPACE:
8971#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974 first = NULL;
8975 last = NULL;
8976 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008977 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008978 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008979 case AXIS_PARENT:
8980#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008981 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008982#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008983 first = NULL;
8984 next = xmlXPathNextParent;
8985 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008986 case AXIS_PRECEDING:
8987#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008988 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008989#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 first = NULL;
8991 next = xmlXPathNextPrecedingInternal;
8992 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008993 case AXIS_PRECEDING_SIBLING:
8994#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008995 xmlGenericError(xmlGenericErrorContext,
8996 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008997#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008998 first = NULL;
8999 next = xmlXPathNextPrecedingSibling;
9000 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009001 case AXIS_SELF:
9002#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009003 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009004#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009005 first = NULL;
9006 last = NULL;
9007 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009008 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009009 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009010 }
9011 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009012 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009013
9014 nodelist = obj->nodesetval;
9015 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009016 xmlXPathFreeObject(obj);
9017 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9018 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009019 }
9020 addNode = xmlXPathNodeSetAddUnique;
9021 ret = NULL;
9022#ifdef DEBUG_STEP
9023 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009024 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009025 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009026 case NODE_TEST_NONE:
9027 xmlGenericError(xmlGenericErrorContext,
9028 " searching for none !!!\n");
9029 break;
9030 case NODE_TEST_TYPE:
9031 xmlGenericError(xmlGenericErrorContext,
9032 " searching for type %d\n", type);
9033 break;
9034 case NODE_TEST_PI:
9035 xmlGenericError(xmlGenericErrorContext,
9036 " searching for PI !!!\n");
9037 break;
9038 case NODE_TEST_ALL:
9039 xmlGenericError(xmlGenericErrorContext,
9040 " searching for *\n");
9041 break;
9042 case NODE_TEST_NS:
9043 xmlGenericError(xmlGenericErrorContext,
9044 " searching for namespace %s\n",
9045 prefix);
9046 break;
9047 case NODE_TEST_NAME:
9048 xmlGenericError(xmlGenericErrorContext,
9049 " searching for name %s\n", name);
9050 if (prefix != NULL)
9051 xmlGenericError(xmlGenericErrorContext,
9052 " with namespace %s\n", prefix);
9053 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009054 }
9055 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9056#endif
9057 /*
9058 * 2.3 Node Tests
9059 * - For the attribute axis, the principal node type is attribute.
9060 * - For the namespace axis, the principal node type is namespace.
9061 * - For other axes, the principal node type is element.
9062 *
9063 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009064 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009065 * select all element children of the context node
9066 */
9067 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009068 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009069 ctxt->context->node = nodelist->nodeTab[i];
9070
Daniel Veillardf06307e2001-07-03 10:35:50 +00009071 cur = NULL;
9072 list = xmlXPathNodeSetCreate(NULL);
9073 do {
9074 cur = next(ctxt, cur);
9075 if (cur == NULL)
9076 break;
9077 if ((first != NULL) && (*first == cur))
9078 break;
9079 if (((t % 256) == 0) &&
9080 (first != NULL) && (*first != NULL) &&
9081 (xmlXPathCmpNodes(*first, cur) >= 0))
9082 break;
9083 if ((last != NULL) && (*last == cur))
9084 break;
9085 if (((t % 256) == 0) &&
9086 (last != NULL) && (*last != NULL) &&
9087 (xmlXPathCmpNodes(cur, *last) >= 0))
9088 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009089 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009090#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9092#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009093 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009094 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009095 ctxt->context->node = tmp;
9096 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009097 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 if ((cur->type == type) ||
9099 ((type == NODE_TYPE_NODE) &&
9100 ((cur->type == XML_DOCUMENT_NODE) ||
9101 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9102 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009103 (cur->type == XML_NAMESPACE_DECL) ||
9104 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 (cur->type == XML_PI_NODE) ||
9106 (cur->type == XML_COMMENT_NODE) ||
9107 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009108 (cur->type == XML_TEXT_NODE))) ||
9109 ((type == NODE_TYPE_TEXT) &&
9110 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009111#ifdef DEBUG_STEP
9112 n++;
9113#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 addNode(list, cur);
9115 }
9116 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009117 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009118 if (cur->type == XML_PI_NODE) {
9119 if ((name != NULL) &&
9120 (!xmlStrEqual(name, cur->name)))
9121 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009122#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009124#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009125 addNode(list, cur);
9126 }
9127 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009128 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 if (axis == AXIS_ATTRIBUTE) {
9130 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009131#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009133#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 addNode(list, cur);
9135 }
9136 } else if (axis == AXIS_NAMESPACE) {
9137 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009138#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009140#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009141 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9142 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 }
9144 } else {
9145 if (cur->type == XML_ELEMENT_NODE) {
9146 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009147#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009149#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009150 addNode(list, cur);
9151 } else if ((cur->ns != NULL) &&
9152 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009153#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009154 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009155#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009156 addNode(list, cur);
9157 }
9158 }
9159 }
9160 break;
9161 case NODE_TEST_NS:{
9162 TODO;
9163 break;
9164 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009165 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009166 switch (cur->type) {
9167 case XML_ELEMENT_NODE:
9168 if (xmlStrEqual(name, cur->name)) {
9169 if (prefix == NULL) {
9170 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009171#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009172 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009173#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009174 addNode(list, cur);
9175 }
9176 } else {
9177 if ((cur->ns != NULL) &&
9178 (xmlStrEqual(URI,
9179 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009180#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009181 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009182#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009183 addNode(list, cur);
9184 }
9185 }
9186 }
9187 break;
9188 case XML_ATTRIBUTE_NODE:{
9189 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009190
Daniel Veillardf06307e2001-07-03 10:35:50 +00009191 if (xmlStrEqual(name, attr->name)) {
9192 if (prefix == NULL) {
9193 if ((attr->ns == NULL) ||
9194 (attr->ns->prefix == NULL)) {
9195#ifdef DEBUG_STEP
9196 n++;
9197#endif
9198 addNode(list,
9199 (xmlNodePtr) attr);
9200 }
9201 } else {
9202 if ((attr->ns != NULL) &&
9203 (xmlStrEqual(URI,
9204 attr->ns->
9205 href))) {
9206#ifdef DEBUG_STEP
9207 n++;
9208#endif
9209 addNode(list,
9210 (xmlNodePtr) attr);
9211 }
9212 }
9213 }
9214 break;
9215 }
9216 case XML_NAMESPACE_DECL:
9217 if (cur->type == XML_NAMESPACE_DECL) {
9218 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009219
Daniel Veillardf06307e2001-07-03 10:35:50 +00009220 if ((ns->prefix != NULL) && (name != NULL)
9221 && (xmlStrEqual(ns->prefix, name))) {
9222#ifdef DEBUG_STEP
9223 n++;
9224#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009225 xmlXPathNodeSetAddNs(list,
9226 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009227 }
9228 }
9229 break;
9230 default:
9231 break;
9232 }
9233 break;
9234 break;
9235 }
9236 } while (cur != NULL);
9237
9238 /*
9239 * If there is some predicate filtering do it now
9240 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009241 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009242 xmlXPathObjectPtr obj2;
9243
9244 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9245 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9246 CHECK_TYPE0(XPATH_NODESET);
9247 obj2 = valuePop(ctxt);
9248 list = obj2->nodesetval;
9249 obj2->nodesetval = NULL;
9250 xmlXPathFreeObject(obj2);
9251 }
9252 if (ret == NULL) {
9253 ret = list;
9254 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009255 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009256 xmlXPathFreeNodeSet(list);
9257 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009258 }
9259 ctxt->context->node = tmp;
9260#ifdef DEBUG_STEP
9261 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009262 "\nExamined %d nodes, found %d nodes at that step\n",
9263 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009264#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009265 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009266 if ((obj->boolval) && (obj->user != NULL)) {
9267 ctxt->value->boolval = 1;
9268 ctxt->value->user = obj->user;
9269 obj->user = NULL;
9270 obj->boolval = 0;
9271 }
9272 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009273 return(t);
9274}
9275
9276/**
9277 * xmlXPathNodeCollectAndTestNth:
9278 * @ctxt: the XPath Parser context
9279 * @op: the XPath precompiled step operation
9280 * @indx: the index to collect
9281 * @first: pointer to the first element in document order
9282 * @last: pointer to the last element in document order
9283 *
9284 * This is the function implementing a step: based on the current list
9285 * of nodes, it builds up a new list, looking at all nodes under that
9286 * axis and selecting them it also do the predicate filtering
9287 *
9288 * Pushes the new NodeSet resulting from the search.
9289 * Returns the number of node traversed
9290 */
9291static int
9292xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9293 xmlXPathStepOpPtr op, int indx,
9294 xmlNodePtr * first, xmlNodePtr * last)
9295{
William M. Brack78637da2003-07-31 14:47:38 +00009296 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9297 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9298 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009299 const xmlChar *prefix = op->value4;
9300 const xmlChar *name = op->value5;
9301 const xmlChar *URI = NULL;
9302 int n = 0, t = 0;
9303
9304 int i;
9305 xmlNodeSetPtr list;
9306 xmlXPathTraversalFunction next = NULL;
9307 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9308 xmlNodePtr cur = NULL;
9309 xmlXPathObjectPtr obj;
9310 xmlNodeSetPtr nodelist;
9311 xmlNodePtr tmp;
9312
9313 CHECK_TYPE0(XPATH_NODESET);
9314 obj = valuePop(ctxt);
9315 addNode = xmlXPathNodeSetAdd;
9316 if (prefix != NULL) {
9317 URI = xmlXPathNsLookup(ctxt->context, prefix);
9318 if (URI == NULL)
9319 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9320 }
9321#ifdef DEBUG_STEP_NTH
9322 xmlGenericError(xmlGenericErrorContext, "new step : ");
9323 if (first != NULL) {
9324 if (*first != NULL)
9325 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9326 (*first)->name);
9327 else
9328 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9329 }
9330 if (last != NULL) {
9331 if (*last != NULL)
9332 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9333 (*last)->name);
9334 else
9335 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9336 }
9337#endif
9338 switch (axis) {
9339 case AXIS_ANCESTOR:
9340#ifdef DEBUG_STEP_NTH
9341 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9342#endif
9343 first = NULL;
9344 next = xmlXPathNextAncestor;
9345 break;
9346 case AXIS_ANCESTOR_OR_SELF:
9347#ifdef DEBUG_STEP_NTH
9348 xmlGenericError(xmlGenericErrorContext,
9349 "axis 'ancestors-or-self' ");
9350#endif
9351 first = NULL;
9352 next = xmlXPathNextAncestorOrSelf;
9353 break;
9354 case AXIS_ATTRIBUTE:
9355#ifdef DEBUG_STEP_NTH
9356 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9357#endif
9358 first = NULL;
9359 last = NULL;
9360 next = xmlXPathNextAttribute;
9361 break;
9362 case AXIS_CHILD:
9363#ifdef DEBUG_STEP_NTH
9364 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9365#endif
9366 last = NULL;
9367 next = xmlXPathNextChild;
9368 break;
9369 case AXIS_DESCENDANT:
9370#ifdef DEBUG_STEP_NTH
9371 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9372#endif
9373 last = NULL;
9374 next = xmlXPathNextDescendant;
9375 break;
9376 case AXIS_DESCENDANT_OR_SELF:
9377#ifdef DEBUG_STEP_NTH
9378 xmlGenericError(xmlGenericErrorContext,
9379 "axis 'descendant-or-self' ");
9380#endif
9381 last = NULL;
9382 next = xmlXPathNextDescendantOrSelf;
9383 break;
9384 case AXIS_FOLLOWING:
9385#ifdef DEBUG_STEP_NTH
9386 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9387#endif
9388 last = NULL;
9389 next = xmlXPathNextFollowing;
9390 break;
9391 case AXIS_FOLLOWING_SIBLING:
9392#ifdef DEBUG_STEP_NTH
9393 xmlGenericError(xmlGenericErrorContext,
9394 "axis 'following-siblings' ");
9395#endif
9396 last = NULL;
9397 next = xmlXPathNextFollowingSibling;
9398 break;
9399 case AXIS_NAMESPACE:
9400#ifdef DEBUG_STEP_NTH
9401 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9402#endif
9403 last = NULL;
9404 first = NULL;
9405 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9406 break;
9407 case AXIS_PARENT:
9408#ifdef DEBUG_STEP_NTH
9409 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9410#endif
9411 first = NULL;
9412 next = xmlXPathNextParent;
9413 break;
9414 case AXIS_PRECEDING:
9415#ifdef DEBUG_STEP_NTH
9416 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9417#endif
9418 first = NULL;
9419 next = xmlXPathNextPrecedingInternal;
9420 break;
9421 case AXIS_PRECEDING_SIBLING:
9422#ifdef DEBUG_STEP_NTH
9423 xmlGenericError(xmlGenericErrorContext,
9424 "axis 'preceding-sibling' ");
9425#endif
9426 first = NULL;
9427 next = xmlXPathNextPrecedingSibling;
9428 break;
9429 case AXIS_SELF:
9430#ifdef DEBUG_STEP_NTH
9431 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9432#endif
9433 first = NULL;
9434 last = NULL;
9435 next = xmlXPathNextSelf;
9436 break;
9437 }
9438 if (next == NULL)
9439 return(0);
9440
9441 nodelist = obj->nodesetval;
9442 if (nodelist == NULL) {
9443 xmlXPathFreeObject(obj);
9444 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9445 return(0);
9446 }
9447 addNode = xmlXPathNodeSetAddUnique;
9448#ifdef DEBUG_STEP_NTH
9449 xmlGenericError(xmlGenericErrorContext,
9450 " context contains %d nodes\n", nodelist->nodeNr);
9451 switch (test) {
9452 case NODE_TEST_NONE:
9453 xmlGenericError(xmlGenericErrorContext,
9454 " searching for none !!!\n");
9455 break;
9456 case NODE_TEST_TYPE:
9457 xmlGenericError(xmlGenericErrorContext,
9458 " searching for type %d\n", type);
9459 break;
9460 case NODE_TEST_PI:
9461 xmlGenericError(xmlGenericErrorContext,
9462 " searching for PI !!!\n");
9463 break;
9464 case NODE_TEST_ALL:
9465 xmlGenericError(xmlGenericErrorContext,
9466 " searching for *\n");
9467 break;
9468 case NODE_TEST_NS:
9469 xmlGenericError(xmlGenericErrorContext,
9470 " searching for namespace %s\n",
9471 prefix);
9472 break;
9473 case NODE_TEST_NAME:
9474 xmlGenericError(xmlGenericErrorContext,
9475 " searching for name %s\n", name);
9476 if (prefix != NULL)
9477 xmlGenericError(xmlGenericErrorContext,
9478 " with namespace %s\n", prefix);
9479 break;
9480 }
9481 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9482#endif
9483 /*
9484 * 2.3 Node Tests
9485 * - For the attribute axis, the principal node type is attribute.
9486 * - For the namespace axis, the principal node type is namespace.
9487 * - For other axes, the principal node type is element.
9488 *
9489 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009490 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009491 * select all element children of the context node
9492 */
9493 tmp = ctxt->context->node;
9494 list = xmlXPathNodeSetCreate(NULL);
9495 for (i = 0; i < nodelist->nodeNr; i++) {
9496 ctxt->context->node = nodelist->nodeTab[i];
9497
9498 cur = NULL;
9499 n = 0;
9500 do {
9501 cur = next(ctxt, cur);
9502 if (cur == NULL)
9503 break;
9504 if ((first != NULL) && (*first == cur))
9505 break;
9506 if (((t % 256) == 0) &&
9507 (first != NULL) && (*first != NULL) &&
9508 (xmlXPathCmpNodes(*first, cur) >= 0))
9509 break;
9510 if ((last != NULL) && (*last == cur))
9511 break;
9512 if (((t % 256) == 0) &&
9513 (last != NULL) && (*last != NULL) &&
9514 (xmlXPathCmpNodes(cur, *last) >= 0))
9515 break;
9516 t++;
9517 switch (test) {
9518 case NODE_TEST_NONE:
9519 ctxt->context->node = tmp;
9520 STRANGE return(0);
9521 case NODE_TEST_TYPE:
9522 if ((cur->type == type) ||
9523 ((type == NODE_TYPE_NODE) &&
9524 ((cur->type == XML_DOCUMENT_NODE) ||
9525 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9526 (cur->type == XML_ELEMENT_NODE) ||
9527 (cur->type == XML_PI_NODE) ||
9528 (cur->type == XML_COMMENT_NODE) ||
9529 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009530 (cur->type == XML_TEXT_NODE))) ||
9531 ((type == NODE_TYPE_TEXT) &&
9532 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009533 n++;
9534 if (n == indx)
9535 addNode(list, cur);
9536 }
9537 break;
9538 case NODE_TEST_PI:
9539 if (cur->type == XML_PI_NODE) {
9540 if ((name != NULL) &&
9541 (!xmlStrEqual(name, cur->name)))
9542 break;
9543 n++;
9544 if (n == indx)
9545 addNode(list, cur);
9546 }
9547 break;
9548 case NODE_TEST_ALL:
9549 if (axis == AXIS_ATTRIBUTE) {
9550 if (cur->type == XML_ATTRIBUTE_NODE) {
9551 n++;
9552 if (n == indx)
9553 addNode(list, cur);
9554 }
9555 } else if (axis == AXIS_NAMESPACE) {
9556 if (cur->type == XML_NAMESPACE_DECL) {
9557 n++;
9558 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009559 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9560 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009561 }
9562 } else {
9563 if (cur->type == XML_ELEMENT_NODE) {
9564 if (prefix == NULL) {
9565 n++;
9566 if (n == indx)
9567 addNode(list, cur);
9568 } else if ((cur->ns != NULL) &&
9569 (xmlStrEqual(URI, cur->ns->href))) {
9570 n++;
9571 if (n == indx)
9572 addNode(list, cur);
9573 }
9574 }
9575 }
9576 break;
9577 case NODE_TEST_NS:{
9578 TODO;
9579 break;
9580 }
9581 case NODE_TEST_NAME:
9582 switch (cur->type) {
9583 case XML_ELEMENT_NODE:
9584 if (xmlStrEqual(name, cur->name)) {
9585 if (prefix == NULL) {
9586 if (cur->ns == NULL) {
9587 n++;
9588 if (n == indx)
9589 addNode(list, cur);
9590 }
9591 } else {
9592 if ((cur->ns != NULL) &&
9593 (xmlStrEqual(URI,
9594 cur->ns->href))) {
9595 n++;
9596 if (n == indx)
9597 addNode(list, cur);
9598 }
9599 }
9600 }
9601 break;
9602 case XML_ATTRIBUTE_NODE:{
9603 xmlAttrPtr attr = (xmlAttrPtr) cur;
9604
9605 if (xmlStrEqual(name, attr->name)) {
9606 if (prefix == NULL) {
9607 if ((attr->ns == NULL) ||
9608 (attr->ns->prefix == NULL)) {
9609 n++;
9610 if (n == indx)
9611 addNode(list, cur);
9612 }
9613 } else {
9614 if ((attr->ns != NULL) &&
9615 (xmlStrEqual(URI,
9616 attr->ns->
9617 href))) {
9618 n++;
9619 if (n == indx)
9620 addNode(list, cur);
9621 }
9622 }
9623 }
9624 break;
9625 }
9626 case XML_NAMESPACE_DECL:
9627 if (cur->type == XML_NAMESPACE_DECL) {
9628 xmlNsPtr ns = (xmlNsPtr) cur;
9629
9630 if ((ns->prefix != NULL) && (name != NULL)
9631 && (xmlStrEqual(ns->prefix, name))) {
9632 n++;
9633 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009634 xmlXPathNodeSetAddNs(list,
9635 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009636 }
9637 }
9638 break;
9639 default:
9640 break;
9641 }
9642 break;
9643 break;
9644 }
9645 } while (n < indx);
9646 }
9647 ctxt->context->node = tmp;
9648#ifdef DEBUG_STEP_NTH
9649 xmlGenericError(xmlGenericErrorContext,
9650 "\nExamined %d nodes, found %d nodes at that step\n",
9651 t, list->nodeNr);
9652#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009653 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009654 if ((obj->boolval) && (obj->user != NULL)) {
9655 ctxt->value->boolval = 1;
9656 ctxt->value->user = obj->user;
9657 obj->user = NULL;
9658 obj->boolval = 0;
9659 }
9660 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009661 return(t);
9662}
9663
9664/**
9665 * xmlXPathCompOpEvalFirst:
9666 * @ctxt: the XPath parser context with the compiled expression
9667 * @op: an XPath compiled operation
9668 * @first: the first elem found so far
9669 *
9670 * Evaluate the Precompiled XPath operation searching only the first
9671 * element in document order
9672 *
9673 * Returns the number of examined objects.
9674 */
9675static int
9676xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9677 xmlXPathStepOpPtr op, xmlNodePtr * first)
9678{
9679 int total = 0, cur;
9680 xmlXPathCompExprPtr comp;
9681 xmlXPathObjectPtr arg1, arg2;
9682
Daniel Veillard556c6682001-10-06 09:59:51 +00009683 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009684 comp = ctxt->comp;
9685 switch (op->op) {
9686 case XPATH_OP_END:
9687 return (0);
9688 case XPATH_OP_UNION:
9689 total =
9690 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9691 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009692 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693 if ((ctxt->value != NULL)
9694 && (ctxt->value->type == XPATH_NODESET)
9695 && (ctxt->value->nodesetval != NULL)
9696 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9697 /*
9698 * limit tree traversing to first node in the result
9699 */
9700 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9701 *first = ctxt->value->nodesetval->nodeTab[0];
9702 }
9703 cur =
9704 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9705 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009706 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009707 CHECK_TYPE0(XPATH_NODESET);
9708 arg2 = valuePop(ctxt);
9709
9710 CHECK_TYPE0(XPATH_NODESET);
9711 arg1 = valuePop(ctxt);
9712
9713 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9714 arg2->nodesetval);
9715 valuePush(ctxt, arg1);
9716 xmlXPathFreeObject(arg2);
9717 /* optimizer */
9718 if (total > cur)
9719 xmlXPathCompSwap(op);
9720 return (total + cur);
9721 case XPATH_OP_ROOT:
9722 xmlXPathRoot(ctxt);
9723 return (0);
9724 case XPATH_OP_NODE:
9725 if (op->ch1 != -1)
9726 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009727 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009728 if (op->ch2 != -1)
9729 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009730 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009731 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9732 return (total);
9733 case XPATH_OP_RESET:
9734 if (op->ch1 != -1)
9735 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009736 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009737 if (op->ch2 != -1)
9738 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009739 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009740 ctxt->context->node = NULL;
9741 return (total);
9742 case XPATH_OP_COLLECT:{
9743 if (op->ch1 == -1)
9744 return (total);
9745
9746 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009747 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009748
9749 /*
9750 * Optimization for [n] selection where n is a number
9751 */
9752 if ((op->ch2 != -1) &&
9753 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9754 (comp->steps[op->ch2].ch1 == -1) &&
9755 (comp->steps[op->ch2].ch2 != -1) &&
9756 (comp->steps[comp->steps[op->ch2].ch2].op ==
9757 XPATH_OP_VALUE)) {
9758 xmlXPathObjectPtr val;
9759
9760 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9761 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9762 int indx = (int) val->floatval;
9763
9764 if (val->floatval == (float) indx) {
9765 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9766 first, NULL);
9767 return (total);
9768 }
9769 }
9770 }
9771 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9772 return (total);
9773 }
9774 case XPATH_OP_VALUE:
9775 valuePush(ctxt,
9776 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9777 return (0);
9778 case XPATH_OP_SORT:
9779 if (op->ch1 != -1)
9780 total +=
9781 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9782 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009783 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009784 if ((ctxt->value != NULL)
9785 && (ctxt->value->type == XPATH_NODESET)
9786 && (ctxt->value->nodesetval != NULL))
9787 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9788 return (total);
9789 default:
9790 return (xmlXPathCompOpEval(ctxt, op));
9791 }
9792}
9793
9794/**
9795 * xmlXPathCompOpEvalLast:
9796 * @ctxt: the XPath parser context with the compiled expression
9797 * @op: an XPath compiled operation
9798 * @last: the last elem found so far
9799 *
9800 * Evaluate the Precompiled XPath operation searching only the last
9801 * element in document order
9802 *
9803 * Returns the number of node traversed
9804 */
9805static int
9806xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9807 xmlNodePtr * last)
9808{
9809 int total = 0, cur;
9810 xmlXPathCompExprPtr comp;
9811 xmlXPathObjectPtr arg1, arg2;
9812
Daniel Veillard556c6682001-10-06 09:59:51 +00009813 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009814 comp = ctxt->comp;
9815 switch (op->op) {
9816 case XPATH_OP_END:
9817 return (0);
9818 case XPATH_OP_UNION:
9819 total =
9820 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009821 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009822 if ((ctxt->value != NULL)
9823 && (ctxt->value->type == XPATH_NODESET)
9824 && (ctxt->value->nodesetval != NULL)
9825 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9826 /*
9827 * limit tree traversing to first node in the result
9828 */
9829 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9830 *last =
9831 ctxt->value->nodesetval->nodeTab[ctxt->value->
9832 nodesetval->nodeNr -
9833 1];
9834 }
9835 cur =
9836 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009837 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009838 if ((ctxt->value != NULL)
9839 && (ctxt->value->type == XPATH_NODESET)
9840 && (ctxt->value->nodesetval != NULL)
9841 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9842 }
9843 CHECK_TYPE0(XPATH_NODESET);
9844 arg2 = valuePop(ctxt);
9845
9846 CHECK_TYPE0(XPATH_NODESET);
9847 arg1 = valuePop(ctxt);
9848
9849 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9850 arg2->nodesetval);
9851 valuePush(ctxt, arg1);
9852 xmlXPathFreeObject(arg2);
9853 /* optimizer */
9854 if (total > cur)
9855 xmlXPathCompSwap(op);
9856 return (total + cur);
9857 case XPATH_OP_ROOT:
9858 xmlXPathRoot(ctxt);
9859 return (0);
9860 case XPATH_OP_NODE:
9861 if (op->ch1 != -1)
9862 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009863 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009864 if (op->ch2 != -1)
9865 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009866 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009867 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9868 return (total);
9869 case XPATH_OP_RESET:
9870 if (op->ch1 != -1)
9871 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009872 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009873 if (op->ch2 != -1)
9874 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009875 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009876 ctxt->context->node = NULL;
9877 return (total);
9878 case XPATH_OP_COLLECT:{
9879 if (op->ch1 == -1)
9880 return (0);
9881
9882 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009883 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009884
9885 /*
9886 * Optimization for [n] selection where n is a number
9887 */
9888 if ((op->ch2 != -1) &&
9889 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9890 (comp->steps[op->ch2].ch1 == -1) &&
9891 (comp->steps[op->ch2].ch2 != -1) &&
9892 (comp->steps[comp->steps[op->ch2].ch2].op ==
9893 XPATH_OP_VALUE)) {
9894 xmlXPathObjectPtr val;
9895
9896 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9897 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9898 int indx = (int) val->floatval;
9899
9900 if (val->floatval == (float) indx) {
9901 total +=
9902 xmlXPathNodeCollectAndTestNth(ctxt, op,
9903 indx, NULL,
9904 last);
9905 return (total);
9906 }
9907 }
9908 }
9909 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9910 return (total);
9911 }
9912 case XPATH_OP_VALUE:
9913 valuePush(ctxt,
9914 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9915 return (0);
9916 case XPATH_OP_SORT:
9917 if (op->ch1 != -1)
9918 total +=
9919 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9920 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009921 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 if ((ctxt->value != NULL)
9923 && (ctxt->value->type == XPATH_NODESET)
9924 && (ctxt->value->nodesetval != NULL))
9925 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9926 return (total);
9927 default:
9928 return (xmlXPathCompOpEval(ctxt, op));
9929 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009930}
9931
Owen Taylor3473f882001-02-23 17:55:21 +00009932/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009933 * xmlXPathCompOpEval:
9934 * @ctxt: the XPath parser context with the compiled expression
9935 * @op: an XPath compiled operation
9936 *
9937 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009938 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009939 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009940static int
9941xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9942{
9943 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009944 int equal, ret;
9945 xmlXPathCompExprPtr comp;
9946 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009947 xmlNodePtr bak;
9948 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009949 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009950 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009951
Daniel Veillard556c6682001-10-06 09:59:51 +00009952 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009953 comp = ctxt->comp;
9954 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009955 case XPATH_OP_END:
9956 return (0);
9957 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009958 bakd = ctxt->context->doc;
9959 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009960 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009961 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009962 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009963 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009964 xmlXPathBooleanFunction(ctxt, 1);
9965 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9966 return (total);
9967 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009968 ctxt->context->doc = bakd;
9969 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009970 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009971 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009972 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009973 if (ctxt->error) {
9974 xmlXPathFreeObject(arg2);
9975 return(0);
9976 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009977 xmlXPathBooleanFunction(ctxt, 1);
9978 arg1 = valuePop(ctxt);
9979 arg1->boolval &= arg2->boolval;
9980 valuePush(ctxt, arg1);
9981 xmlXPathFreeObject(arg2);
9982 return (total);
9983 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009984 bakd = ctxt->context->doc;
9985 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009986 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009987 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009988 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009989 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009990 xmlXPathBooleanFunction(ctxt, 1);
9991 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9992 return (total);
9993 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009994 ctxt->context->doc = bakd;
9995 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009996 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009997 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009998 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009999 if (ctxt->error) {
10000 xmlXPathFreeObject(arg2);
10001 return(0);
10002 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010003 xmlXPathBooleanFunction(ctxt, 1);
10004 arg1 = valuePop(ctxt);
10005 arg1->boolval |= arg2->boolval;
10006 valuePush(ctxt, arg1);
10007 xmlXPathFreeObject(arg2);
10008 return (total);
10009 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010010 bakd = ctxt->context->doc;
10011 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010012 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010013 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010014 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010015 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010016 ctxt->context->doc = bakd;
10017 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010018 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010019 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010020 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010021 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010022 if (op->value)
10023 equal = xmlXPathEqualValues(ctxt);
10024 else
10025 equal = xmlXPathNotEqualValues(ctxt);
10026 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010027 return (total);
10028 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010029 bakd = ctxt->context->doc;
10030 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010031 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010032 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010033 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010034 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010035 ctxt->context->doc = bakd;
10036 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010037 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010038 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010039 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010040 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010041 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10042 valuePush(ctxt, xmlXPathNewBoolean(ret));
10043 return (total);
10044 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010045 bakd = ctxt->context->doc;
10046 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010047 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010048 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010049 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010050 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010051 if (op->ch2 != -1) {
10052 ctxt->context->doc = bakd;
10053 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010054 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010055 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010057 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010058 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059 if (op->value == 0)
10060 xmlXPathSubValues(ctxt);
10061 else if (op->value == 1)
10062 xmlXPathAddValues(ctxt);
10063 else if (op->value == 2)
10064 xmlXPathValueFlipSign(ctxt);
10065 else if (op->value == 3) {
10066 CAST_TO_NUMBER;
10067 CHECK_TYPE0(XPATH_NUMBER);
10068 }
10069 return (total);
10070 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010071 bakd = ctxt->context->doc;
10072 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010073 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010074 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010075 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010076 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010077 ctxt->context->doc = bakd;
10078 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010079 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010080 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010081 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010082 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010083 if (op->value == 0)
10084 xmlXPathMultValues(ctxt);
10085 else if (op->value == 1)
10086 xmlXPathDivValues(ctxt);
10087 else if (op->value == 2)
10088 xmlXPathModValues(ctxt);
10089 return (total);
10090 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010091 bakd = ctxt->context->doc;
10092 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010093 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010094 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010095 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010096 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010097 ctxt->context->doc = bakd;
10098 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010099 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010100 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010101 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010102 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010103 CHECK_TYPE0(XPATH_NODESET);
10104 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010105
Daniel Veillardf06307e2001-07-03 10:35:50 +000010106 CHECK_TYPE0(XPATH_NODESET);
10107 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010108
Daniel Veillardf06307e2001-07-03 10:35:50 +000010109 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10110 arg2->nodesetval);
10111 valuePush(ctxt, arg1);
10112 xmlXPathFreeObject(arg2);
10113 return (total);
10114 case XPATH_OP_ROOT:
10115 xmlXPathRoot(ctxt);
10116 return (total);
10117 case XPATH_OP_NODE:
10118 if (op->ch1 != -1)
10119 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010120 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010121 if (op->ch2 != -1)
10122 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010123 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010124 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10125 return (total);
10126 case XPATH_OP_RESET:
10127 if (op->ch1 != -1)
10128 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010129 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010130 if (op->ch2 != -1)
10131 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010132 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010133 ctxt->context->node = NULL;
10134 return (total);
10135 case XPATH_OP_COLLECT:{
10136 if (op->ch1 == -1)
10137 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010138
Daniel Veillardf06307e2001-07-03 10:35:50 +000010139 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010140 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010141
Daniel Veillardf06307e2001-07-03 10:35:50 +000010142 /*
10143 * Optimization for [n] selection where n is a number
10144 */
10145 if ((op->ch2 != -1) &&
10146 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10147 (comp->steps[op->ch2].ch1 == -1) &&
10148 (comp->steps[op->ch2].ch2 != -1) &&
10149 (comp->steps[comp->steps[op->ch2].ch2].op ==
10150 XPATH_OP_VALUE)) {
10151 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010152
Daniel Veillardf06307e2001-07-03 10:35:50 +000010153 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10154 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10155 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010156
Daniel Veillardf06307e2001-07-03 10:35:50 +000010157 if (val->floatval == (float) indx) {
10158 total +=
10159 xmlXPathNodeCollectAndTestNth(ctxt, op,
10160 indx, NULL,
10161 NULL);
10162 return (total);
10163 }
10164 }
10165 }
10166 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10167 return (total);
10168 }
10169 case XPATH_OP_VALUE:
10170 valuePush(ctxt,
10171 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10172 return (total);
10173 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010174 xmlXPathObjectPtr val;
10175
Daniel Veillardf06307e2001-07-03 10:35:50 +000010176 if (op->ch1 != -1)
10177 total +=
10178 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010179 if (op->value5 == NULL) {
10180 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10181 if (val == NULL) {
10182 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10183 return(0);
10184 }
10185 valuePush(ctxt, val);
10186 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010187 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010188
Daniel Veillardf06307e2001-07-03 10:35:50 +000010189 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10190 if (URI == NULL) {
10191 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010192 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010193 op->value4, op->value5);
10194 return (total);
10195 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010196 val = xmlXPathVariableLookupNS(ctxt->context,
10197 op->value4, URI);
10198 if (val == NULL) {
10199 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10200 return(0);
10201 }
10202 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010203 }
10204 return (total);
10205 }
10206 case XPATH_OP_FUNCTION:{
10207 xmlXPathFunction func;
10208 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010209 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010210
10211 if (op->ch1 != -1)
10212 total +=
10213 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010214 if (ctxt->valueNr < op->value) {
10215 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010216 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010217 ctxt->error = XPATH_INVALID_OPERAND;
10218 return (total);
10219 }
10220 for (i = 0; i < op->value; i++)
10221 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10222 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010223 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010224 ctxt->error = XPATH_INVALID_OPERAND;
10225 return (total);
10226 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010227 if (op->cache != NULL)
10228 func = (xmlXPathFunction) op->cache;
10229 else {
10230 const xmlChar *URI = NULL;
10231
10232 if (op->value5 == NULL)
10233 func =
10234 xmlXPathFunctionLookup(ctxt->context,
10235 op->value4);
10236 else {
10237 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10238 if (URI == NULL) {
10239 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010240 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010241 op->value4, op->value5);
10242 return (total);
10243 }
10244 func = xmlXPathFunctionLookupNS(ctxt->context,
10245 op->value4, URI);
10246 }
10247 if (func == NULL) {
10248 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010249 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010250 op->value4);
10251 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010252 }
10253 op->cache = (void *) func;
10254 op->cacheURI = (void *) URI;
10255 }
10256 oldFunc = ctxt->context->function;
10257 oldFuncURI = ctxt->context->functionURI;
10258 ctxt->context->function = op->value4;
10259 ctxt->context->functionURI = op->cacheURI;
10260 func(ctxt, op->value);
10261 ctxt->context->function = oldFunc;
10262 ctxt->context->functionURI = oldFuncURI;
10263 return (total);
10264 }
10265 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010266 bakd = ctxt->context->doc;
10267 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010268 if (op->ch1 != -1)
10269 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010270 ctxt->context->doc = bakd;
10271 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010272 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010273 if (op->ch2 != -1)
10274 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010275 ctxt->context->doc = bakd;
10276 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010277 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010278 return (total);
10279 case XPATH_OP_PREDICATE:
10280 case XPATH_OP_FILTER:{
10281 xmlXPathObjectPtr res;
10282 xmlXPathObjectPtr obj, tmp;
10283 xmlNodeSetPtr newset = NULL;
10284 xmlNodeSetPtr oldset;
10285 xmlNodePtr oldnode;
10286 int i;
10287
10288 /*
10289 * Optimization for ()[1] selection i.e. the first elem
10290 */
10291 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10292 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10293 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10294 xmlXPathObjectPtr val;
10295
10296 val = comp->steps[op->ch2].value4;
10297 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10298 (val->floatval == 1.0)) {
10299 xmlNodePtr first = NULL;
10300
10301 total +=
10302 xmlXPathCompOpEvalFirst(ctxt,
10303 &comp->steps[op->ch1],
10304 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010305 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010306 /*
10307 * The nodeset should be in document order,
10308 * Keep only the first value
10309 */
10310 if ((ctxt->value != NULL) &&
10311 (ctxt->value->type == XPATH_NODESET) &&
10312 (ctxt->value->nodesetval != NULL) &&
10313 (ctxt->value->nodesetval->nodeNr > 1))
10314 ctxt->value->nodesetval->nodeNr = 1;
10315 return (total);
10316 }
10317 }
10318 /*
10319 * Optimization for ()[last()] selection i.e. the last elem
10320 */
10321 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10322 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10323 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10324 int f = comp->steps[op->ch2].ch1;
10325
10326 if ((f != -1) &&
10327 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10328 (comp->steps[f].value5 == NULL) &&
10329 (comp->steps[f].value == 0) &&
10330 (comp->steps[f].value4 != NULL) &&
10331 (xmlStrEqual
10332 (comp->steps[f].value4, BAD_CAST "last"))) {
10333 xmlNodePtr last = NULL;
10334
10335 total +=
10336 xmlXPathCompOpEvalLast(ctxt,
10337 &comp->steps[op->ch1],
10338 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010339 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010340 /*
10341 * The nodeset should be in document order,
10342 * Keep only the last value
10343 */
10344 if ((ctxt->value != NULL) &&
10345 (ctxt->value->type == XPATH_NODESET) &&
10346 (ctxt->value->nodesetval != NULL) &&
10347 (ctxt->value->nodesetval->nodeTab != NULL) &&
10348 (ctxt->value->nodesetval->nodeNr > 1)) {
10349 ctxt->value->nodesetval->nodeTab[0] =
10350 ctxt->value->nodesetval->nodeTab[ctxt->
10351 value->
10352 nodesetval->
10353 nodeNr -
10354 1];
10355 ctxt->value->nodesetval->nodeNr = 1;
10356 }
10357 return (total);
10358 }
10359 }
10360
10361 if (op->ch1 != -1)
10362 total +=
10363 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010364 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010365 if (op->ch2 == -1)
10366 return (total);
10367 if (ctxt->value == NULL)
10368 return (total);
10369
10370 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010371
10372#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010373 /*
10374 * Hum are we filtering the result of an XPointer expression
10375 */
10376 if (ctxt->value->type == XPATH_LOCATIONSET) {
10377 xmlLocationSetPtr newlocset = NULL;
10378 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010379
Daniel Veillardf06307e2001-07-03 10:35:50 +000010380 /*
10381 * Extract the old locset, and then evaluate the result of the
10382 * expression for all the element in the locset. use it to grow
10383 * up a new locset.
10384 */
10385 CHECK_TYPE0(XPATH_LOCATIONSET);
10386 obj = valuePop(ctxt);
10387 oldlocset = obj->user;
10388 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010389
Daniel Veillardf06307e2001-07-03 10:35:50 +000010390 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10391 ctxt->context->contextSize = 0;
10392 ctxt->context->proximityPosition = 0;
10393 if (op->ch2 != -1)
10394 total +=
10395 xmlXPathCompOpEval(ctxt,
10396 &comp->steps[op->ch2]);
10397 res = valuePop(ctxt);
10398 if (res != NULL)
10399 xmlXPathFreeObject(res);
10400 valuePush(ctxt, obj);
10401 CHECK_ERROR0;
10402 return (total);
10403 }
10404 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010405
Daniel Veillardf06307e2001-07-03 10:35:50 +000010406 for (i = 0; i < oldlocset->locNr; i++) {
10407 /*
10408 * Run the evaluation with a node list made of a
10409 * single item in the nodelocset.
10410 */
10411 ctxt->context->node = oldlocset->locTab[i]->user;
10412 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10413 valuePush(ctxt, tmp);
10414 ctxt->context->contextSize = oldlocset->locNr;
10415 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010416
Daniel Veillardf06307e2001-07-03 10:35:50 +000010417 if (op->ch2 != -1)
10418 total +=
10419 xmlXPathCompOpEval(ctxt,
10420 &comp->steps[op->ch2]);
10421 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010422
Daniel Veillardf06307e2001-07-03 10:35:50 +000010423 /*
10424 * The result of the evaluation need to be tested to
10425 * decided whether the filter succeeded or not
10426 */
10427 res = valuePop(ctxt);
10428 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10429 xmlXPtrLocationSetAdd(newlocset,
10430 xmlXPathObjectCopy
10431 (oldlocset->locTab[i]));
10432 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010433
Daniel Veillardf06307e2001-07-03 10:35:50 +000010434 /*
10435 * Cleanup
10436 */
10437 if (res != NULL)
10438 xmlXPathFreeObject(res);
10439 if (ctxt->value == tmp) {
10440 res = valuePop(ctxt);
10441 xmlXPathFreeObject(res);
10442 }
10443
10444 ctxt->context->node = NULL;
10445 }
10446
10447 /*
10448 * The result is used as the new evaluation locset.
10449 */
10450 xmlXPathFreeObject(obj);
10451 ctxt->context->node = NULL;
10452 ctxt->context->contextSize = -1;
10453 ctxt->context->proximityPosition = -1;
10454 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10455 ctxt->context->node = oldnode;
10456 return (total);
10457 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010458#endif /* LIBXML_XPTR_ENABLED */
10459
Daniel Veillardf06307e2001-07-03 10:35:50 +000010460 /*
10461 * Extract the old set, and then evaluate the result of the
10462 * expression for all the element in the set. use it to grow
10463 * up a new set.
10464 */
10465 CHECK_TYPE0(XPATH_NODESET);
10466 obj = valuePop(ctxt);
10467 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010468
Daniel Veillardf06307e2001-07-03 10:35:50 +000010469 oldnode = ctxt->context->node;
10470 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010471
Daniel Veillardf06307e2001-07-03 10:35:50 +000010472 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10473 ctxt->context->contextSize = 0;
10474 ctxt->context->proximityPosition = 0;
10475 if (op->ch2 != -1)
10476 total +=
10477 xmlXPathCompOpEval(ctxt,
10478 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010479 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010480 res = valuePop(ctxt);
10481 if (res != NULL)
10482 xmlXPathFreeObject(res);
10483 valuePush(ctxt, obj);
10484 ctxt->context->node = oldnode;
10485 CHECK_ERROR0;
10486 } else {
10487 /*
10488 * Initialize the new set.
10489 */
10490 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010491
Daniel Veillardf06307e2001-07-03 10:35:50 +000010492 for (i = 0; i < oldset->nodeNr; i++) {
10493 /*
10494 * Run the evaluation with a node list made of
10495 * a single item in the nodeset.
10496 */
10497 ctxt->context->node = oldset->nodeTab[i];
10498 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10499 valuePush(ctxt, tmp);
10500 ctxt->context->contextSize = oldset->nodeNr;
10501 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010502
Daniel Veillardf06307e2001-07-03 10:35:50 +000010503 if (op->ch2 != -1)
10504 total +=
10505 xmlXPathCompOpEval(ctxt,
10506 &comp->steps[op->ch2]);
10507 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010508
Daniel Veillardf06307e2001-07-03 10:35:50 +000010509 /*
10510 * The result of the evaluation need to be tested to
10511 * decided whether the filter succeeded or not
10512 */
10513 res = valuePop(ctxt);
10514 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10515 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10516 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010517
Daniel Veillardf06307e2001-07-03 10:35:50 +000010518 /*
10519 * Cleanup
10520 */
10521 if (res != NULL)
10522 xmlXPathFreeObject(res);
10523 if (ctxt->value == tmp) {
10524 res = valuePop(ctxt);
10525 xmlXPathFreeObject(res);
10526 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010527
Daniel Veillardf06307e2001-07-03 10:35:50 +000010528 ctxt->context->node = NULL;
10529 }
10530
10531 /*
10532 * The result is used as the new evaluation set.
10533 */
10534 xmlXPathFreeObject(obj);
10535 ctxt->context->node = NULL;
10536 ctxt->context->contextSize = -1;
10537 ctxt->context->proximityPosition = -1;
10538 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10539 }
10540 ctxt->context->node = oldnode;
10541 return (total);
10542 }
10543 case XPATH_OP_SORT:
10544 if (op->ch1 != -1)
10545 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010546 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010547 if ((ctxt->value != NULL) &&
10548 (ctxt->value->type == XPATH_NODESET) &&
10549 (ctxt->value->nodesetval != NULL))
10550 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10551 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010552#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010553 case XPATH_OP_RANGETO:{
10554 xmlXPathObjectPtr range;
10555 xmlXPathObjectPtr res, obj;
10556 xmlXPathObjectPtr tmp;
10557 xmlLocationSetPtr newset = NULL;
10558 xmlNodeSetPtr oldset;
10559 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010560
Daniel Veillardf06307e2001-07-03 10:35:50 +000010561 if (op->ch1 != -1)
10562 total +=
10563 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10564 if (op->ch2 == -1)
10565 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010566
Daniel Veillardf06307e2001-07-03 10:35:50 +000010567 CHECK_TYPE0(XPATH_NODESET);
10568 obj = valuePop(ctxt);
10569 oldset = obj->nodesetval;
10570 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010571
Daniel Veillardf06307e2001-07-03 10:35:50 +000010572 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010573
Daniel Veillardf06307e2001-07-03 10:35:50 +000010574 if (oldset != NULL) {
10575 for (i = 0; i < oldset->nodeNr; i++) {
10576 /*
10577 * Run the evaluation with a node list made of a single item
10578 * in the nodeset.
10579 */
10580 ctxt->context->node = oldset->nodeTab[i];
10581 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10582 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010583
Daniel Veillardf06307e2001-07-03 10:35:50 +000010584 if (op->ch2 != -1)
10585 total +=
10586 xmlXPathCompOpEval(ctxt,
10587 &comp->steps[op->ch2]);
10588 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010589
Daniel Veillardf06307e2001-07-03 10:35:50 +000010590 /*
10591 * The result of the evaluation need to be tested to
10592 * decided whether the filter succeeded or not
10593 */
10594 res = valuePop(ctxt);
10595 range =
10596 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10597 res);
10598 if (range != NULL) {
10599 xmlXPtrLocationSetAdd(newset, range);
10600 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010601
Daniel Veillardf06307e2001-07-03 10:35:50 +000010602 /*
10603 * Cleanup
10604 */
10605 if (res != NULL)
10606 xmlXPathFreeObject(res);
10607 if (ctxt->value == tmp) {
10608 res = valuePop(ctxt);
10609 xmlXPathFreeObject(res);
10610 }
10611
10612 ctxt->context->node = NULL;
10613 }
10614 }
10615
10616 /*
10617 * The result is used as the new evaluation set.
10618 */
10619 xmlXPathFreeObject(obj);
10620 ctxt->context->node = NULL;
10621 ctxt->context->contextSize = -1;
10622 ctxt->context->proximityPosition = -1;
10623 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10624 return (total);
10625 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010626#endif /* LIBXML_XPTR_ENABLED */
10627 }
10628 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010629 "XPath: unknown precompiled operation %d\n", op->op);
10630 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010631}
10632
10633/**
10634 * xmlXPathRunEval:
10635 * @ctxt: the XPath parser context with the compiled expression
10636 *
10637 * Evaluate the Precompiled XPath expression in the given context.
10638 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010639static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010640xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10641 xmlXPathCompExprPtr comp;
10642
10643 if ((ctxt == NULL) || (ctxt->comp == NULL))
10644 return;
10645
10646 if (ctxt->valueTab == NULL) {
10647 /* Allocate the value stack */
10648 ctxt->valueTab = (xmlXPathObjectPtr *)
10649 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10650 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010651 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010652 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010653 }
10654 ctxt->valueNr = 0;
10655 ctxt->valueMax = 10;
10656 ctxt->value = NULL;
10657 }
10658 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010659 if(comp->last < 0) {
10660 xmlGenericError(xmlGenericErrorContext,
10661 "xmlXPathRunEval: last is less than zero\n");
10662 return;
10663 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010664 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10665}
10666
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010667/************************************************************************
10668 * *
10669 * Public interfaces *
10670 * *
10671 ************************************************************************/
10672
10673/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010674 * xmlXPathEvalPredicate:
10675 * @ctxt: the XPath context
10676 * @res: the Predicate Expression evaluation result
10677 *
10678 * Evaluate a predicate result for the current node.
10679 * A PredicateExpr is evaluated by evaluating the Expr and converting
10680 * the result to a boolean. If the result is a number, the result will
10681 * be converted to true if the number is equal to the position of the
10682 * context node in the context node list (as returned by the position
10683 * function) and will be converted to false otherwise; if the result
10684 * is not a number, then the result will be converted as if by a call
10685 * to the boolean function.
10686 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010687 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010688 */
10689int
10690xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10691 if (res == NULL) return(0);
10692 switch (res->type) {
10693 case XPATH_BOOLEAN:
10694 return(res->boolval);
10695 case XPATH_NUMBER:
10696 return(res->floatval == ctxt->proximityPosition);
10697 case XPATH_NODESET:
10698 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010699 if (res->nodesetval == NULL)
10700 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010701 return(res->nodesetval->nodeNr != 0);
10702 case XPATH_STRING:
10703 return((res->stringval != NULL) &&
10704 (xmlStrlen(res->stringval) != 0));
10705 default:
10706 STRANGE
10707 }
10708 return(0);
10709}
10710
10711/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010712 * xmlXPathEvaluatePredicateResult:
10713 * @ctxt: the XPath Parser context
10714 * @res: the Predicate Expression evaluation result
10715 *
10716 * Evaluate a predicate result for the current node.
10717 * A PredicateExpr is evaluated by evaluating the Expr and converting
10718 * the result to a boolean. If the result is a number, the result will
10719 * be converted to true if the number is equal to the position of the
10720 * context node in the context node list (as returned by the position
10721 * function) and will be converted to false otherwise; if the result
10722 * is not a number, then the result will be converted as if by a call
10723 * to the boolean function.
10724 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010725 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010726 */
10727int
10728xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10729 xmlXPathObjectPtr res) {
10730 if (res == NULL) return(0);
10731 switch (res->type) {
10732 case XPATH_BOOLEAN:
10733 return(res->boolval);
10734 case XPATH_NUMBER:
10735 return(res->floatval == ctxt->context->proximityPosition);
10736 case XPATH_NODESET:
10737 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010738 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010739 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010740 return(res->nodesetval->nodeNr != 0);
10741 case XPATH_STRING:
10742 return((res->stringval != NULL) &&
10743 (xmlStrlen(res->stringval) != 0));
10744 default:
10745 STRANGE
10746 }
10747 return(0);
10748}
10749
10750/**
10751 * xmlXPathCompile:
10752 * @str: the XPath expression
10753 *
10754 * Compile an XPath expression
10755 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010756 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010757 * the caller has to free the object.
10758 */
10759xmlXPathCompExprPtr
10760xmlXPathCompile(const xmlChar *str) {
10761 xmlXPathParserContextPtr ctxt;
10762 xmlXPathCompExprPtr comp;
10763
10764 xmlXPathInit();
10765
10766 ctxt = xmlXPathNewParserContext(str, NULL);
10767 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010768
Daniel Veillard40af6492001-04-22 08:50:55 +000010769 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010770 /*
10771 * aleksey: in some cases this line prints *second* error message
10772 * (see bug #78858) and probably this should be fixed.
10773 * However, we are not sure that all error messages are printed
10774 * out in other places. It's not critical so we leave it as-is for now
10775 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010776 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10777 comp = NULL;
10778 } else {
10779 comp = ctxt->comp;
10780 ctxt->comp = NULL;
10781 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010782 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010783 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010784 comp->expr = xmlStrdup(str);
10785#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010786 comp->string = xmlStrdup(str);
10787 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010788#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010789 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010790 return(comp);
10791}
10792
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010793/**
10794 * xmlXPathCompiledEval:
10795 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010796 * @ctx: the XPath context
10797 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010798 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010799 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010800 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010801 * the caller has to free the object.
10802 */
10803xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010804xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010805 xmlXPathParserContextPtr ctxt;
10806 xmlXPathObjectPtr res, tmp, init = NULL;
10807 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010808#ifndef LIBXML_THREAD_ENABLED
10809 static int reentance = 0;
10810#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010811
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010812 if ((comp == NULL) || (ctx == NULL))
10813 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010814 xmlXPathInit();
10815
10816 CHECK_CONTEXT(ctx)
10817
Daniel Veillard81463942001-10-16 12:34:39 +000010818#ifndef LIBXML_THREAD_ENABLED
10819 reentance++;
10820 if (reentance > 1)
10821 xmlXPathDisableOptimizer = 1;
10822#endif
10823
Daniel Veillardf06307e2001-07-03 10:35:50 +000010824#ifdef DEBUG_EVAL_COUNTS
10825 comp->nb++;
10826 if ((comp->string != NULL) && (comp->nb > 100)) {
10827 fprintf(stderr, "100 x %s\n", comp->string);
10828 comp->nb = 0;
10829 }
10830#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010831 ctxt = xmlXPathCompParserContext(comp, ctx);
10832 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010833
10834 if (ctxt->value == NULL) {
10835 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010836 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010837 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010838 } else {
10839 res = valuePop(ctxt);
10840 }
10841
Daniel Veillardf06307e2001-07-03 10:35:50 +000010842
Owen Taylor3473f882001-02-23 17:55:21 +000010843 do {
10844 tmp = valuePop(ctxt);
10845 if (tmp != NULL) {
10846 if (tmp != init)
10847 stack++;
10848 xmlXPathFreeObject(tmp);
10849 }
10850 } while (tmp != NULL);
10851 if ((stack != 0) && (res != NULL)) {
10852 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010853 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010854 stack);
10855 }
10856 if (ctxt->error != XPATH_EXPRESSION_OK) {
10857 xmlXPathFreeObject(res);
10858 res = NULL;
10859 }
10860
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010861
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010862 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010863 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010864#ifndef LIBXML_THREAD_ENABLED
10865 reentance--;
10866#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010867 return(res);
10868}
10869
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010870/**
10871 * xmlXPathEvalExpr:
10872 * @ctxt: the XPath Parser context
10873 *
10874 * Parse and evaluate an XPath expression in the given context,
10875 * then push the result on the context stack
10876 */
10877void
10878xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10879 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010880 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010881 xmlXPathRunEval(ctxt);
10882}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010883
10884/**
10885 * xmlXPathEval:
10886 * @str: the XPath expression
10887 * @ctx: the XPath context
10888 *
10889 * Evaluate the XPath Location Path in the given context.
10890 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010891 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010892 * the caller has to free the object.
10893 */
10894xmlXPathObjectPtr
10895xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10896 xmlXPathParserContextPtr ctxt;
10897 xmlXPathObjectPtr res, tmp, init = NULL;
10898 int stack = 0;
10899
10900 xmlXPathInit();
10901
10902 CHECK_CONTEXT(ctx)
10903
10904 ctxt = xmlXPathNewParserContext(str, ctx);
10905 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010906
10907 if (ctxt->value == NULL) {
10908 xmlGenericError(xmlGenericErrorContext,
10909 "xmlXPathEval: evaluation failed\n");
10910 res = NULL;
10911 } else if (*ctxt->cur != 0) {
10912 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10913 res = NULL;
10914 } else {
10915 res = valuePop(ctxt);
10916 }
10917
10918 do {
10919 tmp = valuePop(ctxt);
10920 if (tmp != NULL) {
10921 if (tmp != init)
10922 stack++;
10923 xmlXPathFreeObject(tmp);
10924 }
10925 } while (tmp != NULL);
10926 if ((stack != 0) && (res != NULL)) {
10927 xmlGenericError(xmlGenericErrorContext,
10928 "xmlXPathEval: %d object left on the stack\n",
10929 stack);
10930 }
10931 if (ctxt->error != XPATH_EXPRESSION_OK) {
10932 xmlXPathFreeObject(res);
10933 res = NULL;
10934 }
10935
Owen Taylor3473f882001-02-23 17:55:21 +000010936 xmlXPathFreeParserContext(ctxt);
10937 return(res);
10938}
10939
10940/**
10941 * xmlXPathEvalExpression:
10942 * @str: the XPath expression
10943 * @ctxt: the XPath context
10944 *
10945 * Evaluate the XPath expression in the given context.
10946 *
10947 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10948 * the caller has to free the object.
10949 */
10950xmlXPathObjectPtr
10951xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10952 xmlXPathParserContextPtr pctxt;
10953 xmlXPathObjectPtr res, tmp;
10954 int stack = 0;
10955
10956 xmlXPathInit();
10957
10958 CHECK_CONTEXT(ctxt)
10959
10960 pctxt = xmlXPathNewParserContext(str, ctxt);
10961 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010962
10963 if (*pctxt->cur != 0) {
10964 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10965 res = NULL;
10966 } else {
10967 res = valuePop(pctxt);
10968 }
10969 do {
10970 tmp = valuePop(pctxt);
10971 if (tmp != NULL) {
10972 xmlXPathFreeObject(tmp);
10973 stack++;
10974 }
10975 } while (tmp != NULL);
10976 if ((stack != 0) && (res != NULL)) {
10977 xmlGenericError(xmlGenericErrorContext,
10978 "xmlXPathEvalExpression: %d object left on the stack\n",
10979 stack);
10980 }
10981 xmlXPathFreeParserContext(pctxt);
10982 return(res);
10983}
10984
Daniel Veillard42766c02002-08-22 20:52:17 +000010985/************************************************************************
10986 * *
10987 * Extra functions not pertaining to the XPath spec *
10988 * *
10989 ************************************************************************/
10990/**
10991 * xmlXPathEscapeUriFunction:
10992 * @ctxt: the XPath Parser context
10993 * @nargs: the number of arguments
10994 *
10995 * Implement the escape-uri() XPath function
10996 * string escape-uri(string $str, bool $escape-reserved)
10997 *
10998 * This function applies the URI escaping rules defined in section 2 of [RFC
10999 * 2396] to the string supplied as $uri-part, which typically represents all
11000 * or part of a URI. The effect of the function is to replace any special
11001 * character in the string by an escape sequence of the form %xx%yy...,
11002 * where xxyy... is the hexadecimal representation of the octets used to
11003 * represent the character in UTF-8.
11004 *
11005 * The set of characters that are escaped depends on the setting of the
11006 * boolean argument $escape-reserved.
11007 *
11008 * If $escape-reserved is true, all characters are escaped other than lower
11009 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11010 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11011 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11012 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11013 * A-F).
11014 *
11015 * If $escape-reserved is false, the behavior differs in that characters
11016 * referred to in [RFC 2396] as reserved characters are not escaped. These
11017 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11018 *
11019 * [RFC 2396] does not define whether escaped URIs should use lower case or
11020 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11021 * compared using string comparison functions, this function must always use
11022 * the upper-case letters A-F.
11023 *
11024 * Generally, $escape-reserved should be set to true when escaping a string
11025 * that is to form a single part of a URI, and to false when escaping an
11026 * entire URI or URI reference.
11027 *
11028 * In the case of non-ascii characters, the string is encoded according to
11029 * utf-8 and then converted according to RFC 2396.
11030 *
11031 * Examples
11032 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11033 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11034 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11035 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11036 *
11037 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011038static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011039xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11040 xmlXPathObjectPtr str;
11041 int escape_reserved;
11042 xmlBufferPtr target;
11043 xmlChar *cptr;
11044 xmlChar escape[4];
11045
11046 CHECK_ARITY(2);
11047
11048 escape_reserved = xmlXPathPopBoolean(ctxt);
11049
11050 CAST_TO_STRING;
11051 str = valuePop(ctxt);
11052
11053 target = xmlBufferCreate();
11054
11055 escape[0] = '%';
11056 escape[3] = 0;
11057
11058 if (target) {
11059 for (cptr = str->stringval; *cptr; cptr++) {
11060 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11061 (*cptr >= 'a' && *cptr <= 'z') ||
11062 (*cptr >= '0' && *cptr <= '9') ||
11063 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11064 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11065 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11066 (*cptr == '%' &&
11067 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11068 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11069 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11070 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11071 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11072 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11073 (!escape_reserved &&
11074 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11075 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11076 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11077 *cptr == ','))) {
11078 xmlBufferAdd(target, cptr, 1);
11079 } else {
11080 if ((*cptr >> 4) < 10)
11081 escape[1] = '0' + (*cptr >> 4);
11082 else
11083 escape[1] = 'A' - 10 + (*cptr >> 4);
11084 if ((*cptr & 0xF) < 10)
11085 escape[2] = '0' + (*cptr & 0xF);
11086 else
11087 escape[2] = 'A' - 10 + (*cptr & 0xF);
11088
11089 xmlBufferAdd(target, &escape[0], 3);
11090 }
11091 }
11092 }
11093 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11094 xmlBufferFree(target);
11095 xmlXPathFreeObject(str);
11096}
11097
Owen Taylor3473f882001-02-23 17:55:21 +000011098/**
11099 * xmlXPathRegisterAllFunctions:
11100 * @ctxt: the XPath context
11101 *
11102 * Registers all default XPath functions in this context
11103 */
11104void
11105xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11106{
11107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11108 xmlXPathBooleanFunction);
11109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11110 xmlXPathCeilingFunction);
11111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11112 xmlXPathCountFunction);
11113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11114 xmlXPathConcatFunction);
11115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11116 xmlXPathContainsFunction);
11117 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11118 xmlXPathIdFunction);
11119 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11120 xmlXPathFalseFunction);
11121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11122 xmlXPathFloorFunction);
11123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11124 xmlXPathLastFunction);
11125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11126 xmlXPathLangFunction);
11127 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11128 xmlXPathLocalNameFunction);
11129 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11130 xmlXPathNotFunction);
11131 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11132 xmlXPathNameFunction);
11133 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11134 xmlXPathNamespaceURIFunction);
11135 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11136 xmlXPathNormalizeFunction);
11137 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11138 xmlXPathNumberFunction);
11139 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11140 xmlXPathPositionFunction);
11141 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11142 xmlXPathRoundFunction);
11143 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11144 xmlXPathStringFunction);
11145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11146 xmlXPathStringLengthFunction);
11147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11148 xmlXPathStartsWithFunction);
11149 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11150 xmlXPathSubstringFunction);
11151 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11152 xmlXPathSubstringBeforeFunction);
11153 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11154 xmlXPathSubstringAfterFunction);
11155 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11156 xmlXPathSumFunction);
11157 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11158 xmlXPathTrueFunction);
11159 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11160 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011161
11162 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11163 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11164 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011165}
11166
11167#endif /* LIBXML_XPATH_ENABLED */