blob: fd97498129566d006cb7075b59beb1b924689896 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000054
Daniel Veillardd96f6d32003-10-07 21:25:12 +000055#define TODO \
56 xmlGenericError(xmlGenericErrorContext, \
57 "Unimplemented block at %s:%d\n", \
58 __FILE__, __LINE__);
59
Daniel Veillard4432df22003-09-28 18:58:27 +000060#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000061/************************************************************************
62 * *
63 * Floating point stuff *
64 * *
65 ************************************************************************/
66
Daniel Veillardc0631a62001-09-20 13:56:06 +000067#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000068#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000069#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000070#include "trionan.c"
71
Owen Taylor3473f882001-02-23 17:55:21 +000072/*
Owen Taylor3473f882001-02-23 17:55:21 +000073 * The lack of portability of this section of the libc is annoying !
74 */
75double xmlXPathNAN = 0;
76double xmlXPathPINF = 1;
77double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000078double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000079static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000080
Owen Taylor3473f882001-02-23 17:55:21 +000081/**
82 * xmlXPathInit:
83 *
84 * Initialize the XPath environment
85 */
86void
87xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000088 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000089
Bjorn Reese45029602001-08-21 09:23:53 +000090 xmlXPathPINF = trio_pinf();
91 xmlXPathNINF = trio_ninf();
92 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +000093 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +000094
Daniel Veillard20ee8c02001-10-05 09:18:14 +000095 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000096}
97
Daniel Veillardcda96922001-08-21 10:56:31 +000098/**
99 * xmlXPathIsNaN:
100 * @val: a double value
101 *
102 * Provides a portable isnan() function to detect whether a double
103 * is a NotaNumber. Based on trio code
104 * http://sourceforge.net/projects/ctrio/
105 *
106 * Returns 1 if the value is a NaN, 0 otherwise
107 */
108int
109xmlXPathIsNaN(double val) {
110 return(trio_isnan(val));
111}
112
113/**
114 * xmlXPathIsInf:
115 * @val: a double value
116 *
117 * Provides a portable isinf() function to detect whether a double
118 * is a +Infinite or -Infinite. Based on trio code
119 * http://sourceforge.net/projects/ctrio/
120 *
121 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
122 */
123int
124xmlXPathIsInf(double val) {
125 return(trio_isinf(val));
126}
127
Daniel Veillard4432df22003-09-28 18:58:27 +0000128#endif /* SCHEMAS or XPATH */
129#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000130/**
131 * xmlXPathGetSign:
132 * @val: a double value
133 *
134 * Provides a portable function to detect the sign of a double
135 * Modified from trio code
136 * http://sourceforge.net/projects/ctrio/
137 *
138 * Returns 1 if the value is Negative, 0 if positive
139 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000140static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000141xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000142 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000143}
144
145
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000146/*
147 * TODO: when compatibility allows remove all "fake node libxslt" strings
148 * the test should just be name[0] = ' '
149 */
150/* #define DEBUG */
151/* #define DEBUG_STEP */
152/* #define DEBUG_STEP_NTH */
153/* #define DEBUG_EXPR */
154/* #define DEBUG_EVAL_COUNTS */
155
156static xmlNs xmlXPathXMLNamespaceStruct = {
157 NULL,
158 XML_NAMESPACE_DECL,
159 XML_XML_NAMESPACE,
160 BAD_CAST "xml",
161 NULL
162};
163static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
164#ifndef LIBXML_THREAD_ENABLED
165/*
166 * Optimizer is disabled only when threaded apps are detected while
167 * the library ain't compiled for thread safety.
168 */
169static int xmlXPathDisableOptimizer = 0;
170#endif
171
Owen Taylor3473f882001-02-23 17:55:21 +0000172/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000173 * *
174 * Error handling routines *
175 * *
176 ************************************************************************/
177
178
179static const char *xmlXPathErrorMessages[] = {
180 "Ok\n",
181 "Number encoding\n",
182 "Unfinished literal\n",
183 "Start of literal\n",
184 "Expected $ for variable reference\n",
185 "Undefined variable\n",
186 "Invalid predicate\n",
187 "Invalid expression\n",
188 "Missing closing curly brace\n",
189 "Unregistered function\n",
190 "Invalid operand\n",
191 "Invalid type\n",
192 "Invalid number of arguments\n",
193 "Invalid context size\n",
194 "Invalid context position\n",
195 "Memory allocation error\n",
196 "Syntax error\n",
197 "Resource error\n",
198 "Sub resource error\n",
199 "Undefined namespace prefix\n",
200 "Encoding error\n",
201 "Char out of XML range\n"
202};
203
204
205/**
206 * xmlXPathErrMemory:
207 * @ctxt: an XPath context
208 * @extra: extra informations
209 *
210 * Handle a redefinition of attribute error
211 */
212static void
213xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
214{
215 if (ctxt != NULL) {
216 if (extra) {
217 xmlChar buf[200];
218
219 xmlStrPrintf(buf, 200,
220 BAD_CAST "Memory allocation failed : %s\n",
221 extra);
222 ctxt->lastError.message = (char *) xmlStrdup(buf);
223 } else {
224 ctxt->lastError.message = (char *)
225 xmlStrdup(BAD_CAST "Memory allocation failed\n");
226 }
227 ctxt->lastError.domain = XML_FROM_XPATH;
228 ctxt->lastError.code = XML_ERR_NO_MEMORY;
229 if (ctxt->error != NULL)
230 ctxt->error(ctxt->userData, &ctxt->lastError);
231 } else {
232 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000233 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000234 NULL, NULL, XML_FROM_XPATH,
235 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
236 extra, NULL, NULL, 0, 0,
237 "Memory allocation failed : %s\n", extra);
238 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000239 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000240 NULL, NULL, XML_FROM_XPATH,
241 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
242 NULL, NULL, NULL, 0, 0,
243 "Memory allocation failed\n");
244 }
245}
246
247/**
248 * xmlXPathErrMemory:
249 * @ctxt: an XPath parser context
250 * @extra: extra informations
251 *
252 * Handle a redefinition of attribute error
253 */
254static void
255xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
256{
257 ctxt->error = XPATH_MEMORY_ERROR;
258 if (ctxt == NULL)
259 xmlXPathErrMemory(NULL, extra);
260 else
261 xmlXPathErrMemory(ctxt->context, extra);
262}
263
264/**
265 * xmlXPathErr:
266 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000267 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000268 *
269 * Handle a Relax NG Parsing error
270 */
271void
272xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
273{
274 if (ctxt != NULL)
275 ctxt->error = error;
276 if ((ctxt == NULL) || (ctxt->context == NULL)) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000277 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000278 NULL, NULL, XML_FROM_XPATH,
279 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
280 XML_ERR_ERROR, NULL, 0,
281 NULL, NULL, NULL, 0, 0,
282 xmlXPathErrorMessages[error]);
283 return;
284 }
285 ctxt->context->lastError.domain = XML_FROM_XPATH;
286 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
287 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000288 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000289 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
290 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
291 ctxt->context->lastError.node = ctxt->context->debugNode;
292 if (ctxt->context->error != NULL) {
293 ctxt->context->error(ctxt->context->userData,
294 &ctxt->context->lastError);
295 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000296 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000297 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
298 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
299 XML_ERR_ERROR, NULL, 0,
300 (const char *) ctxt->base, NULL, NULL,
301 ctxt->cur - ctxt->base, 0,
302 xmlXPathErrorMessages[error]);
303 }
304
305}
306
307/**
308 * xmlXPatherror:
309 * @ctxt: the XPath Parser context
310 * @file: the file name
311 * @line: the line number
312 * @no: the error number
313 *
314 * Formats an error message.
315 */
316void
317xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
318 int line ATTRIBUTE_UNUSED, int no) {
319 xmlXPathErr(ctxt, no);
320}
321
322
323/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000324 * *
325 * Parser Types *
326 * *
327 ************************************************************************/
328
329/*
330 * Types are private:
331 */
332
333typedef enum {
334 XPATH_OP_END=0,
335 XPATH_OP_AND,
336 XPATH_OP_OR,
337 XPATH_OP_EQUAL,
338 XPATH_OP_CMP,
339 XPATH_OP_PLUS,
340 XPATH_OP_MULT,
341 XPATH_OP_UNION,
342 XPATH_OP_ROOT,
343 XPATH_OP_NODE,
344 XPATH_OP_RESET,
345 XPATH_OP_COLLECT,
346 XPATH_OP_VALUE,
347 XPATH_OP_VARIABLE,
348 XPATH_OP_FUNCTION,
349 XPATH_OP_ARG,
350 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000351 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000352 XPATH_OP_SORT
353#ifdef LIBXML_XPTR_ENABLED
354 ,XPATH_OP_RANGETO
355#endif
356} xmlXPathOp;
357
358typedef enum {
359 AXIS_ANCESTOR = 1,
360 AXIS_ANCESTOR_OR_SELF,
361 AXIS_ATTRIBUTE,
362 AXIS_CHILD,
363 AXIS_DESCENDANT,
364 AXIS_DESCENDANT_OR_SELF,
365 AXIS_FOLLOWING,
366 AXIS_FOLLOWING_SIBLING,
367 AXIS_NAMESPACE,
368 AXIS_PARENT,
369 AXIS_PRECEDING,
370 AXIS_PRECEDING_SIBLING,
371 AXIS_SELF
372} xmlXPathAxisVal;
373
374typedef enum {
375 NODE_TEST_NONE = 0,
376 NODE_TEST_TYPE = 1,
377 NODE_TEST_PI = 2,
378 NODE_TEST_ALL = 3,
379 NODE_TEST_NS = 4,
380 NODE_TEST_NAME = 5
381} xmlXPathTestVal;
382
383typedef enum {
384 NODE_TYPE_NODE = 0,
385 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
386 NODE_TYPE_TEXT = XML_TEXT_NODE,
387 NODE_TYPE_PI = XML_PI_NODE
388} xmlXPathTypeVal;
389
390
391typedef struct _xmlXPathStepOp xmlXPathStepOp;
392typedef xmlXPathStepOp *xmlXPathStepOpPtr;
393struct _xmlXPathStepOp {
394 xmlXPathOp op;
395 int ch1;
396 int ch2;
397 int value;
398 int value2;
399 int value3;
400 void *value4;
401 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000402 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000403 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000404};
405
406struct _xmlXPathCompExpr {
407 int nbStep;
408 int maxStep;
409 xmlXPathStepOp *steps; /* ops for computation */
410 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000411 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000412#ifdef DEBUG_EVAL_COUNTS
413 int nb;
414 xmlChar *string;
415#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000416};
417
418/************************************************************************
419 * *
420 * Parser Type functions *
421 * *
422 ************************************************************************/
423
424/**
425 * xmlXPathNewCompExpr:
426 *
427 * Create a new Xpath component
428 *
429 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
430 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000431static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000432xmlXPathNewCompExpr(void) {
433 xmlXPathCompExprPtr cur;
434
435 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
436 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000437 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000438 return(NULL);
439 }
440 memset(cur, 0, sizeof(xmlXPathCompExpr));
441 cur->maxStep = 10;
442 cur->nbStep = 0;
443 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
444 sizeof(xmlXPathStepOp));
445 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000446 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000447 xmlFree(cur);
448 return(NULL);
449 }
450 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
451 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000452#ifdef DEBUG_EVAL_COUNTS
453 cur->nb = 0;
454#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000455 return(cur);
456}
457
458/**
459 * xmlXPathFreeCompExpr:
460 * @comp: an XPATH comp
461 *
462 * Free up the memory allocated by @comp
463 */
464void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000465xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
466{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000467 xmlXPathStepOpPtr op;
468 int i;
469
470 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000471 return;
472 for (i = 0; i < comp->nbStep; i++) {
473 op = &comp->steps[i];
474 if (op->value4 != NULL) {
475 if (op->op == XPATH_OP_VALUE)
476 xmlXPathFreeObject(op->value4);
477 else
478 xmlFree(op->value4);
479 }
480 if (op->value5 != NULL)
481 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000482 }
483 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000484 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000485 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000486#ifdef DEBUG_EVAL_COUNTS
487 if (comp->string != NULL) {
488 xmlFree(comp->string);
489 }
490#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000491 if (comp->expr != NULL) {
492 xmlFree(comp->expr);
493 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000494
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000495 xmlFree(comp);
496}
497
498/**
499 * xmlXPathCompExprAdd:
500 * @comp: the compiled expression
501 * @ch1: first child index
502 * @ch2: second child index
503 * @op: an op
504 * @value: the first int value
505 * @value2: the second int value
506 * @value3: the third int value
507 * @value4: the first string value
508 * @value5: the second string value
509 *
510 * Add an step to an XPath Compiled Expression
511 *
512 * Returns -1 in case of failure, the index otherwise
513 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000514static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000515xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
516 xmlXPathOp op, int value,
517 int value2, int value3, void *value4, void *value5) {
518 if (comp->nbStep >= comp->maxStep) {
519 xmlXPathStepOp *real;
520
521 comp->maxStep *= 2;
522 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
523 comp->maxStep * sizeof(xmlXPathStepOp));
524 if (real == NULL) {
525 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000526 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000527 return(-1);
528 }
529 comp->steps = real;
530 }
531 comp->last = comp->nbStep;
532 comp->steps[comp->nbStep].ch1 = ch1;
533 comp->steps[comp->nbStep].ch2 = ch2;
534 comp->steps[comp->nbStep].op = op;
535 comp->steps[comp->nbStep].value = value;
536 comp->steps[comp->nbStep].value2 = value2;
537 comp->steps[comp->nbStep].value3 = value3;
538 comp->steps[comp->nbStep].value4 = value4;
539 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000540 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000541 return(comp->nbStep++);
542}
543
Daniel Veillardf06307e2001-07-03 10:35:50 +0000544/**
545 * xmlXPathCompSwap:
546 * @comp: the compiled expression
547 * @op: operation index
548 *
549 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000550 */
551static void
552xmlXPathCompSwap(xmlXPathStepOpPtr op) {
553 int tmp;
554
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000555#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000556 /*
557 * Since this manipulates possibly shared variables, this is
558 * disable if one detects that the library is used in a multithreaded
559 * application
560 */
561 if (xmlXPathDisableOptimizer)
562 return;
563#endif
564
Daniel Veillardf06307e2001-07-03 10:35:50 +0000565 tmp = op->ch1;
566 op->ch1 = op->ch2;
567 op->ch2 = tmp;
568}
569
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000570#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
571 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
572 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000573#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
574 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
575 (op), (val), (val2), (val3), (val4), (val5))
576
577#define PUSH_LEAVE_EXPR(op, val, val2) \
578xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
579
580#define PUSH_UNARY_EXPR(op, ch, val, val2) \
581xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
582
583#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
584xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
585
586/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000587 * *
588 * Debugging related functions *
589 * *
590 ************************************************************************/
591
Owen Taylor3473f882001-02-23 17:55:21 +0000592#define STRANGE \
593 xmlGenericError(xmlGenericErrorContext, \
594 "Internal error at %s:%d\n", \
595 __FILE__, __LINE__);
596
597#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000598static void
599xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000600 int i;
601 char shift[100];
602
603 for (i = 0;((i < depth) && (i < 25));i++)
604 shift[2 * i] = shift[2 * i + 1] = ' ';
605 shift[2 * i] = shift[2 * i + 1] = 0;
606 if (cur == NULL) {
607 fprintf(output, shift);
608 fprintf(output, "Node is NULL !\n");
609 return;
610
611 }
612
613 if ((cur->type == XML_DOCUMENT_NODE) ||
614 (cur->type == XML_HTML_DOCUMENT_NODE)) {
615 fprintf(output, shift);
616 fprintf(output, " /\n");
617 } else if (cur->type == XML_ATTRIBUTE_NODE)
618 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
619 else
620 xmlDebugDumpOneNode(output, cur, depth);
621}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000622static void
623xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000624 xmlNodePtr tmp;
625 int i;
626 char shift[100];
627
628 for (i = 0;((i < depth) && (i < 25));i++)
629 shift[2 * i] = shift[2 * i + 1] = ' ';
630 shift[2 * i] = shift[2 * i + 1] = 0;
631 if (cur == NULL) {
632 fprintf(output, shift);
633 fprintf(output, "Node is NULL !\n");
634 return;
635
636 }
637
638 while (cur != NULL) {
639 tmp = cur;
640 cur = cur->next;
641 xmlDebugDumpOneNode(output, tmp, depth);
642 }
643}
Owen Taylor3473f882001-02-23 17:55:21 +0000644
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000645static void
646xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000647 int i;
648 char shift[100];
649
650 for (i = 0;((i < depth) && (i < 25));i++)
651 shift[2 * i] = shift[2 * i + 1] = ' ';
652 shift[2 * i] = shift[2 * i + 1] = 0;
653
654 if (cur == NULL) {
655 fprintf(output, shift);
656 fprintf(output, "NodeSet is NULL !\n");
657 return;
658
659 }
660
Daniel Veillard911f49a2001-04-07 15:39:35 +0000661 if (cur != NULL) {
662 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
663 for (i = 0;i < cur->nodeNr;i++) {
664 fprintf(output, shift);
665 fprintf(output, "%d", i + 1);
666 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
667 }
Owen Taylor3473f882001-02-23 17:55:21 +0000668 }
669}
670
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000671static void
672xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000673 int i;
674 char shift[100];
675
676 for (i = 0;((i < depth) && (i < 25));i++)
677 shift[2 * i] = shift[2 * i + 1] = ' ';
678 shift[2 * i] = shift[2 * i + 1] = 0;
679
680 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
681 fprintf(output, shift);
682 fprintf(output, "Value Tree is NULL !\n");
683 return;
684
685 }
686
687 fprintf(output, shift);
688 fprintf(output, "%d", i + 1);
689 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
690}
Owen Taylor3473f882001-02-23 17:55:21 +0000691#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000692static void
693xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000694 int i;
695 char shift[100];
696
697 for (i = 0;((i < depth) && (i < 25));i++)
698 shift[2 * i] = shift[2 * i + 1] = ' ';
699 shift[2 * i] = shift[2 * i + 1] = 0;
700
701 if (cur == NULL) {
702 fprintf(output, shift);
703 fprintf(output, "LocationSet is NULL !\n");
704 return;
705
706 }
707
708 for (i = 0;i < cur->locNr;i++) {
709 fprintf(output, shift);
710 fprintf(output, "%d : ", i + 1);
711 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
712 }
713}
Daniel Veillard017b1082001-06-21 11:20:21 +0000714#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000715
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000716/**
717 * xmlXPathDebugDumpObject:
718 * @output: the FILE * to dump the output
719 * @cur: the object to inspect
720 * @depth: indentation level
721 *
722 * Dump the content of the object for debugging purposes
723 */
724void
725xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000726 int i;
727 char shift[100];
728
729 for (i = 0;((i < depth) && (i < 25));i++)
730 shift[2 * i] = shift[2 * i + 1] = ' ';
731 shift[2 * i] = shift[2 * i + 1] = 0;
732
733 fprintf(output, shift);
734
735 if (cur == NULL) {
736 fprintf(output, "Object is empty (NULL)\n");
737 return;
738 }
739 switch(cur->type) {
740 case XPATH_UNDEFINED:
741 fprintf(output, "Object is uninitialized\n");
742 break;
743 case XPATH_NODESET:
744 fprintf(output, "Object is a Node Set :\n");
745 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
746 break;
747 case XPATH_XSLT_TREE:
748 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000749 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000750 break;
751 case XPATH_BOOLEAN:
752 fprintf(output, "Object is a Boolean : ");
753 if (cur->boolval) fprintf(output, "true\n");
754 else fprintf(output, "false\n");
755 break;
756 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000757 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000758 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000759 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000760 break;
761 case -1:
762 fprintf(output, "Object is a number : -Infinity\n");
763 break;
764 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000765 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000766 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000767 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
768 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000769 } else {
770 fprintf(output, "Object is a number : %0g\n", cur->floatval);
771 }
772 }
Owen Taylor3473f882001-02-23 17:55:21 +0000773 break;
774 case XPATH_STRING:
775 fprintf(output, "Object is a string : ");
776 xmlDebugDumpString(output, cur->stringval);
777 fprintf(output, "\n");
778 break;
779 case XPATH_POINT:
780 fprintf(output, "Object is a point : index %d in node", cur->index);
781 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
782 fprintf(output, "\n");
783 break;
784 case XPATH_RANGE:
785 if ((cur->user2 == NULL) ||
786 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
787 fprintf(output, "Object is a collapsed range :\n");
788 fprintf(output, shift);
789 if (cur->index >= 0)
790 fprintf(output, "index %d in ", cur->index);
791 fprintf(output, "node\n");
792 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
793 depth + 1);
794 } else {
795 fprintf(output, "Object is a range :\n");
796 fprintf(output, shift);
797 fprintf(output, "From ");
798 if (cur->index >= 0)
799 fprintf(output, "index %d in ", cur->index);
800 fprintf(output, "node\n");
801 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
802 depth + 1);
803 fprintf(output, shift);
804 fprintf(output, "To ");
805 if (cur->index2 >= 0)
806 fprintf(output, "index %d in ", cur->index2);
807 fprintf(output, "node\n");
808 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
809 depth + 1);
810 fprintf(output, "\n");
811 }
812 break;
813 case XPATH_LOCATIONSET:
814#if defined(LIBXML_XPTR_ENABLED)
815 fprintf(output, "Object is a Location Set:\n");
816 xmlXPathDebugDumpLocationSet(output,
817 (xmlLocationSetPtr) cur->user, depth);
818#endif
819 break;
820 case XPATH_USERS:
821 fprintf(output, "Object is user defined\n");
822 break;
823 }
824}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000825
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000826static void
827xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000828 xmlXPathStepOpPtr op, int depth) {
829 int i;
830 char shift[100];
831
832 for (i = 0;((i < depth) && (i < 25));i++)
833 shift[2 * i] = shift[2 * i + 1] = ' ';
834 shift[2 * i] = shift[2 * i + 1] = 0;
835
836 fprintf(output, shift);
837 if (op == NULL) {
838 fprintf(output, "Step is NULL\n");
839 return;
840 }
841 switch (op->op) {
842 case XPATH_OP_END:
843 fprintf(output, "END"); break;
844 case XPATH_OP_AND:
845 fprintf(output, "AND"); break;
846 case XPATH_OP_OR:
847 fprintf(output, "OR"); break;
848 case XPATH_OP_EQUAL:
849 if (op->value)
850 fprintf(output, "EQUAL =");
851 else
852 fprintf(output, "EQUAL !=");
853 break;
854 case XPATH_OP_CMP:
855 if (op->value)
856 fprintf(output, "CMP <");
857 else
858 fprintf(output, "CMP >");
859 if (!op->value2)
860 fprintf(output, "=");
861 break;
862 case XPATH_OP_PLUS:
863 if (op->value == 0)
864 fprintf(output, "PLUS -");
865 else if (op->value == 1)
866 fprintf(output, "PLUS +");
867 else if (op->value == 2)
868 fprintf(output, "PLUS unary -");
869 else if (op->value == 3)
870 fprintf(output, "PLUS unary - -");
871 break;
872 case XPATH_OP_MULT:
873 if (op->value == 0)
874 fprintf(output, "MULT *");
875 else if (op->value == 1)
876 fprintf(output, "MULT div");
877 else
878 fprintf(output, "MULT mod");
879 break;
880 case XPATH_OP_UNION:
881 fprintf(output, "UNION"); break;
882 case XPATH_OP_ROOT:
883 fprintf(output, "ROOT"); break;
884 case XPATH_OP_NODE:
885 fprintf(output, "NODE"); break;
886 case XPATH_OP_RESET:
887 fprintf(output, "RESET"); break;
888 case XPATH_OP_SORT:
889 fprintf(output, "SORT"); break;
890 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000891 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
892 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
893 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000894 const xmlChar *prefix = op->value4;
895 const xmlChar *name = op->value5;
896
897 fprintf(output, "COLLECT ");
898 switch (axis) {
899 case AXIS_ANCESTOR:
900 fprintf(output, " 'ancestors' "); break;
901 case AXIS_ANCESTOR_OR_SELF:
902 fprintf(output, " 'ancestors-or-self' "); break;
903 case AXIS_ATTRIBUTE:
904 fprintf(output, " 'attributes' "); break;
905 case AXIS_CHILD:
906 fprintf(output, " 'child' "); break;
907 case AXIS_DESCENDANT:
908 fprintf(output, " 'descendant' "); break;
909 case AXIS_DESCENDANT_OR_SELF:
910 fprintf(output, " 'descendant-or-self' "); break;
911 case AXIS_FOLLOWING:
912 fprintf(output, " 'following' "); break;
913 case AXIS_FOLLOWING_SIBLING:
914 fprintf(output, " 'following-siblings' "); break;
915 case AXIS_NAMESPACE:
916 fprintf(output, " 'namespace' "); break;
917 case AXIS_PARENT:
918 fprintf(output, " 'parent' "); break;
919 case AXIS_PRECEDING:
920 fprintf(output, " 'preceding' "); break;
921 case AXIS_PRECEDING_SIBLING:
922 fprintf(output, " 'preceding-sibling' "); break;
923 case AXIS_SELF:
924 fprintf(output, " 'self' "); break;
925 }
926 switch (test) {
927 case NODE_TEST_NONE:
928 fprintf(output, "'none' "); break;
929 case NODE_TEST_TYPE:
930 fprintf(output, "'type' "); break;
931 case NODE_TEST_PI:
932 fprintf(output, "'PI' "); break;
933 case NODE_TEST_ALL:
934 fprintf(output, "'all' "); break;
935 case NODE_TEST_NS:
936 fprintf(output, "'namespace' "); break;
937 case NODE_TEST_NAME:
938 fprintf(output, "'name' "); break;
939 }
940 switch (type) {
941 case NODE_TYPE_NODE:
942 fprintf(output, "'node' "); break;
943 case NODE_TYPE_COMMENT:
944 fprintf(output, "'comment' "); break;
945 case NODE_TYPE_TEXT:
946 fprintf(output, "'text' "); break;
947 case NODE_TYPE_PI:
948 fprintf(output, "'PI' "); break;
949 }
950 if (prefix != NULL)
951 fprintf(output, "%s:", prefix);
952 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000953 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000954 break;
955
956 }
957 case XPATH_OP_VALUE: {
958 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
959
960 fprintf(output, "ELEM ");
961 xmlXPathDebugDumpObject(output, object, 0);
962 goto finish;
963 }
964 case XPATH_OP_VARIABLE: {
965 const xmlChar *prefix = op->value5;
966 const xmlChar *name = op->value4;
967
968 if (prefix != NULL)
969 fprintf(output, "VARIABLE %s:%s", prefix, name);
970 else
971 fprintf(output, "VARIABLE %s", name);
972 break;
973 }
974 case XPATH_OP_FUNCTION: {
975 int nbargs = op->value;
976 const xmlChar *prefix = op->value5;
977 const xmlChar *name = op->value4;
978
979 if (prefix != NULL)
980 fprintf(output, "FUNCTION %s:%s(%d args)",
981 prefix, name, nbargs);
982 else
983 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
984 break;
985 }
986 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
987 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000988 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000989#ifdef LIBXML_XPTR_ENABLED
990 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
991#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000992 default:
993 fprintf(output, "UNKNOWN %d\n", op->op); return;
994 }
995 fprintf(output, "\n");
996finish:
997 if (op->ch1 >= 0)
998 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
999 if (op->ch2 >= 0)
1000 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1001}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001002
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001003/**
1004 * xmlXPathDebugDumpCompExpr:
1005 * @output: the FILE * for the output
1006 * @comp: the precompiled XPath expression
1007 * @depth: the indentation level.
1008 *
1009 * Dumps the tree of the compiled XPath expression.
1010 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001011void
1012xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1013 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001014 int i;
1015 char shift[100];
1016
1017 for (i = 0;((i < depth) && (i < 25));i++)
1018 shift[2 * i] = shift[2 * i + 1] = ' ';
1019 shift[2 * i] = shift[2 * i + 1] = 0;
1020
1021 fprintf(output, shift);
1022
1023 if (comp == NULL) {
1024 fprintf(output, "Compiled Expression is NULL\n");
1025 return;
1026 }
1027 fprintf(output, "Compiled Expression : %d elements\n",
1028 comp->nbStep);
1029 i = comp->last;
1030 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1031}
Daniel Veillard017b1082001-06-21 11:20:21 +00001032#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001033
1034/************************************************************************
1035 * *
1036 * Parser stacks related functions and macros *
1037 * *
1038 ************************************************************************/
1039
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001040/**
1041 * valuePop:
1042 * @ctxt: an XPath evaluation context
1043 *
1044 * Pops the top XPath object from the value stack
1045 *
1046 * Returns the XPath object just removed
1047 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001048extern xmlXPathObjectPtr
1049valuePop(xmlXPathParserContextPtr ctxt)
1050{
1051 xmlXPathObjectPtr ret;
1052
1053 if (ctxt->valueNr <= 0)
1054 return (0);
1055 ctxt->valueNr--;
1056 if (ctxt->valueNr > 0)
1057 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1058 else
1059 ctxt->value = NULL;
1060 ret = ctxt->valueTab[ctxt->valueNr];
1061 ctxt->valueTab[ctxt->valueNr] = 0;
1062 return (ret);
1063}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001064/**
1065 * valuePush:
1066 * @ctxt: an XPath evaluation context
1067 * @value: the XPath object
1068 *
1069 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001070 *
1071 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001072 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001073extern int
1074valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1075{
1076 if (ctxt->valueNr >= ctxt->valueMax) {
1077 ctxt->valueMax *= 2;
1078 ctxt->valueTab =
1079 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1080 ctxt->valueMax *
1081 sizeof(ctxt->valueTab[0]));
1082 if (ctxt->valueTab == NULL) {
1083 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1084 return (0);
1085 }
1086 }
1087 ctxt->valueTab[ctxt->valueNr] = value;
1088 ctxt->value = value;
1089 return (ctxt->valueNr++);
1090}
Owen Taylor3473f882001-02-23 17:55:21 +00001091
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001092/**
1093 * xmlXPathPopBoolean:
1094 * @ctxt: an XPath parser context
1095 *
1096 * Pops a boolean from the stack, handling conversion if needed.
1097 * Check error with #xmlXPathCheckError.
1098 *
1099 * Returns the boolean
1100 */
1101int
1102xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1103 xmlXPathObjectPtr obj;
1104 int ret;
1105
1106 obj = valuePop(ctxt);
1107 if (obj == NULL) {
1108 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1109 return(0);
1110 }
1111 ret = xmlXPathCastToBoolean(obj);
1112 xmlXPathFreeObject(obj);
1113 return(ret);
1114}
1115
1116/**
1117 * xmlXPathPopNumber:
1118 * @ctxt: an XPath parser context
1119 *
1120 * Pops a number from the stack, handling conversion if needed.
1121 * Check error with #xmlXPathCheckError.
1122 *
1123 * Returns the number
1124 */
1125double
1126xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1127 xmlXPathObjectPtr obj;
1128 double ret;
1129
1130 obj = valuePop(ctxt);
1131 if (obj == NULL) {
1132 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1133 return(0);
1134 }
1135 ret = xmlXPathCastToNumber(obj);
1136 xmlXPathFreeObject(obj);
1137 return(ret);
1138}
1139
1140/**
1141 * xmlXPathPopString:
1142 * @ctxt: an XPath parser context
1143 *
1144 * Pops a string from the stack, handling conversion if needed.
1145 * Check error with #xmlXPathCheckError.
1146 *
1147 * Returns the string
1148 */
1149xmlChar *
1150xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1151 xmlXPathObjectPtr obj;
1152 xmlChar * ret;
1153
1154 obj = valuePop(ctxt);
1155 if (obj == NULL) {
1156 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1157 return(NULL);
1158 }
1159 ret = xmlXPathCastToString(obj);
1160 /* TODO: needs refactoring somewhere else */
1161 if (obj->stringval == ret)
1162 obj->stringval = NULL;
1163 xmlXPathFreeObject(obj);
1164 return(ret);
1165}
1166
1167/**
1168 * xmlXPathPopNodeSet:
1169 * @ctxt: an XPath parser context
1170 *
1171 * Pops a node-set from the stack, handling conversion if needed.
1172 * Check error with #xmlXPathCheckError.
1173 *
1174 * Returns the node-set
1175 */
1176xmlNodeSetPtr
1177xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1178 xmlXPathObjectPtr obj;
1179 xmlNodeSetPtr ret;
1180
1181 if (ctxt->value == NULL) {
1182 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1183 return(NULL);
1184 }
1185 if (!xmlXPathStackIsNodeSet(ctxt)) {
1186 xmlXPathSetTypeError(ctxt);
1187 return(NULL);
1188 }
1189 obj = valuePop(ctxt);
1190 ret = obj->nodesetval;
Daniel Veillard9deb2422003-07-28 20:40:59 +00001191 /* to fix memory leak of not clearing obj->user */
1192 if (obj->boolval && obj->user != NULL)
1193 xmlFreeNodeList((xmlNodePtr) obj->user);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001194 xmlXPathFreeNodeSetList(obj);
1195 return(ret);
1196}
1197
1198/**
1199 * xmlXPathPopExternal:
1200 * @ctxt: an XPath parser context
1201 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001202 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001203 * Check error with #xmlXPathCheckError.
1204 *
1205 * Returns the object
1206 */
1207void *
1208xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1209 xmlXPathObjectPtr obj;
1210 void * ret;
1211
1212 if (ctxt->value == NULL) {
1213 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1214 return(NULL);
1215 }
1216 if (ctxt->value->type != XPATH_USERS) {
1217 xmlXPathSetTypeError(ctxt);
1218 return(NULL);
1219 }
1220 obj = valuePop(ctxt);
1221 ret = obj->user;
1222 xmlXPathFreeObject(obj);
1223 return(ret);
1224}
1225
Owen Taylor3473f882001-02-23 17:55:21 +00001226/*
1227 * Macros for accessing the content. Those should be used only by the parser,
1228 * and not exported.
1229 *
1230 * Dirty macros, i.e. one need to make assumption on the context to use them
1231 *
1232 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1233 * CUR returns the current xmlChar value, i.e. a 8 bit value
1234 * in ISO-Latin or UTF-8.
1235 * This should be used internally by the parser
1236 * only to compare to ASCII values otherwise it would break when
1237 * running with UTF-8 encoding.
1238 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1239 * to compare on ASCII based substring.
1240 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1241 * strings within the parser.
1242 * CURRENT Returns the current char value, with the full decoding of
1243 * UTF-8 if we are using this mode. It returns an int.
1244 * NEXT Skip to the next character, this does the proper decoding
1245 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1246 * It returns the pointer to the current xmlChar.
1247 */
1248
1249#define CUR (*ctxt->cur)
1250#define SKIP(val) ctxt->cur += (val)
1251#define NXT(val) ctxt->cur[(val)]
1252#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001253#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1254
1255#define COPY_BUF(l,b,i,v) \
1256 if (l == 1) b[i++] = (xmlChar) v; \
1257 else i += xmlCopyChar(l,&b[i],v)
1258
1259#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001260
1261#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001262 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001263
1264#define CURRENT (*ctxt->cur)
1265#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1266
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001267
1268#ifndef DBL_DIG
1269#define DBL_DIG 16
1270#endif
1271#ifndef DBL_EPSILON
1272#define DBL_EPSILON 1E-9
1273#endif
1274
1275#define UPPER_DOUBLE 1E9
1276#define LOWER_DOUBLE 1E-5
1277
1278#define INTEGER_DIGITS DBL_DIG
1279#define FRACTION_DIGITS (DBL_DIG + 1)
1280#define EXPONENT_DIGITS (3 + 2)
1281
1282/**
1283 * xmlXPathFormatNumber:
1284 * @number: number to format
1285 * @buffer: output buffer
1286 * @buffersize: size of output buffer
1287 *
1288 * Convert the number into a string representation.
1289 */
1290static void
1291xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1292{
Daniel Veillardcda96922001-08-21 10:56:31 +00001293 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001294 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001295 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001296 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001297 break;
1298 case -1:
1299 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001300 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001301 break;
1302 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001303 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001304 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001305 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001306 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001307 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001308 } else if (number == ((int) number)) {
1309 char work[30];
1310 char *ptr, *cur;
1311 int res, value = (int) number;
1312
1313 ptr = &buffer[0];
1314 if (value < 0) {
1315 *ptr++ = '-';
1316 value = -value;
1317 }
1318 if (value == 0) {
1319 *ptr++ = '0';
1320 } else {
1321 cur = &work[0];
1322 while (value != 0) {
1323 res = value % 10;
1324 value = value / 10;
1325 *cur++ = '0' + res;
1326 }
1327 cur--;
1328 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1329 *ptr++ = *cur--;
1330 }
1331 }
1332 if (ptr - buffer < buffersize) {
1333 *ptr = 0;
1334 } else if (buffersize > 0) {
1335 ptr--;
1336 *ptr = 0;
1337 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001338 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001339 /* 3 is sign, decimal point, and terminating zero */
1340 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1341 int integer_place, fraction_place;
1342 char *ptr;
1343 char *after_fraction;
1344 double absolute_value;
1345 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001346
Bjorn Reese70a9da52001-04-21 16:57:29 +00001347 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001348
Bjorn Reese70a9da52001-04-21 16:57:29 +00001349 /*
1350 * First choose format - scientific or regular floating point.
1351 * In either case, result is in work, and after_fraction points
1352 * just past the fractional part.
1353 */
1354 if ( ((absolute_value > UPPER_DOUBLE) ||
1355 (absolute_value < LOWER_DOUBLE)) &&
1356 (absolute_value != 0.0) ) {
1357 /* Use scientific notation */
1358 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1359 fraction_place = DBL_DIG - 1;
1360 snprintf(work, sizeof(work),"%*.*e",
1361 integer_place, fraction_place, number);
1362 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001363 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001364 else {
1365 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001366 if (absolute_value > 0.0)
1367 integer_place = 1 + (int)log10(absolute_value);
1368 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001369 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001370 fraction_place = (integer_place > 0)
1371 ? DBL_DIG - integer_place
1372 : DBL_DIG;
1373 size = snprintf(work, sizeof(work), "%0.*f",
1374 fraction_place, number);
1375 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001376 }
1377
Bjorn Reese70a9da52001-04-21 16:57:29 +00001378 /* Remove fractional trailing zeroes */
1379 ptr = after_fraction;
1380 while (*(--ptr) == '0')
1381 ;
1382 if (*ptr != '.')
1383 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001384 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001385
1386 /* Finally copy result back to caller */
1387 size = strlen(work) + 1;
1388 if (size > buffersize) {
1389 work[buffersize - 1] = 0;
1390 size = buffersize;
1391 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001392 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001393 }
1394 break;
1395 }
1396}
1397
Owen Taylor3473f882001-02-23 17:55:21 +00001398
1399/************************************************************************
1400 * *
1401 * Routines to handle NodeSets *
1402 * *
1403 ************************************************************************/
1404
1405/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001406 * xmlXPathOrderDocElems:
1407 * @doc: an input document
1408 *
1409 * Call this routine to speed up XPath computation on static documents.
1410 * This stamps all the element nodes with the document order
1411 * Like for line information, the order is kept in the element->content
1412 * field, the value stored is actually - the node number (startting at -1)
1413 * to be able to differenciate from line numbers.
1414 *
1415 * Returns the number of element found in the document or -1 in case
1416 * of error.
1417 */
1418long
1419xmlXPathOrderDocElems(xmlDocPtr doc) {
1420 long count = 0;
1421 xmlNodePtr cur;
1422
1423 if (doc == NULL)
1424 return(-1);
1425 cur = doc->children;
1426 while (cur != NULL) {
1427 if (cur->type == XML_ELEMENT_NODE) {
1428 cur->content = (void *) (-(++count));
1429 if (cur->children != NULL) {
1430 cur = cur->children;
1431 continue;
1432 }
1433 }
1434 if (cur->next != NULL) {
1435 cur = cur->next;
1436 continue;
1437 }
1438 do {
1439 cur = cur->parent;
1440 if (cur == NULL)
1441 break;
1442 if (cur == (xmlNodePtr) doc) {
1443 cur = NULL;
1444 break;
1445 }
1446 if (cur->next != NULL) {
1447 cur = cur->next;
1448 break;
1449 }
1450 } while (cur != NULL);
1451 }
1452 return(count);
1453}
1454
1455/**
Owen Taylor3473f882001-02-23 17:55:21 +00001456 * xmlXPathCmpNodes:
1457 * @node1: the first node
1458 * @node2: the second node
1459 *
1460 * Compare two nodes w.r.t document order
1461 *
1462 * Returns -2 in case of error 1 if first point < second point, 0 if
1463 * that's the same node, -1 otherwise
1464 */
1465int
1466xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1467 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001468 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001469 xmlNodePtr cur, root;
1470
1471 if ((node1 == NULL) || (node2 == NULL))
1472 return(-2);
1473 /*
1474 * a couple of optimizations which will avoid computations in most cases
1475 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001476 if (node1->type == XML_ATTRIBUTE_NODE) {
1477 attr1 = 1;
1478 node1 = node1->parent;
1479 }
1480 if (node2->type == XML_ATTRIBUTE_NODE) {
1481 attr2 = 1;
1482 node2 = node2->parent;
1483 }
1484 if (node1 == node2) {
1485 if (attr1 == attr2)
1486 return(0);
1487 if (attr2 == 1)
1488 return(1);
1489 return(-1);
1490 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001491 if ((node1->type == XML_NAMESPACE_DECL) ||
1492 (node2->type == XML_NAMESPACE_DECL))
1493 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001494 if (node1 == node2->prev)
1495 return(1);
1496 if (node1 == node2->next)
1497 return(-1);
1498
1499 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001500 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001501 */
1502 if ((node1->type == XML_ELEMENT_NODE) &&
1503 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001504 (0 > (long) node1->content) &&
1505 (0 > (long) node2->content) &&
1506 (node1->doc == node2->doc)) {
1507 long l1, l2;
1508
1509 l1 = -((long) node1->content);
1510 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001511 if (l1 < l2)
1512 return(1);
1513 if (l1 > l2)
1514 return(-1);
1515 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001516
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001517 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001518 * compute depth to root
1519 */
1520 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1521 if (cur == node1)
1522 return(1);
1523 depth2++;
1524 }
1525 root = cur;
1526 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1527 if (cur == node2)
1528 return(-1);
1529 depth1++;
1530 }
1531 /*
1532 * Distinct document (or distinct entities :-( ) case.
1533 */
1534 if (root != cur) {
1535 return(-2);
1536 }
1537 /*
1538 * get the nearest common ancestor.
1539 */
1540 while (depth1 > depth2) {
1541 depth1--;
1542 node1 = node1->parent;
1543 }
1544 while (depth2 > depth1) {
1545 depth2--;
1546 node2 = node2->parent;
1547 }
1548 while (node1->parent != node2->parent) {
1549 node1 = node1->parent;
1550 node2 = node2->parent;
1551 /* should not happen but just in case ... */
1552 if ((node1 == NULL) || (node2 == NULL))
1553 return(-2);
1554 }
1555 /*
1556 * Find who's first.
1557 */
1558 if (node1 == node2->next)
1559 return(-1);
1560 for (cur = node1->next;cur != NULL;cur = cur->next)
1561 if (cur == node2)
1562 return(1);
1563 return(-1); /* assume there is no sibling list corruption */
1564}
1565
1566/**
1567 * xmlXPathNodeSetSort:
1568 * @set: the node set
1569 *
1570 * Sort the node set in document order
1571 */
1572void
1573xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001574 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001575 xmlNodePtr tmp;
1576
1577 if (set == NULL)
1578 return;
1579
1580 /* Use Shell's sort to sort the node-set */
1581 len = set->nodeNr;
1582 for (incr = len / 2; incr > 0; incr /= 2) {
1583 for (i = incr; i < len; i++) {
1584 j = i - incr;
1585 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001586 if (xmlXPathCmpNodes(set->nodeTab[j],
1587 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001588 tmp = set->nodeTab[j];
1589 set->nodeTab[j] = set->nodeTab[j + incr];
1590 set->nodeTab[j + incr] = tmp;
1591 j -= incr;
1592 } else
1593 break;
1594 }
1595 }
1596 }
1597}
1598
1599#define XML_NODESET_DEFAULT 10
1600/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001601 * xmlXPathNodeSetDupNs:
1602 * @node: the parent node of the namespace XPath node
1603 * @ns: the libxml namespace declaration node.
1604 *
1605 * Namespace node in libxml don't match the XPath semantic. In a node set
1606 * the namespace nodes are duplicated and the next pointer is set to the
1607 * parent node in the XPath semantic.
1608 *
1609 * Returns the newly created object.
1610 */
1611static xmlNodePtr
1612xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1613 xmlNsPtr cur;
1614
1615 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1616 return(NULL);
1617 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1618 return((xmlNodePtr) ns);
1619
1620 /*
1621 * Allocate a new Namespace and fill the fields.
1622 */
1623 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1624 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001625 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001626 return(NULL);
1627 }
1628 memset(cur, 0, sizeof(xmlNs));
1629 cur->type = XML_NAMESPACE_DECL;
1630 if (ns->href != NULL)
1631 cur->href = xmlStrdup(ns->href);
1632 if (ns->prefix != NULL)
1633 cur->prefix = xmlStrdup(ns->prefix);
1634 cur->next = (xmlNsPtr) node;
1635 return((xmlNodePtr) cur);
1636}
1637
1638/**
1639 * xmlXPathNodeSetFreeNs:
1640 * @ns: the XPath namespace node found in a nodeset.
1641 *
1642 * Namespace node in libxml don't match the XPath semantic. In a node set
1643 * the namespace nodes are duplicated and the next pointer is set to the
1644 * parent node in the XPath semantic. Check if such a node need to be freed
1645 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001646void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001647xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1648 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1649 return;
1650
1651 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1652 if (ns->href != NULL)
1653 xmlFree((xmlChar *)ns->href);
1654 if (ns->prefix != NULL)
1655 xmlFree((xmlChar *)ns->prefix);
1656 xmlFree(ns);
1657 }
1658}
1659
1660/**
Owen Taylor3473f882001-02-23 17:55:21 +00001661 * xmlXPathNodeSetCreate:
1662 * @val: an initial xmlNodePtr, or NULL
1663 *
1664 * Create a new xmlNodeSetPtr of type double and of value @val
1665 *
1666 * Returns the newly created object.
1667 */
1668xmlNodeSetPtr
1669xmlXPathNodeSetCreate(xmlNodePtr val) {
1670 xmlNodeSetPtr ret;
1671
1672 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1673 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001674 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001675 return(NULL);
1676 }
1677 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1678 if (val != NULL) {
1679 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1680 sizeof(xmlNodePtr));
1681 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001682 xmlXPathErrMemory(NULL, "creating nodeset\n");
1683 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001684 return(NULL);
1685 }
1686 memset(ret->nodeTab, 0 ,
1687 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1688 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001689 if (val->type == XML_NAMESPACE_DECL) {
1690 xmlNsPtr ns = (xmlNsPtr) val;
1691
1692 ret->nodeTab[ret->nodeNr++] =
1693 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1694 } else
1695 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001696 }
1697 return(ret);
1698}
1699
1700/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001701 * xmlXPathNodeSetContains:
1702 * @cur: the node-set
1703 * @val: the node
1704 *
1705 * checks whether @cur contains @val
1706 *
1707 * Returns true (1) if @cur contains @val, false (0) otherwise
1708 */
1709int
1710xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1711 int i;
1712
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001713 if (val->type == XML_NAMESPACE_DECL) {
1714 for (i = 0; i < cur->nodeNr; i++) {
1715 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1716 xmlNsPtr ns1, ns2;
1717
1718 ns1 = (xmlNsPtr) val;
1719 ns2 = (xmlNsPtr) cur->nodeTab[i];
1720 if (ns1 == ns2)
1721 return(1);
1722 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1723 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1724 return(1);
1725 }
1726 }
1727 } else {
1728 for (i = 0; i < cur->nodeNr; i++) {
1729 if (cur->nodeTab[i] == val)
1730 return(1);
1731 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001732 }
1733 return(0);
1734}
1735
1736/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001737 * xmlXPathNodeSetAddNs:
1738 * @cur: the initial node set
1739 * @node: the hosting node
1740 * @ns: a the namespace node
1741 *
1742 * add a new namespace node to an existing NodeSet
1743 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001744void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001745xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1746 int i;
1747
1748 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1749 (node->type != XML_ELEMENT_NODE))
1750 return;
1751
1752 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1753 /*
1754 * check against doublons
1755 */
1756 for (i = 0;i < cur->nodeNr;i++) {
1757 if ((cur->nodeTab[i] != NULL) &&
1758 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001759 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001760 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1761 return;
1762 }
1763
1764 /*
1765 * grow the nodeTab if needed
1766 */
1767 if (cur->nodeMax == 0) {
1768 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1769 sizeof(xmlNodePtr));
1770 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001771 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001772 return;
1773 }
1774 memset(cur->nodeTab, 0 ,
1775 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1776 cur->nodeMax = XML_NODESET_DEFAULT;
1777 } else if (cur->nodeNr == cur->nodeMax) {
1778 xmlNodePtr *temp;
1779
1780 cur->nodeMax *= 2;
1781 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1782 sizeof(xmlNodePtr));
1783 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001784 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001785 return;
1786 }
1787 cur->nodeTab = temp;
1788 }
1789 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1790}
1791
1792/**
Owen Taylor3473f882001-02-23 17:55:21 +00001793 * xmlXPathNodeSetAdd:
1794 * @cur: the initial node set
1795 * @val: a new xmlNodePtr
1796 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001797 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001798 */
1799void
1800xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1801 int i;
1802
1803 if (val == NULL) return;
1804
Daniel Veillardef0b4502003-03-24 13:57:34 +00001805#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001806 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1807 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001808#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001809
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001810 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001811 /*
1812 * check against doublons
1813 */
1814 for (i = 0;i < cur->nodeNr;i++)
1815 if (cur->nodeTab[i] == val) return;
1816
1817 /*
1818 * grow the nodeTab if needed
1819 */
1820 if (cur->nodeMax == 0) {
1821 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1822 sizeof(xmlNodePtr));
1823 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001824 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001825 return;
1826 }
1827 memset(cur->nodeTab, 0 ,
1828 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1829 cur->nodeMax = XML_NODESET_DEFAULT;
1830 } else if (cur->nodeNr == cur->nodeMax) {
1831 xmlNodePtr *temp;
1832
1833 cur->nodeMax *= 2;
1834 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1835 sizeof(xmlNodePtr));
1836 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001837 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001838 return;
1839 }
1840 cur->nodeTab = temp;
1841 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001842 if (val->type == XML_NAMESPACE_DECL) {
1843 xmlNsPtr ns = (xmlNsPtr) val;
1844
1845 cur->nodeTab[cur->nodeNr++] =
1846 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1847 } else
1848 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001849}
1850
1851/**
1852 * xmlXPathNodeSetAddUnique:
1853 * @cur: the initial node set
1854 * @val: a new xmlNodePtr
1855 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001856 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001857 * when we are sure the node is not already in the set.
1858 */
1859void
1860xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1861 if (val == NULL) return;
1862
Daniel Veillardef0b4502003-03-24 13:57:34 +00001863#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001864 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1865 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001866#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001867
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001868 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001869 /*
1870 * grow the nodeTab if needed
1871 */
1872 if (cur->nodeMax == 0) {
1873 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1874 sizeof(xmlNodePtr));
1875 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001876 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001877 return;
1878 }
1879 memset(cur->nodeTab, 0 ,
1880 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1881 cur->nodeMax = XML_NODESET_DEFAULT;
1882 } else if (cur->nodeNr == cur->nodeMax) {
1883 xmlNodePtr *temp;
1884
1885 cur->nodeMax *= 2;
1886 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1887 sizeof(xmlNodePtr));
1888 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001889 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001890 return;
1891 }
1892 cur->nodeTab = temp;
1893 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001894 if (val->type == XML_NAMESPACE_DECL) {
1895 xmlNsPtr ns = (xmlNsPtr) val;
1896
1897 cur->nodeTab[cur->nodeNr++] =
1898 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1899 } else
1900 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001901}
1902
1903/**
1904 * xmlXPathNodeSetMerge:
1905 * @val1: the first NodeSet or NULL
1906 * @val2: the second NodeSet
1907 *
1908 * Merges two nodesets, all nodes from @val2 are added to @val1
1909 * if @val1 is NULL, a new set is created and copied from @val2
1910 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001911 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001912 */
1913xmlNodeSetPtr
1914xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001915 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001916
1917 if (val2 == NULL) return(val1);
1918 if (val1 == NULL) {
1919 val1 = xmlXPathNodeSetCreate(NULL);
1920 }
1921
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001922 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001923 initNr = val1->nodeNr;
1924
1925 for (i = 0;i < val2->nodeNr;i++) {
1926 /*
1927 * check against doublons
1928 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001929 skip = 0;
1930 for (j = 0; j < initNr; j++) {
1931 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1932 skip = 1;
1933 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001934 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1935 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1936 xmlNsPtr ns1, ns2;
1937 ns1 = (xmlNsPtr) val1->nodeTab[j];
1938 ns2 = (xmlNsPtr) val2->nodeTab[i];
1939 if ((ns1->next == ns2->next) &&
1940 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1941 skip = 1;
1942 break;
1943 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001944 }
1945 }
1946 if (skip)
1947 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001948
1949 /*
1950 * grow the nodeTab if needed
1951 */
1952 if (val1->nodeMax == 0) {
1953 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1954 sizeof(xmlNodePtr));
1955 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001956 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001957 return(NULL);
1958 }
1959 memset(val1->nodeTab, 0 ,
1960 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1961 val1->nodeMax = XML_NODESET_DEFAULT;
1962 } else if (val1->nodeNr == val1->nodeMax) {
1963 xmlNodePtr *temp;
1964
1965 val1->nodeMax *= 2;
1966 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1967 sizeof(xmlNodePtr));
1968 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001969 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001970 return(NULL);
1971 }
1972 val1->nodeTab = temp;
1973 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001974 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1975 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1976
1977 val1->nodeTab[val1->nodeNr++] =
1978 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1979 } else
1980 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001981 }
1982
1983 return(val1);
1984}
1985
1986/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001987 * xmlXPathNodeSetMergeUnique:
1988 * @val1: the first NodeSet or NULL
1989 * @val2: the second NodeSet
1990 *
1991 * Merges two nodesets, all nodes from @val2 are added to @val1
1992 * if @val1 is NULL, a new set is created and copied from @val2
1993 *
1994 * Returns @val1 once extended or NULL in case of error.
1995 */
1996static xmlNodeSetPtr
1997xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00001998 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00001999
2000 if (val2 == NULL) return(val1);
2001 if (val1 == NULL) {
2002 val1 = xmlXPathNodeSetCreate(NULL);
2003 }
2004
2005 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002006
2007 for (i = 0;i < val2->nodeNr;i++) {
2008 /*
2009 * grow the nodeTab if needed
2010 */
2011 if (val1->nodeMax == 0) {
2012 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2013 sizeof(xmlNodePtr));
2014 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002015 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002016 return(NULL);
2017 }
2018 memset(val1->nodeTab, 0 ,
2019 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2020 val1->nodeMax = XML_NODESET_DEFAULT;
2021 } else if (val1->nodeNr == val1->nodeMax) {
2022 xmlNodePtr *temp;
2023
2024 val1->nodeMax *= 2;
2025 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2026 sizeof(xmlNodePtr));
2027 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002028 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002029 return(NULL);
2030 }
2031 val1->nodeTab = temp;
2032 }
2033 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2034 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2035
2036 val1->nodeTab[val1->nodeNr++] =
2037 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2038 } else
2039 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2040 }
2041
2042 return(val1);
2043}
2044
2045/**
Owen Taylor3473f882001-02-23 17:55:21 +00002046 * xmlXPathNodeSetDel:
2047 * @cur: the initial node set
2048 * @val: an xmlNodePtr
2049 *
2050 * Removes an xmlNodePtr from an existing NodeSet
2051 */
2052void
2053xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2054 int i;
2055
2056 if (cur == NULL) return;
2057 if (val == NULL) return;
2058
2059 /*
2060 * check against doublons
2061 */
2062 for (i = 0;i < cur->nodeNr;i++)
2063 if (cur->nodeTab[i] == val) break;
2064
2065 if (i >= cur->nodeNr) {
2066#ifdef DEBUG
2067 xmlGenericError(xmlGenericErrorContext,
2068 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2069 val->name);
2070#endif
2071 return;
2072 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002073 if ((cur->nodeTab[i] != NULL) &&
2074 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2075 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002076 cur->nodeNr--;
2077 for (;i < cur->nodeNr;i++)
2078 cur->nodeTab[i] = cur->nodeTab[i + 1];
2079 cur->nodeTab[cur->nodeNr] = NULL;
2080}
2081
2082/**
2083 * xmlXPathNodeSetRemove:
2084 * @cur: the initial node set
2085 * @val: the index to remove
2086 *
2087 * Removes an entry from an existing NodeSet list.
2088 */
2089void
2090xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2091 if (cur == NULL) return;
2092 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002093 if ((cur->nodeTab[val] != NULL) &&
2094 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2095 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002096 cur->nodeNr--;
2097 for (;val < cur->nodeNr;val++)
2098 cur->nodeTab[val] = cur->nodeTab[val + 1];
2099 cur->nodeTab[cur->nodeNr] = NULL;
2100}
2101
2102/**
2103 * xmlXPathFreeNodeSet:
2104 * @obj: the xmlNodeSetPtr to free
2105 *
2106 * Free the NodeSet compound (not the actual nodes !).
2107 */
2108void
2109xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2110 if (obj == NULL) return;
2111 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002112 int i;
2113
2114 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2115 for (i = 0;i < obj->nodeNr;i++)
2116 if ((obj->nodeTab[i] != NULL) &&
2117 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2118 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002119 xmlFree(obj->nodeTab);
2120 }
Owen Taylor3473f882001-02-23 17:55:21 +00002121 xmlFree(obj);
2122}
2123
2124/**
2125 * xmlXPathFreeValueTree:
2126 * @obj: the xmlNodeSetPtr to free
2127 *
2128 * Free the NodeSet compound and the actual tree, this is different
2129 * from xmlXPathFreeNodeSet()
2130 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002131static void
Owen Taylor3473f882001-02-23 17:55:21 +00002132xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2133 int i;
2134
2135 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002136
2137 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002138 for (i = 0;i < obj->nodeNr;i++) {
2139 if (obj->nodeTab[i] != NULL) {
2140 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2141 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2142 } else {
2143 xmlFreeNodeList(obj->nodeTab[i]);
2144 }
2145 }
2146 }
Owen Taylor3473f882001-02-23 17:55:21 +00002147 xmlFree(obj->nodeTab);
2148 }
Owen Taylor3473f882001-02-23 17:55:21 +00002149 xmlFree(obj);
2150}
2151
2152#if defined(DEBUG) || defined(DEBUG_STEP)
2153/**
2154 * xmlGenericErrorContextNodeSet:
2155 * @output: a FILE * for the output
2156 * @obj: the xmlNodeSetPtr to free
2157 *
2158 * Quick display of a NodeSet
2159 */
2160void
2161xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2162 int i;
2163
2164 if (output == NULL) output = xmlGenericErrorContext;
2165 if (obj == NULL) {
2166 fprintf(output, "NodeSet == NULL !\n");
2167 return;
2168 }
2169 if (obj->nodeNr == 0) {
2170 fprintf(output, "NodeSet is empty\n");
2171 return;
2172 }
2173 if (obj->nodeTab == NULL) {
2174 fprintf(output, " nodeTab == NULL !\n");
2175 return;
2176 }
2177 for (i = 0; i < obj->nodeNr; i++) {
2178 if (obj->nodeTab[i] == NULL) {
2179 fprintf(output, " NULL !\n");
2180 return;
2181 }
2182 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2183 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2184 fprintf(output, " /");
2185 else if (obj->nodeTab[i]->name == NULL)
2186 fprintf(output, " noname!");
2187 else fprintf(output, " %s", obj->nodeTab[i]->name);
2188 }
2189 fprintf(output, "\n");
2190}
2191#endif
2192
2193/**
2194 * xmlXPathNewNodeSet:
2195 * @val: the NodePtr value
2196 *
2197 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2198 * it with the single Node @val
2199 *
2200 * Returns the newly created object.
2201 */
2202xmlXPathObjectPtr
2203xmlXPathNewNodeSet(xmlNodePtr val) {
2204 xmlXPathObjectPtr ret;
2205
2206 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2207 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002208 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002209 return(NULL);
2210 }
2211 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2212 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002213 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002214 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002215 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002216 return(ret);
2217}
2218
2219/**
2220 * xmlXPathNewValueTree:
2221 * @val: the NodePtr value
2222 *
2223 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2224 * it with the tree root @val
2225 *
2226 * Returns the newly created object.
2227 */
2228xmlXPathObjectPtr
2229xmlXPathNewValueTree(xmlNodePtr val) {
2230 xmlXPathObjectPtr ret;
2231
2232 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2233 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002234 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002235 return(NULL);
2236 }
2237 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2238 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002239 ret->boolval = 1;
2240 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002241 ret->nodesetval = xmlXPathNodeSetCreate(val);
2242 return(ret);
2243}
2244
2245/**
2246 * xmlXPathNewNodeSetList:
2247 * @val: an existing NodeSet
2248 *
2249 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2250 * it with the Nodeset @val
2251 *
2252 * Returns the newly created object.
2253 */
2254xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002255xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2256{
Owen Taylor3473f882001-02-23 17:55:21 +00002257 xmlXPathObjectPtr ret;
2258 int i;
2259
2260 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002261 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002262 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002263 ret = xmlXPathNewNodeSet(NULL);
2264 else {
2265 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2266 for (i = 1; i < val->nodeNr; ++i)
2267 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2268 }
Owen Taylor3473f882001-02-23 17:55:21 +00002269
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002270 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002271}
2272
2273/**
2274 * xmlXPathWrapNodeSet:
2275 * @val: the NodePtr value
2276 *
2277 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2278 *
2279 * Returns the newly created object.
2280 */
2281xmlXPathObjectPtr
2282xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2283 xmlXPathObjectPtr ret;
2284
2285 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2286 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002287 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002288 return(NULL);
2289 }
2290 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2291 ret->type = XPATH_NODESET;
2292 ret->nodesetval = val;
2293 return(ret);
2294}
2295
2296/**
2297 * xmlXPathFreeNodeSetList:
2298 * @obj: an existing NodeSetList object
2299 *
2300 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2301 * the list contrary to xmlXPathFreeObject().
2302 */
2303void
2304xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2305 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002306 xmlFree(obj);
2307}
2308
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002309/**
2310 * xmlXPathDifference:
2311 * @nodes1: a node-set
2312 * @nodes2: a node-set
2313 *
2314 * Implements the EXSLT - Sets difference() function:
2315 * node-set set:difference (node-set, node-set)
2316 *
2317 * Returns the difference between the two node sets, or nodes1 if
2318 * nodes2 is empty
2319 */
2320xmlNodeSetPtr
2321xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2322 xmlNodeSetPtr ret;
2323 int i, l1;
2324 xmlNodePtr cur;
2325
2326 if (xmlXPathNodeSetIsEmpty(nodes2))
2327 return(nodes1);
2328
2329 ret = xmlXPathNodeSetCreate(NULL);
2330 if (xmlXPathNodeSetIsEmpty(nodes1))
2331 return(ret);
2332
2333 l1 = xmlXPathNodeSetGetLength(nodes1);
2334
2335 for (i = 0; i < l1; i++) {
2336 cur = xmlXPathNodeSetItem(nodes1, i);
2337 if (!xmlXPathNodeSetContains(nodes2, cur))
2338 xmlXPathNodeSetAddUnique(ret, cur);
2339 }
2340 return(ret);
2341}
2342
2343/**
2344 * xmlXPathIntersection:
2345 * @nodes1: a node-set
2346 * @nodes2: a node-set
2347 *
2348 * Implements the EXSLT - Sets intersection() function:
2349 * node-set set:intersection (node-set, node-set)
2350 *
2351 * Returns a node set comprising the nodes that are within both the
2352 * node sets passed as arguments
2353 */
2354xmlNodeSetPtr
2355xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2356 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2357 int i, l1;
2358 xmlNodePtr cur;
2359
2360 if (xmlXPathNodeSetIsEmpty(nodes1))
2361 return(ret);
2362 if (xmlXPathNodeSetIsEmpty(nodes2))
2363 return(ret);
2364
2365 l1 = xmlXPathNodeSetGetLength(nodes1);
2366
2367 for (i = 0; i < l1; i++) {
2368 cur = xmlXPathNodeSetItem(nodes1, i);
2369 if (xmlXPathNodeSetContains(nodes2, cur))
2370 xmlXPathNodeSetAddUnique(ret, cur);
2371 }
2372 return(ret);
2373}
2374
2375/**
2376 * xmlXPathDistinctSorted:
2377 * @nodes: a node-set, sorted by document order
2378 *
2379 * Implements the EXSLT - Sets distinct() function:
2380 * node-set set:distinct (node-set)
2381 *
2382 * Returns a subset of the nodes contained in @nodes, or @nodes if
2383 * it is empty
2384 */
2385xmlNodeSetPtr
2386xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2387 xmlNodeSetPtr ret;
2388 xmlHashTablePtr hash;
2389 int i, l;
2390 xmlChar * strval;
2391 xmlNodePtr cur;
2392
2393 if (xmlXPathNodeSetIsEmpty(nodes))
2394 return(nodes);
2395
2396 ret = xmlXPathNodeSetCreate(NULL);
2397 l = xmlXPathNodeSetGetLength(nodes);
2398 hash = xmlHashCreate (l);
2399 for (i = 0; i < l; i++) {
2400 cur = xmlXPathNodeSetItem(nodes, i);
2401 strval = xmlXPathCastNodeToString(cur);
2402 if (xmlHashLookup(hash, strval) == NULL) {
2403 xmlHashAddEntry(hash, strval, strval);
2404 xmlXPathNodeSetAddUnique(ret, cur);
2405 } else {
2406 xmlFree(strval);
2407 }
2408 }
2409 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2410 return(ret);
2411}
2412
2413/**
2414 * xmlXPathDistinct:
2415 * @nodes: a node-set
2416 *
2417 * Implements the EXSLT - Sets distinct() function:
2418 * node-set set:distinct (node-set)
2419 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2420 * is called with the sorted node-set
2421 *
2422 * Returns a subset of the nodes contained in @nodes, or @nodes if
2423 * it is empty
2424 */
2425xmlNodeSetPtr
2426xmlXPathDistinct (xmlNodeSetPtr nodes) {
2427 if (xmlXPathNodeSetIsEmpty(nodes))
2428 return(nodes);
2429
2430 xmlXPathNodeSetSort(nodes);
2431 return(xmlXPathDistinctSorted(nodes));
2432}
2433
2434/**
2435 * xmlXPathHasSameNodes:
2436 * @nodes1: a node-set
2437 * @nodes2: a node-set
2438 *
2439 * Implements the EXSLT - Sets has-same-nodes function:
2440 * boolean set:has-same-node(node-set, node-set)
2441 *
2442 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2443 * otherwise
2444 */
2445int
2446xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2447 int i, l;
2448 xmlNodePtr cur;
2449
2450 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2451 xmlXPathNodeSetIsEmpty(nodes2))
2452 return(0);
2453
2454 l = xmlXPathNodeSetGetLength(nodes1);
2455 for (i = 0; i < l; i++) {
2456 cur = xmlXPathNodeSetItem(nodes1, i);
2457 if (xmlXPathNodeSetContains(nodes2, cur))
2458 return(1);
2459 }
2460 return(0);
2461}
2462
2463/**
2464 * xmlXPathNodeLeadingSorted:
2465 * @nodes: a node-set, sorted by document order
2466 * @node: a node
2467 *
2468 * Implements the EXSLT - Sets leading() function:
2469 * node-set set:leading (node-set, node-set)
2470 *
2471 * Returns the nodes in @nodes that precede @node in document order,
2472 * @nodes if @node is NULL or an empty node-set if @nodes
2473 * doesn't contain @node
2474 */
2475xmlNodeSetPtr
2476xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2477 int i, l;
2478 xmlNodePtr cur;
2479 xmlNodeSetPtr ret;
2480
2481 if (node == NULL)
2482 return(nodes);
2483
2484 ret = xmlXPathNodeSetCreate(NULL);
2485 if (xmlXPathNodeSetIsEmpty(nodes) ||
2486 (!xmlXPathNodeSetContains(nodes, node)))
2487 return(ret);
2488
2489 l = xmlXPathNodeSetGetLength(nodes);
2490 for (i = 0; i < l; i++) {
2491 cur = xmlXPathNodeSetItem(nodes, i);
2492 if (cur == node)
2493 break;
2494 xmlXPathNodeSetAddUnique(ret, cur);
2495 }
2496 return(ret);
2497}
2498
2499/**
2500 * xmlXPathNodeLeading:
2501 * @nodes: a node-set
2502 * @node: a node
2503 *
2504 * Implements the EXSLT - Sets leading() function:
2505 * node-set set:leading (node-set, node-set)
2506 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2507 * is called.
2508 *
2509 * Returns the nodes in @nodes that precede @node in document order,
2510 * @nodes if @node is NULL or an empty node-set if @nodes
2511 * doesn't contain @node
2512 */
2513xmlNodeSetPtr
2514xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2515 xmlXPathNodeSetSort(nodes);
2516 return(xmlXPathNodeLeadingSorted(nodes, node));
2517}
2518
2519/**
2520 * xmlXPathLeadingSorted:
2521 * @nodes1: a node-set, sorted by document order
2522 * @nodes2: a node-set, sorted by document order
2523 *
2524 * Implements the EXSLT - Sets leading() function:
2525 * node-set set:leading (node-set, node-set)
2526 *
2527 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2528 * in document order, @nodes1 if @nodes2 is NULL or empty or
2529 * an empty node-set if @nodes1 doesn't contain @nodes2
2530 */
2531xmlNodeSetPtr
2532xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2533 if (xmlXPathNodeSetIsEmpty(nodes2))
2534 return(nodes1);
2535 return(xmlXPathNodeLeadingSorted(nodes1,
2536 xmlXPathNodeSetItem(nodes2, 1)));
2537}
2538
2539/**
2540 * xmlXPathLeading:
2541 * @nodes1: a node-set
2542 * @nodes2: a node-set
2543 *
2544 * Implements the EXSLT - Sets leading() function:
2545 * node-set set:leading (node-set, node-set)
2546 * @nodes1 and @nodes2 are sorted by document order, then
2547 * #exslSetsLeadingSorted is called.
2548 *
2549 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2550 * in document order, @nodes1 if @nodes2 is NULL or empty or
2551 * an empty node-set if @nodes1 doesn't contain @nodes2
2552 */
2553xmlNodeSetPtr
2554xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2555 if (xmlXPathNodeSetIsEmpty(nodes2))
2556 return(nodes1);
2557 if (xmlXPathNodeSetIsEmpty(nodes1))
2558 return(xmlXPathNodeSetCreate(NULL));
2559 xmlXPathNodeSetSort(nodes1);
2560 xmlXPathNodeSetSort(nodes2);
2561 return(xmlXPathNodeLeadingSorted(nodes1,
2562 xmlXPathNodeSetItem(nodes2, 1)));
2563}
2564
2565/**
2566 * xmlXPathNodeTrailingSorted:
2567 * @nodes: a node-set, sorted by document order
2568 * @node: a node
2569 *
2570 * Implements the EXSLT - Sets trailing() function:
2571 * node-set set:trailing (node-set, node-set)
2572 *
2573 * Returns the nodes in @nodes that follow @node in document order,
2574 * @nodes if @node is NULL or an empty node-set if @nodes
2575 * doesn't contain @node
2576 */
2577xmlNodeSetPtr
2578xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2579 int i, l;
2580 xmlNodePtr cur;
2581 xmlNodeSetPtr ret;
2582
2583 if (node == NULL)
2584 return(nodes);
2585
2586 ret = xmlXPathNodeSetCreate(NULL);
2587 if (xmlXPathNodeSetIsEmpty(nodes) ||
2588 (!xmlXPathNodeSetContains(nodes, node)))
2589 return(ret);
2590
2591 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002592 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002593 cur = xmlXPathNodeSetItem(nodes, i);
2594 if (cur == node)
2595 break;
2596 xmlXPathNodeSetAddUnique(ret, cur);
2597 }
2598 return(ret);
2599}
2600
2601/**
2602 * xmlXPathNodeTrailing:
2603 * @nodes: a node-set
2604 * @node: a node
2605 *
2606 * Implements the EXSLT - Sets trailing() function:
2607 * node-set set:trailing (node-set, node-set)
2608 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2609 * is called.
2610 *
2611 * Returns the nodes in @nodes that follow @node in document order,
2612 * @nodes if @node is NULL or an empty node-set if @nodes
2613 * doesn't contain @node
2614 */
2615xmlNodeSetPtr
2616xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2617 xmlXPathNodeSetSort(nodes);
2618 return(xmlXPathNodeTrailingSorted(nodes, node));
2619}
2620
2621/**
2622 * xmlXPathTrailingSorted:
2623 * @nodes1: a node-set, sorted by document order
2624 * @nodes2: a node-set, sorted by document order
2625 *
2626 * Implements the EXSLT - Sets trailing() function:
2627 * node-set set:trailing (node-set, node-set)
2628 *
2629 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2630 * in document order, @nodes1 if @nodes2 is NULL or empty or
2631 * an empty node-set if @nodes1 doesn't contain @nodes2
2632 */
2633xmlNodeSetPtr
2634xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2635 if (xmlXPathNodeSetIsEmpty(nodes2))
2636 return(nodes1);
2637 return(xmlXPathNodeTrailingSorted(nodes1,
2638 xmlXPathNodeSetItem(nodes2, 0)));
2639}
2640
2641/**
2642 * xmlXPathTrailing:
2643 * @nodes1: a node-set
2644 * @nodes2: a node-set
2645 *
2646 * Implements the EXSLT - Sets trailing() function:
2647 * node-set set:trailing (node-set, node-set)
2648 * @nodes1 and @nodes2 are sorted by document order, then
2649 * #xmlXPathTrailingSorted is called.
2650 *
2651 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2652 * in document order, @nodes1 if @nodes2 is NULL or empty or
2653 * an empty node-set if @nodes1 doesn't contain @nodes2
2654 */
2655xmlNodeSetPtr
2656xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2657 if (xmlXPathNodeSetIsEmpty(nodes2))
2658 return(nodes1);
2659 if (xmlXPathNodeSetIsEmpty(nodes1))
2660 return(xmlXPathNodeSetCreate(NULL));
2661 xmlXPathNodeSetSort(nodes1);
2662 xmlXPathNodeSetSort(nodes2);
2663 return(xmlXPathNodeTrailingSorted(nodes1,
2664 xmlXPathNodeSetItem(nodes2, 0)));
2665}
2666
Owen Taylor3473f882001-02-23 17:55:21 +00002667/************************************************************************
2668 * *
2669 * Routines to handle extra functions *
2670 * *
2671 ************************************************************************/
2672
2673/**
2674 * xmlXPathRegisterFunc:
2675 * @ctxt: the XPath context
2676 * @name: the function name
2677 * @f: the function implementation or NULL
2678 *
2679 * Register a new function. If @f is NULL it unregisters the function
2680 *
2681 * Returns 0 in case of success, -1 in case of error
2682 */
2683int
2684xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2685 xmlXPathFunction f) {
2686 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2687}
2688
2689/**
2690 * xmlXPathRegisterFuncNS:
2691 * @ctxt: the XPath context
2692 * @name: the function name
2693 * @ns_uri: the function namespace URI
2694 * @f: the function implementation or NULL
2695 *
2696 * Register a new function. If @f is NULL it unregisters the function
2697 *
2698 * Returns 0 in case of success, -1 in case of error
2699 */
2700int
2701xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2702 const xmlChar *ns_uri, xmlXPathFunction f) {
2703 if (ctxt == NULL)
2704 return(-1);
2705 if (name == NULL)
2706 return(-1);
2707
2708 if (ctxt->funcHash == NULL)
2709 ctxt->funcHash = xmlHashCreate(0);
2710 if (ctxt->funcHash == NULL)
2711 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002712 if (f == NULL)
2713 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002714 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2715}
2716
2717/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002718 * xmlXPathRegisterFuncLookup:
2719 * @ctxt: the XPath context
2720 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002721 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002722 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002723 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002724 */
2725void
2726xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2727 xmlXPathFuncLookupFunc f,
2728 void *funcCtxt) {
2729 if (ctxt == NULL)
2730 return;
2731 ctxt->funcLookupFunc = (void *) f;
2732 ctxt->funcLookupData = funcCtxt;
2733}
2734
2735/**
Owen Taylor3473f882001-02-23 17:55:21 +00002736 * xmlXPathFunctionLookup:
2737 * @ctxt: the XPath context
2738 * @name: the function name
2739 *
2740 * Search in the Function array of the context for the given
2741 * function.
2742 *
2743 * Returns the xmlXPathFunction or NULL if not found
2744 */
2745xmlXPathFunction
2746xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002747 if (ctxt == NULL)
2748 return (NULL);
2749
2750 if (ctxt->funcLookupFunc != NULL) {
2751 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002752 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002753
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002754 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002755 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002756 if (ret != NULL)
2757 return(ret);
2758 }
Owen Taylor3473f882001-02-23 17:55:21 +00002759 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2760}
2761
2762/**
2763 * xmlXPathFunctionLookupNS:
2764 * @ctxt: the XPath context
2765 * @name: the function name
2766 * @ns_uri: the function namespace URI
2767 *
2768 * Search in the Function array of the context for the given
2769 * function.
2770 *
2771 * Returns the xmlXPathFunction or NULL if not found
2772 */
2773xmlXPathFunction
2774xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2775 const xmlChar *ns_uri) {
2776 if (ctxt == NULL)
2777 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002778 if (name == NULL)
2779 return(NULL);
2780
Thomas Broyerba4ad322001-07-26 16:55:21 +00002781 if (ctxt->funcLookupFunc != NULL) {
2782 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002783 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002784
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002785 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002786 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002787 if (ret != NULL)
2788 return(ret);
2789 }
2790
2791 if (ctxt->funcHash == NULL)
2792 return(NULL);
2793
Owen Taylor3473f882001-02-23 17:55:21 +00002794 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2795}
2796
2797/**
2798 * xmlXPathRegisteredFuncsCleanup:
2799 * @ctxt: the XPath context
2800 *
2801 * Cleanup the XPath context data associated to registered functions
2802 */
2803void
2804xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2805 if (ctxt == NULL)
2806 return;
2807
2808 xmlHashFree(ctxt->funcHash, NULL);
2809 ctxt->funcHash = NULL;
2810}
2811
2812/************************************************************************
2813 * *
2814 * Routines to handle Variable *
2815 * *
2816 ************************************************************************/
2817
2818/**
2819 * xmlXPathRegisterVariable:
2820 * @ctxt: the XPath context
2821 * @name: the variable name
2822 * @value: the variable value or NULL
2823 *
2824 * Register a new variable value. If @value is NULL it unregisters
2825 * the variable
2826 *
2827 * Returns 0 in case of success, -1 in case of error
2828 */
2829int
2830xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2831 xmlXPathObjectPtr value) {
2832 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2833}
2834
2835/**
2836 * xmlXPathRegisterVariableNS:
2837 * @ctxt: the XPath context
2838 * @name: the variable name
2839 * @ns_uri: the variable namespace URI
2840 * @value: the variable value or NULL
2841 *
2842 * Register a new variable value. If @value is NULL it unregisters
2843 * the variable
2844 *
2845 * Returns 0 in case of success, -1 in case of error
2846 */
2847int
2848xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2849 const xmlChar *ns_uri,
2850 xmlXPathObjectPtr value) {
2851 if (ctxt == NULL)
2852 return(-1);
2853 if (name == NULL)
2854 return(-1);
2855
2856 if (ctxt->varHash == NULL)
2857 ctxt->varHash = xmlHashCreate(0);
2858 if (ctxt->varHash == NULL)
2859 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002860 if (value == NULL)
2861 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2862 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002863 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2864 (void *) value,
2865 (xmlHashDeallocator)xmlXPathFreeObject));
2866}
2867
2868/**
2869 * xmlXPathRegisterVariableLookup:
2870 * @ctxt: the XPath context
2871 * @f: the lookup function
2872 * @data: the lookup data
2873 *
2874 * register an external mechanism to do variable lookup
2875 */
2876void
2877xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2878 xmlXPathVariableLookupFunc f, void *data) {
2879 if (ctxt == NULL)
2880 return;
2881 ctxt->varLookupFunc = (void *) f;
2882 ctxt->varLookupData = data;
2883}
2884
2885/**
2886 * xmlXPathVariableLookup:
2887 * @ctxt: the XPath context
2888 * @name: the variable name
2889 *
2890 * Search in the Variable array of the context for the given
2891 * variable value.
2892 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002893 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002894 */
2895xmlXPathObjectPtr
2896xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2897 if (ctxt == NULL)
2898 return(NULL);
2899
2900 if (ctxt->varLookupFunc != NULL) {
2901 xmlXPathObjectPtr ret;
2902
2903 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2904 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002905 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002906 }
2907 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2908}
2909
2910/**
2911 * xmlXPathVariableLookupNS:
2912 * @ctxt: the XPath context
2913 * @name: the variable name
2914 * @ns_uri: the variable namespace URI
2915 *
2916 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002917 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002918 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002919 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002920 */
2921xmlXPathObjectPtr
2922xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2923 const xmlChar *ns_uri) {
2924 if (ctxt == NULL)
2925 return(NULL);
2926
2927 if (ctxt->varLookupFunc != NULL) {
2928 xmlXPathObjectPtr ret;
2929
2930 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2931 (ctxt->varLookupData, name, ns_uri);
2932 if (ret != NULL) return(ret);
2933 }
2934
2935 if (ctxt->varHash == NULL)
2936 return(NULL);
2937 if (name == NULL)
2938 return(NULL);
2939
Daniel Veillard8c357d52001-07-03 23:43:33 +00002940 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2941 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002942}
2943
2944/**
2945 * xmlXPathRegisteredVariablesCleanup:
2946 * @ctxt: the XPath context
2947 *
2948 * Cleanup the XPath context data associated to registered variables
2949 */
2950void
2951xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2952 if (ctxt == NULL)
2953 return;
2954
Daniel Veillard76d66f42001-05-16 21:05:17 +00002955 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002956 ctxt->varHash = NULL;
2957}
2958
2959/**
2960 * xmlXPathRegisterNs:
2961 * @ctxt: the XPath context
2962 * @prefix: the namespace prefix
2963 * @ns_uri: the namespace name
2964 *
2965 * Register a new namespace. If @ns_uri is NULL it unregisters
2966 * the namespace
2967 *
2968 * Returns 0 in case of success, -1 in case of error
2969 */
2970int
2971xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2972 const xmlChar *ns_uri) {
2973 if (ctxt == NULL)
2974 return(-1);
2975 if (prefix == NULL)
2976 return(-1);
2977
2978 if (ctxt->nsHash == NULL)
2979 ctxt->nsHash = xmlHashCreate(10);
2980 if (ctxt->nsHash == NULL)
2981 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00002982 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00002983 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00002984 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00002985 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002986 (xmlHashDeallocator)xmlFree));
2987}
2988
2989/**
2990 * xmlXPathNsLookup:
2991 * @ctxt: the XPath context
2992 * @prefix: the namespace prefix value
2993 *
2994 * Search in the namespace declaration array of the context for the given
2995 * namespace name associated to the given prefix
2996 *
2997 * Returns the value or NULL if not found
2998 */
2999const xmlChar *
3000xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3001 if (ctxt == NULL)
3002 return(NULL);
3003 if (prefix == NULL)
3004 return(NULL);
3005
3006#ifdef XML_XML_NAMESPACE
3007 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3008 return(XML_XML_NAMESPACE);
3009#endif
3010
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003011 if (ctxt->namespaces != NULL) {
3012 int i;
3013
3014 for (i = 0;i < ctxt->nsNr;i++) {
3015 if ((ctxt->namespaces[i] != NULL) &&
3016 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3017 return(ctxt->namespaces[i]->href);
3018 }
3019 }
Owen Taylor3473f882001-02-23 17:55:21 +00003020
3021 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3022}
3023
3024/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003025 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003026 * @ctxt: the XPath context
3027 *
3028 * Cleanup the XPath context data associated to registered variables
3029 */
3030void
3031xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3032 if (ctxt == NULL)
3033 return;
3034
Daniel Veillard42766c02002-08-22 20:52:17 +00003035 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003036 ctxt->nsHash = NULL;
3037}
3038
3039/************************************************************************
3040 * *
3041 * Routines to handle Values *
3042 * *
3043 ************************************************************************/
3044
3045/* Allocations are terrible, one need to optimize all this !!! */
3046
3047/**
3048 * xmlXPathNewFloat:
3049 * @val: the double value
3050 *
3051 * Create a new xmlXPathObjectPtr of type double and of value @val
3052 *
3053 * Returns the newly created object.
3054 */
3055xmlXPathObjectPtr
3056xmlXPathNewFloat(double val) {
3057 xmlXPathObjectPtr ret;
3058
3059 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3060 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003061 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003062 return(NULL);
3063 }
3064 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3065 ret->type = XPATH_NUMBER;
3066 ret->floatval = val;
3067 return(ret);
3068}
3069
3070/**
3071 * xmlXPathNewBoolean:
3072 * @val: the boolean value
3073 *
3074 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3075 *
3076 * Returns the newly created object.
3077 */
3078xmlXPathObjectPtr
3079xmlXPathNewBoolean(int val) {
3080 xmlXPathObjectPtr ret;
3081
3082 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3083 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003084 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003085 return(NULL);
3086 }
3087 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3088 ret->type = XPATH_BOOLEAN;
3089 ret->boolval = (val != 0);
3090 return(ret);
3091}
3092
3093/**
3094 * xmlXPathNewString:
3095 * @val: the xmlChar * value
3096 *
3097 * Create a new xmlXPathObjectPtr of type string and of value @val
3098 *
3099 * Returns the newly created object.
3100 */
3101xmlXPathObjectPtr
3102xmlXPathNewString(const xmlChar *val) {
3103 xmlXPathObjectPtr ret;
3104
3105 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3106 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003107 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003108 return(NULL);
3109 }
3110 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3111 ret->type = XPATH_STRING;
3112 if (val != NULL)
3113 ret->stringval = xmlStrdup(val);
3114 else
3115 ret->stringval = xmlStrdup((const xmlChar *)"");
3116 return(ret);
3117}
3118
3119/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003120 * xmlXPathWrapString:
3121 * @val: the xmlChar * value
3122 *
3123 * Wraps the @val string into an XPath object.
3124 *
3125 * Returns the newly created object.
3126 */
3127xmlXPathObjectPtr
3128xmlXPathWrapString (xmlChar *val) {
3129 xmlXPathObjectPtr ret;
3130
3131 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3132 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003133 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003134 return(NULL);
3135 }
3136 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3137 ret->type = XPATH_STRING;
3138 ret->stringval = val;
3139 return(ret);
3140}
3141
3142/**
Owen Taylor3473f882001-02-23 17:55:21 +00003143 * xmlXPathNewCString:
3144 * @val: the char * value
3145 *
3146 * Create a new xmlXPathObjectPtr of type string and of value @val
3147 *
3148 * Returns the newly created object.
3149 */
3150xmlXPathObjectPtr
3151xmlXPathNewCString(const char *val) {
3152 xmlXPathObjectPtr ret;
3153
3154 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3155 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003156 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003157 return(NULL);
3158 }
3159 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3160 ret->type = XPATH_STRING;
3161 ret->stringval = xmlStrdup(BAD_CAST val);
3162 return(ret);
3163}
3164
3165/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003166 * xmlXPathWrapCString:
3167 * @val: the char * value
3168 *
3169 * Wraps a string into an XPath object.
3170 *
3171 * Returns the newly created object.
3172 */
3173xmlXPathObjectPtr
3174xmlXPathWrapCString (char * val) {
3175 return(xmlXPathWrapString((xmlChar *)(val)));
3176}
3177
3178/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003179 * xmlXPathWrapExternal:
3180 * @val: the user data
3181 *
3182 * Wraps the @val data into an XPath object.
3183 *
3184 * Returns the newly created object.
3185 */
3186xmlXPathObjectPtr
3187xmlXPathWrapExternal (void *val) {
3188 xmlXPathObjectPtr ret;
3189
3190 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3191 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003192 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003193 return(NULL);
3194 }
3195 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3196 ret->type = XPATH_USERS;
3197 ret->user = val;
3198 return(ret);
3199}
3200
3201/**
Owen Taylor3473f882001-02-23 17:55:21 +00003202 * xmlXPathObjectCopy:
3203 * @val: the original object
3204 *
3205 * allocate a new copy of a given object
3206 *
3207 * Returns the newly created object.
3208 */
3209xmlXPathObjectPtr
3210xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3211 xmlXPathObjectPtr ret;
3212
3213 if (val == NULL)
3214 return(NULL);
3215
3216 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3217 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003218 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003219 return(NULL);
3220 }
3221 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3222 switch (val->type) {
3223 case XPATH_BOOLEAN:
3224 case XPATH_NUMBER:
3225 case XPATH_POINT:
3226 case XPATH_RANGE:
3227 break;
3228 case XPATH_STRING:
3229 ret->stringval = xmlStrdup(val->stringval);
3230 break;
3231 case XPATH_XSLT_TREE:
3232 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003233 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003234 xmlNodePtr cur, tmp;
3235 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003236
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003237 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003238 top = xmlNewDoc(NULL);
3239 top->name = (char *)
3240 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003241 ret->user = top;
3242 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003243 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003244 cur = val->nodesetval->nodeTab[0]->children;
3245 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003246 tmp = xmlDocCopyNode(cur, top, 1);
3247 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003248 cur = cur->next;
3249 }
3250 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003251 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003252 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003253 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003254 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003255 break;
3256 case XPATH_NODESET:
3257 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003258 /* Do not deallocate the copied tree value */
3259 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003260 break;
3261 case XPATH_LOCATIONSET:
3262#ifdef LIBXML_XPTR_ENABLED
3263 {
3264 xmlLocationSetPtr loc = val->user;
3265 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3266 break;
3267 }
3268#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003269 case XPATH_USERS:
3270 ret->user = val->user;
3271 break;
3272 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003273 xmlGenericError(xmlGenericErrorContext,
3274 "xmlXPathObjectCopy: unsupported type %d\n",
3275 val->type);
3276 break;
3277 }
3278 return(ret);
3279}
3280
3281/**
3282 * xmlXPathFreeObject:
3283 * @obj: the object to free
3284 *
3285 * Free up an xmlXPathObjectPtr object.
3286 */
3287void
3288xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3289 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003290 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003291 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003292 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003293 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003294 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003295 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003296 xmlXPathFreeValueTree(obj->nodesetval);
3297 } else {
3298 if (obj->nodesetval != NULL)
3299 xmlXPathFreeNodeSet(obj->nodesetval);
3300 }
Owen Taylor3473f882001-02-23 17:55:21 +00003301#ifdef LIBXML_XPTR_ENABLED
3302 } else if (obj->type == XPATH_LOCATIONSET) {
3303 if (obj->user != NULL)
3304 xmlXPtrFreeLocationSet(obj->user);
3305#endif
3306 } else if (obj->type == XPATH_STRING) {
3307 if (obj->stringval != NULL)
3308 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003309 }
3310
Owen Taylor3473f882001-02-23 17:55:21 +00003311 xmlFree(obj);
3312}
3313
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003314
3315/************************************************************************
3316 * *
3317 * Type Casting Routines *
3318 * *
3319 ************************************************************************/
3320
3321/**
3322 * xmlXPathCastBooleanToString:
3323 * @val: a boolean
3324 *
3325 * Converts a boolean to its string value.
3326 *
3327 * Returns a newly allocated string.
3328 */
3329xmlChar *
3330xmlXPathCastBooleanToString (int val) {
3331 xmlChar *ret;
3332 if (val)
3333 ret = xmlStrdup((const xmlChar *) "true");
3334 else
3335 ret = xmlStrdup((const xmlChar *) "false");
3336 return(ret);
3337}
3338
3339/**
3340 * xmlXPathCastNumberToString:
3341 * @val: a number
3342 *
3343 * Converts a number to its string value.
3344 *
3345 * Returns a newly allocated string.
3346 */
3347xmlChar *
3348xmlXPathCastNumberToString (double val) {
3349 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003350 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003351 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003352 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003353 break;
3354 case -1:
3355 ret = xmlStrdup((const xmlChar *) "-Infinity");
3356 break;
3357 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003358 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003359 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003360 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3361 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003362 } else {
3363 /* could be improved */
3364 char buf[100];
3365 xmlXPathFormatNumber(val, buf, 100);
3366 ret = xmlStrdup((const xmlChar *) buf);
3367 }
3368 }
3369 return(ret);
3370}
3371
3372/**
3373 * xmlXPathCastNodeToString:
3374 * @node: a node
3375 *
3376 * Converts a node to its string value.
3377 *
3378 * Returns a newly allocated string.
3379 */
3380xmlChar *
3381xmlXPathCastNodeToString (xmlNodePtr node) {
3382 return(xmlNodeGetContent(node));
3383}
3384
3385/**
3386 * xmlXPathCastNodeSetToString:
3387 * @ns: a node-set
3388 *
3389 * Converts a node-set to its string value.
3390 *
3391 * Returns a newly allocated string.
3392 */
3393xmlChar *
3394xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3395 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3396 return(xmlStrdup((const xmlChar *) ""));
3397
3398 xmlXPathNodeSetSort(ns);
3399 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3400}
3401
3402/**
3403 * xmlXPathCastToString:
3404 * @val: an XPath object
3405 *
3406 * Converts an existing object to its string() equivalent
3407 *
3408 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003409 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003410 * string object).
3411 */
3412xmlChar *
3413xmlXPathCastToString(xmlXPathObjectPtr val) {
3414 xmlChar *ret = NULL;
3415
3416 if (val == NULL)
3417 return(xmlStrdup((const xmlChar *) ""));
3418 switch (val->type) {
3419 case XPATH_UNDEFINED:
3420#ifdef DEBUG_EXPR
3421 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3422#endif
3423 ret = xmlStrdup((const xmlChar *) "");
3424 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003425 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003426 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003427 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3428 break;
3429 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003430 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003431 case XPATH_BOOLEAN:
3432 ret = xmlXPathCastBooleanToString(val->boolval);
3433 break;
3434 case XPATH_NUMBER: {
3435 ret = xmlXPathCastNumberToString(val->floatval);
3436 break;
3437 }
3438 case XPATH_USERS:
3439 case XPATH_POINT:
3440 case XPATH_RANGE:
3441 case XPATH_LOCATIONSET:
3442 TODO
3443 ret = xmlStrdup((const xmlChar *) "");
3444 break;
3445 }
3446 return(ret);
3447}
3448
3449/**
3450 * xmlXPathConvertString:
3451 * @val: an XPath object
3452 *
3453 * Converts an existing object to its string() equivalent
3454 *
3455 * Returns the new object, the old one is freed (or the operation
3456 * is done directly on @val)
3457 */
3458xmlXPathObjectPtr
3459xmlXPathConvertString(xmlXPathObjectPtr val) {
3460 xmlChar *res = NULL;
3461
3462 if (val == NULL)
3463 return(xmlXPathNewCString(""));
3464
3465 switch (val->type) {
3466 case XPATH_UNDEFINED:
3467#ifdef DEBUG_EXPR
3468 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3469#endif
3470 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003471 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003472 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003473 res = xmlXPathCastNodeSetToString(val->nodesetval);
3474 break;
3475 case XPATH_STRING:
3476 return(val);
3477 case XPATH_BOOLEAN:
3478 res = xmlXPathCastBooleanToString(val->boolval);
3479 break;
3480 case XPATH_NUMBER:
3481 res = xmlXPathCastNumberToString(val->floatval);
3482 break;
3483 case XPATH_USERS:
3484 case XPATH_POINT:
3485 case XPATH_RANGE:
3486 case XPATH_LOCATIONSET:
3487 TODO;
3488 break;
3489 }
3490 xmlXPathFreeObject(val);
3491 if (res == NULL)
3492 return(xmlXPathNewCString(""));
3493 return(xmlXPathWrapString(res));
3494}
3495
3496/**
3497 * xmlXPathCastBooleanToNumber:
3498 * @val: a boolean
3499 *
3500 * Converts a boolean to its number value
3501 *
3502 * Returns the number value
3503 */
3504double
3505xmlXPathCastBooleanToNumber(int val) {
3506 if (val)
3507 return(1.0);
3508 return(0.0);
3509}
3510
3511/**
3512 * xmlXPathCastStringToNumber:
3513 * @val: a string
3514 *
3515 * Converts a string to its number value
3516 *
3517 * Returns the number value
3518 */
3519double
3520xmlXPathCastStringToNumber(const xmlChar * val) {
3521 return(xmlXPathStringEvalNumber(val));
3522}
3523
3524/**
3525 * xmlXPathCastNodeToNumber:
3526 * @node: a node
3527 *
3528 * Converts a node to its number value
3529 *
3530 * Returns the number value
3531 */
3532double
3533xmlXPathCastNodeToNumber (xmlNodePtr node) {
3534 xmlChar *strval;
3535 double ret;
3536
3537 if (node == NULL)
3538 return(xmlXPathNAN);
3539 strval = xmlXPathCastNodeToString(node);
3540 if (strval == NULL)
3541 return(xmlXPathNAN);
3542 ret = xmlXPathCastStringToNumber(strval);
3543 xmlFree(strval);
3544
3545 return(ret);
3546}
3547
3548/**
3549 * xmlXPathCastNodeSetToNumber:
3550 * @ns: a node-set
3551 *
3552 * Converts a node-set to its number value
3553 *
3554 * Returns the number value
3555 */
3556double
3557xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3558 xmlChar *str;
3559 double ret;
3560
3561 if (ns == NULL)
3562 return(xmlXPathNAN);
3563 str = xmlXPathCastNodeSetToString(ns);
3564 ret = xmlXPathCastStringToNumber(str);
3565 xmlFree(str);
3566 return(ret);
3567}
3568
3569/**
3570 * xmlXPathCastToNumber:
3571 * @val: an XPath object
3572 *
3573 * Converts an XPath object to its number value
3574 *
3575 * Returns the number value
3576 */
3577double
3578xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3579 double ret = 0.0;
3580
3581 if (val == NULL)
3582 return(xmlXPathNAN);
3583 switch (val->type) {
3584 case XPATH_UNDEFINED:
3585#ifdef DEGUB_EXPR
3586 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3587#endif
3588 ret = xmlXPathNAN;
3589 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003590 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003591 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003592 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3593 break;
3594 case XPATH_STRING:
3595 ret = xmlXPathCastStringToNumber(val->stringval);
3596 break;
3597 case XPATH_NUMBER:
3598 ret = val->floatval;
3599 break;
3600 case XPATH_BOOLEAN:
3601 ret = xmlXPathCastBooleanToNumber(val->boolval);
3602 break;
3603 case XPATH_USERS:
3604 case XPATH_POINT:
3605 case XPATH_RANGE:
3606 case XPATH_LOCATIONSET:
3607 TODO;
3608 ret = xmlXPathNAN;
3609 break;
3610 }
3611 return(ret);
3612}
3613
3614/**
3615 * xmlXPathConvertNumber:
3616 * @val: an XPath object
3617 *
3618 * Converts an existing object to its number() equivalent
3619 *
3620 * Returns the new object, the old one is freed (or the operation
3621 * is done directly on @val)
3622 */
3623xmlXPathObjectPtr
3624xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3625 xmlXPathObjectPtr ret;
3626
3627 if (val == NULL)
3628 return(xmlXPathNewFloat(0.0));
3629 if (val->type == XPATH_NUMBER)
3630 return(val);
3631 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3632 xmlXPathFreeObject(val);
3633 return(ret);
3634}
3635
3636/**
3637 * xmlXPathCastNumberToBoolean:
3638 * @val: a number
3639 *
3640 * Converts a number to its boolean value
3641 *
3642 * Returns the boolean value
3643 */
3644int
3645xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003646 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003647 return(0);
3648 return(1);
3649}
3650
3651/**
3652 * xmlXPathCastStringToBoolean:
3653 * @val: a string
3654 *
3655 * Converts a string to its boolean value
3656 *
3657 * Returns the boolean value
3658 */
3659int
3660xmlXPathCastStringToBoolean (const xmlChar *val) {
3661 if ((val == NULL) || (xmlStrlen(val) == 0))
3662 return(0);
3663 return(1);
3664}
3665
3666/**
3667 * xmlXPathCastNodeSetToBoolean:
3668 * @ns: a node-set
3669 *
3670 * Converts a node-set to its boolean value
3671 *
3672 * Returns the boolean value
3673 */
3674int
3675xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3676 if ((ns == NULL) || (ns->nodeNr == 0))
3677 return(0);
3678 return(1);
3679}
3680
3681/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003682 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003683 * @val: an XPath object
3684 *
3685 * Converts an XPath object to its boolean value
3686 *
3687 * Returns the boolean value
3688 */
3689int
3690xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3691 int ret = 0;
3692
3693 if (val == NULL)
3694 return(0);
3695 switch (val->type) {
3696 case XPATH_UNDEFINED:
3697#ifdef DEBUG_EXPR
3698 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3699#endif
3700 ret = 0;
3701 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003702 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003703 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003704 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3705 break;
3706 case XPATH_STRING:
3707 ret = xmlXPathCastStringToBoolean(val->stringval);
3708 break;
3709 case XPATH_NUMBER:
3710 ret = xmlXPathCastNumberToBoolean(val->floatval);
3711 break;
3712 case XPATH_BOOLEAN:
3713 ret = val->boolval;
3714 break;
3715 case XPATH_USERS:
3716 case XPATH_POINT:
3717 case XPATH_RANGE:
3718 case XPATH_LOCATIONSET:
3719 TODO;
3720 ret = 0;
3721 break;
3722 }
3723 return(ret);
3724}
3725
3726
3727/**
3728 * xmlXPathConvertBoolean:
3729 * @val: an XPath object
3730 *
3731 * Converts an existing object to its boolean() equivalent
3732 *
3733 * Returns the new object, the old one is freed (or the operation
3734 * is done directly on @val)
3735 */
3736xmlXPathObjectPtr
3737xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3738 xmlXPathObjectPtr ret;
3739
3740 if (val == NULL)
3741 return(xmlXPathNewBoolean(0));
3742 if (val->type == XPATH_BOOLEAN)
3743 return(val);
3744 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3745 xmlXPathFreeObject(val);
3746 return(ret);
3747}
3748
Owen Taylor3473f882001-02-23 17:55:21 +00003749/************************************************************************
3750 * *
3751 * Routines to handle XPath contexts *
3752 * *
3753 ************************************************************************/
3754
3755/**
3756 * xmlXPathNewContext:
3757 * @doc: the XML document
3758 *
3759 * Create a new xmlXPathContext
3760 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003761 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003762 */
3763xmlXPathContextPtr
3764xmlXPathNewContext(xmlDocPtr doc) {
3765 xmlXPathContextPtr ret;
3766
3767 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3768 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003769 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003770 return(NULL);
3771 }
3772 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3773 ret->doc = doc;
3774 ret->node = NULL;
3775
3776 ret->varHash = NULL;
3777
3778 ret->nb_types = 0;
3779 ret->max_types = 0;
3780 ret->types = NULL;
3781
3782 ret->funcHash = xmlHashCreate(0);
3783
3784 ret->nb_axis = 0;
3785 ret->max_axis = 0;
3786 ret->axis = NULL;
3787
3788 ret->nsHash = NULL;
3789 ret->user = NULL;
3790
3791 ret->contextSize = -1;
3792 ret->proximityPosition = -1;
3793
3794 xmlXPathRegisterAllFunctions(ret);
3795
3796 return(ret);
3797}
3798
3799/**
3800 * xmlXPathFreeContext:
3801 * @ctxt: the context to free
3802 *
3803 * Free up an xmlXPathContext
3804 */
3805void
3806xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3807 xmlXPathRegisteredNsCleanup(ctxt);
3808 xmlXPathRegisteredFuncsCleanup(ctxt);
3809 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003810 xmlFree(ctxt);
3811}
3812
3813/************************************************************************
3814 * *
3815 * Routines to handle XPath parser contexts *
3816 * *
3817 ************************************************************************/
3818
3819#define CHECK_CTXT(ctxt) \
3820 if (ctxt == NULL) { \
3821 xmlGenericError(xmlGenericErrorContext, \
3822 "%s:%d Internal error: ctxt == NULL\n", \
3823 __FILE__, __LINE__); \
3824 } \
3825
3826
3827#define CHECK_CONTEXT(ctxt) \
3828 if (ctxt == NULL) { \
3829 xmlGenericError(xmlGenericErrorContext, \
3830 "%s:%d Internal error: no context\n", \
3831 __FILE__, __LINE__); \
3832 } \
3833 else if (ctxt->doc == NULL) { \
3834 xmlGenericError(xmlGenericErrorContext, \
3835 "%s:%d Internal error: no document\n", \
3836 __FILE__, __LINE__); \
3837 } \
3838 else if (ctxt->doc->children == NULL) { \
3839 xmlGenericError(xmlGenericErrorContext, \
3840 "%s:%d Internal error: document without root\n", \
3841 __FILE__, __LINE__); \
3842 } \
3843
3844
3845/**
3846 * xmlXPathNewParserContext:
3847 * @str: the XPath expression
3848 * @ctxt: the XPath context
3849 *
3850 * Create a new xmlXPathParserContext
3851 *
3852 * Returns the xmlXPathParserContext just allocated.
3853 */
3854xmlXPathParserContextPtr
3855xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3856 xmlXPathParserContextPtr ret;
3857
3858 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3859 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003860 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003861 return(NULL);
3862 }
3863 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3864 ret->cur = ret->base = str;
3865 ret->context = ctxt;
3866
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003867 ret->comp = xmlXPathNewCompExpr();
3868 if (ret->comp == NULL) {
3869 xmlFree(ret->valueTab);
3870 xmlFree(ret);
3871 return(NULL);
3872 }
3873
3874 return(ret);
3875}
3876
3877/**
3878 * xmlXPathCompParserContext:
3879 * @comp: the XPath compiled expression
3880 * @ctxt: the XPath context
3881 *
3882 * Create a new xmlXPathParserContext when processing a compiled expression
3883 *
3884 * Returns the xmlXPathParserContext just allocated.
3885 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003886static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003887xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3888 xmlXPathParserContextPtr ret;
3889
3890 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3891 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003892 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003893 return(NULL);
3894 }
3895 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3896
Owen Taylor3473f882001-02-23 17:55:21 +00003897 /* Allocate the value stack */
3898 ret->valueTab = (xmlXPathObjectPtr *)
3899 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003900 if (ret->valueTab == NULL) {
3901 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003902 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003903 return(NULL);
3904 }
Owen Taylor3473f882001-02-23 17:55:21 +00003905 ret->valueNr = 0;
3906 ret->valueMax = 10;
3907 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003908
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003909 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003910 ret->comp = comp;
3911
Owen Taylor3473f882001-02-23 17:55:21 +00003912 return(ret);
3913}
3914
3915/**
3916 * xmlXPathFreeParserContext:
3917 * @ctxt: the context to free
3918 *
3919 * Free up an xmlXPathParserContext
3920 */
3921void
3922xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3923 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003924 xmlFree(ctxt->valueTab);
3925 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003926 if (ctxt->comp)
3927 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003928 xmlFree(ctxt);
3929}
3930
3931/************************************************************************
3932 * *
3933 * The implicit core function library *
3934 * *
3935 ************************************************************************/
3936
Owen Taylor3473f882001-02-23 17:55:21 +00003937/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003938 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003939 * @node: a node pointer
3940 *
3941 * Function computing the beginning of the string value of the node,
3942 * used to speed up comparisons
3943 *
3944 * Returns an int usable as a hash
3945 */
3946static unsigned int
3947xmlXPathNodeValHash(xmlNodePtr node) {
3948 int len = 2;
3949 const xmlChar * string = NULL;
3950 xmlNodePtr tmp = NULL;
3951 unsigned int ret = 0;
3952
3953 if (node == NULL)
3954 return(0);
3955
Daniel Veillard9adc0462003-03-24 18:39:54 +00003956 if (node->type == XML_DOCUMENT_NODE) {
3957 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3958 if (tmp == NULL)
3959 node = node->children;
3960 else
3961 node = tmp;
3962
3963 if (node == NULL)
3964 return(0);
3965 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003966
3967 switch (node->type) {
3968 case XML_COMMENT_NODE:
3969 case XML_PI_NODE:
3970 case XML_CDATA_SECTION_NODE:
3971 case XML_TEXT_NODE:
3972 string = node->content;
3973 if (string == NULL)
3974 return(0);
3975 if (string[0] == 0)
3976 return(0);
3977 return(((unsigned int) string[0]) +
3978 (((unsigned int) string[1]) << 8));
3979 case XML_NAMESPACE_DECL:
3980 string = ((xmlNsPtr)node)->href;
3981 if (string == NULL)
3982 return(0);
3983 if (string[0] == 0)
3984 return(0);
3985 return(((unsigned int) string[0]) +
3986 (((unsigned int) string[1]) << 8));
3987 case XML_ATTRIBUTE_NODE:
3988 tmp = ((xmlAttrPtr) node)->children;
3989 break;
3990 case XML_ELEMENT_NODE:
3991 tmp = node->children;
3992 break;
3993 default:
3994 return(0);
3995 }
3996 while (tmp != NULL) {
3997 switch (tmp->type) {
3998 case XML_COMMENT_NODE:
3999 case XML_PI_NODE:
4000 case XML_CDATA_SECTION_NODE:
4001 case XML_TEXT_NODE:
4002 string = tmp->content;
4003 break;
4004 case XML_NAMESPACE_DECL:
4005 string = ((xmlNsPtr)tmp)->href;
4006 break;
4007 default:
4008 break;
4009 }
4010 if ((string != NULL) && (string[0] != 0)) {
4011 if (string[0] == 0)
4012 return(0);
4013 if (len == 1) {
4014 return(ret + (((unsigned int) string[0]) << 8));
4015 }
4016 if (string[1] == 0) {
4017 len = 1;
4018 ret = (unsigned int) string[0];
4019 } else {
4020 return(((unsigned int) string[0]) +
4021 (((unsigned int) string[1]) << 8));
4022 }
4023 }
4024 /*
4025 * Skip to next node
4026 */
4027 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4028 if (tmp->children->type != XML_ENTITY_DECL) {
4029 tmp = tmp->children;
4030 continue;
4031 }
4032 }
4033 if (tmp == node)
4034 break;
4035
4036 if (tmp->next != NULL) {
4037 tmp = tmp->next;
4038 continue;
4039 }
4040
4041 do {
4042 tmp = tmp->parent;
4043 if (tmp == NULL)
4044 break;
4045 if (tmp == node) {
4046 tmp = NULL;
4047 break;
4048 }
4049 if (tmp->next != NULL) {
4050 tmp = tmp->next;
4051 break;
4052 }
4053 } while (tmp != NULL);
4054 }
4055 return(ret);
4056}
4057
4058/**
4059 * xmlXPathStringHash:
4060 * @string: a string
4061 *
4062 * Function computing the beginning of the string value of the node,
4063 * used to speed up comparisons
4064 *
4065 * Returns an int usable as a hash
4066 */
4067static unsigned int
4068xmlXPathStringHash(const xmlChar * string) {
4069 if (string == NULL)
4070 return((unsigned int) 0);
4071 if (string[0] == 0)
4072 return(0);
4073 return(((unsigned int) string[0]) +
4074 (((unsigned int) string[1]) << 8));
4075}
4076
4077/**
Owen Taylor3473f882001-02-23 17:55:21 +00004078 * xmlXPathCompareNodeSetFloat:
4079 * @ctxt: the XPath Parser context
4080 * @inf: less than (1) or greater than (0)
4081 * @strict: is the comparison strict
4082 * @arg: the node set
4083 * @f: the value
4084 *
4085 * Implement the compare operation between a nodeset and a number
4086 * @ns < @val (1, 1, ...
4087 * @ns <= @val (1, 0, ...
4088 * @ns > @val (0, 1, ...
4089 * @ns >= @val (0, 0, ...
4090 *
4091 * If one object to be compared is a node-set and the other is a number,
4092 * then the comparison will be true if and only if there is a node in the
4093 * node-set such that the result of performing the comparison on the number
4094 * to be compared and on the result of converting the string-value of that
4095 * node to a number using the number function is true.
4096 *
4097 * Returns 0 or 1 depending on the results of the test.
4098 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004099static int
Owen Taylor3473f882001-02-23 17:55:21 +00004100xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4101 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4102 int i, ret = 0;
4103 xmlNodeSetPtr ns;
4104 xmlChar *str2;
4105
4106 if ((f == NULL) || (arg == NULL) ||
4107 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4108 xmlXPathFreeObject(arg);
4109 xmlXPathFreeObject(f);
4110 return(0);
4111 }
4112 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004113 if (ns != NULL) {
4114 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004115 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004116 if (str2 != NULL) {
4117 valuePush(ctxt,
4118 xmlXPathNewString(str2));
4119 xmlFree(str2);
4120 xmlXPathNumberFunction(ctxt, 1);
4121 valuePush(ctxt, xmlXPathObjectCopy(f));
4122 ret = xmlXPathCompareValues(ctxt, inf, strict);
4123 if (ret)
4124 break;
4125 }
4126 }
Owen Taylor3473f882001-02-23 17:55:21 +00004127 }
4128 xmlXPathFreeObject(arg);
4129 xmlXPathFreeObject(f);
4130 return(ret);
4131}
4132
4133/**
4134 * xmlXPathCompareNodeSetString:
4135 * @ctxt: the XPath Parser context
4136 * @inf: less than (1) or greater than (0)
4137 * @strict: is the comparison strict
4138 * @arg: the node set
4139 * @s: the value
4140 *
4141 * Implement the compare operation between a nodeset and a string
4142 * @ns < @val (1, 1, ...
4143 * @ns <= @val (1, 0, ...
4144 * @ns > @val (0, 1, ...
4145 * @ns >= @val (0, 0, ...
4146 *
4147 * If one object to be compared is a node-set and the other is a string,
4148 * then the comparison will be true if and only if there is a node in
4149 * the node-set such that the result of performing the comparison on the
4150 * string-value of the node and the other string is true.
4151 *
4152 * Returns 0 or 1 depending on the results of the test.
4153 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004154static int
Owen Taylor3473f882001-02-23 17:55:21 +00004155xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4156 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4157 int i, ret = 0;
4158 xmlNodeSetPtr ns;
4159 xmlChar *str2;
4160
4161 if ((s == NULL) || (arg == NULL) ||
4162 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4163 xmlXPathFreeObject(arg);
4164 xmlXPathFreeObject(s);
4165 return(0);
4166 }
4167 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004168 if (ns != NULL) {
4169 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004170 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004171 if (str2 != NULL) {
4172 valuePush(ctxt,
4173 xmlXPathNewString(str2));
4174 xmlFree(str2);
4175 valuePush(ctxt, xmlXPathObjectCopy(s));
4176 ret = xmlXPathCompareValues(ctxt, inf, strict);
4177 if (ret)
4178 break;
4179 }
4180 }
Owen Taylor3473f882001-02-23 17:55:21 +00004181 }
4182 xmlXPathFreeObject(arg);
4183 xmlXPathFreeObject(s);
4184 return(ret);
4185}
4186
4187/**
4188 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004189 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004190 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004191 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004192 * @arg2: the second node set object
4193 *
4194 * Implement the compare operation on nodesets:
4195 *
4196 * If both objects to be compared are node-sets, then the comparison
4197 * will be true if and only if there is a node in the first node-set
4198 * and a node in the second node-set such that the result of performing
4199 * the comparison on the string-values of the two nodes is true.
4200 * ....
4201 * When neither object to be compared is a node-set and the operator
4202 * is <=, <, >= or >, then the objects are compared by converting both
4203 * objects to numbers and comparing the numbers according to IEEE 754.
4204 * ....
4205 * The number function converts its argument to a number as follows:
4206 * - a string that consists of optional whitespace followed by an
4207 * optional minus sign followed by a Number followed by whitespace
4208 * is converted to the IEEE 754 number that is nearest (according
4209 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4210 * represented by the string; any other string is converted to NaN
4211 *
4212 * Conclusion all nodes need to be converted first to their string value
4213 * and then the comparison must be done when possible
4214 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004215static int
4216xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004217 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4218 int i, j, init = 0;
4219 double val1;
4220 double *values2;
4221 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004222 xmlNodeSetPtr ns1;
4223 xmlNodeSetPtr ns2;
4224
4225 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004226 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4227 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004228 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004229 }
Owen Taylor3473f882001-02-23 17:55:21 +00004230 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004231 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4232 xmlXPathFreeObject(arg1);
4233 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004234 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004235 }
Owen Taylor3473f882001-02-23 17:55:21 +00004236
4237 ns1 = arg1->nodesetval;
4238 ns2 = arg2->nodesetval;
4239
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004240 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004241 xmlXPathFreeObject(arg1);
4242 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004243 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004244 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004245 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004246 xmlXPathFreeObject(arg1);
4247 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004248 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004249 }
Owen Taylor3473f882001-02-23 17:55:21 +00004250
4251 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4252 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004253 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004254 xmlXPathFreeObject(arg1);
4255 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004256 return(0);
4257 }
4258 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004259 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004260 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004261 continue;
4262 for (j = 0;j < ns2->nodeNr;j++) {
4263 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004264 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004265 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004266 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004267 continue;
4268 if (inf && strict)
4269 ret = (val1 < values2[j]);
4270 else if (inf && !strict)
4271 ret = (val1 <= values2[j]);
4272 else if (!inf && strict)
4273 ret = (val1 > values2[j]);
4274 else if (!inf && !strict)
4275 ret = (val1 >= values2[j]);
4276 if (ret)
4277 break;
4278 }
4279 if (ret)
4280 break;
4281 init = 1;
4282 }
4283 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004284 xmlXPathFreeObject(arg1);
4285 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004286 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004287}
4288
4289/**
4290 * xmlXPathCompareNodeSetValue:
4291 * @ctxt: the XPath Parser context
4292 * @inf: less than (1) or greater than (0)
4293 * @strict: is the comparison strict
4294 * @arg: the node set
4295 * @val: the value
4296 *
4297 * Implement the compare operation between a nodeset and a value
4298 * @ns < @val (1, 1, ...
4299 * @ns <= @val (1, 0, ...
4300 * @ns > @val (0, 1, ...
4301 * @ns >= @val (0, 0, ...
4302 *
4303 * If one object to be compared is a node-set and the other is a boolean,
4304 * then the comparison will be true if and only if the result of performing
4305 * the comparison on the boolean and on the result of converting
4306 * the node-set to a boolean using the boolean function is true.
4307 *
4308 * Returns 0 or 1 depending on the results of the test.
4309 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004310static int
Owen Taylor3473f882001-02-23 17:55:21 +00004311xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4312 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4313 if ((val == NULL) || (arg == NULL) ||
4314 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4315 return(0);
4316
4317 switch(val->type) {
4318 case XPATH_NUMBER:
4319 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4320 case XPATH_NODESET:
4321 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004322 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004323 case XPATH_STRING:
4324 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4325 case XPATH_BOOLEAN:
4326 valuePush(ctxt, arg);
4327 xmlXPathBooleanFunction(ctxt, 1);
4328 valuePush(ctxt, val);
4329 return(xmlXPathCompareValues(ctxt, inf, strict));
4330 default:
4331 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004332 }
4333 return(0);
4334}
4335
4336/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004337 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004338 * @arg: the nodeset object argument
4339 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004340 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004341 *
4342 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4343 * If one object to be compared is a node-set and the other is a string,
4344 * then the comparison will be true if and only if there is a node in
4345 * the node-set such that the result of performing the comparison on the
4346 * string-value of the node and the other string is true.
4347 *
4348 * Returns 0 or 1 depending on the results of the test.
4349 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004350static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004351xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004352{
Owen Taylor3473f882001-02-23 17:55:21 +00004353 int i;
4354 xmlNodeSetPtr ns;
4355 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004356 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004357
4358 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004359 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4360 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004361 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004362 /*
4363 * A NULL nodeset compared with a string is always false
4364 * (since there is no node equal, and no node not equal)
4365 */
4366 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004367 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004368 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004369 for (i = 0; i < ns->nodeNr; i++) {
4370 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4371 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4372 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4373 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004374 if (neq)
4375 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004376 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004377 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4378 if (neq)
4379 continue;
4380 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004381 } else if (neq) {
4382 if (str2 != NULL)
4383 xmlFree(str2);
4384 return (1);
4385 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004386 if (str2 != NULL)
4387 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004388 } else if (neq)
4389 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004390 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004391 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004392}
4393
4394/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004395 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004396 * @arg: the nodeset object argument
4397 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004398 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004399 *
4400 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4401 * If one object to be compared is a node-set and the other is a number,
4402 * then the comparison will be true if and only if there is a node in
4403 * the node-set such that the result of performing the comparison on the
4404 * number to be compared and on the result of converting the string-value
4405 * of that node to a number using the number function is true.
4406 *
4407 * Returns 0 or 1 depending on the results of the test.
4408 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004409static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004410xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4411 xmlXPathObjectPtr arg, double f, int neq) {
4412 int i, ret=0;
4413 xmlNodeSetPtr ns;
4414 xmlChar *str2;
4415 xmlXPathObjectPtr val;
4416 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004417
4418 if ((arg == NULL) ||
4419 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4420 return(0);
4421
William M. Brack0c022ad2002-07-12 00:56:01 +00004422 ns = arg->nodesetval;
4423 if (ns != NULL) {
4424 for (i=0;i<ns->nodeNr;i++) {
4425 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4426 if (str2 != NULL) {
4427 valuePush(ctxt, xmlXPathNewString(str2));
4428 xmlFree(str2);
4429 xmlXPathNumberFunction(ctxt, 1);
4430 val = valuePop(ctxt);
4431 v = val->floatval;
4432 xmlXPathFreeObject(val);
4433 if (!xmlXPathIsNaN(v)) {
4434 if ((!neq) && (v==f)) {
4435 ret = 1;
4436 break;
4437 } else if ((neq) && (v!=f)) {
4438 ret = 1;
4439 break;
4440 }
4441 }
4442 }
4443 }
4444 }
4445
4446 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004447}
4448
4449
4450/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004451 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004452 * @arg1: first nodeset object argument
4453 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004454 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004455 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004456 * Implement the equal / not equal operation on XPath nodesets:
4457 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004458 * If both objects to be compared are node-sets, then the comparison
4459 * will be true if and only if there is a node in the first node-set and
4460 * a node in the second node-set such that the result of performing the
4461 * comparison on the string-values of the two nodes is true.
4462 *
4463 * (needless to say, this is a costly operation)
4464 *
4465 * Returns 0 or 1 depending on the results of the test.
4466 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004467static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004468xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004469 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004470 unsigned int *hashs1;
4471 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004472 xmlChar **values1;
4473 xmlChar **values2;
4474 int ret = 0;
4475 xmlNodeSetPtr ns1;
4476 xmlNodeSetPtr ns2;
4477
4478 if ((arg1 == NULL) ||
4479 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4480 return(0);
4481 if ((arg2 == NULL) ||
4482 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4483 return(0);
4484
4485 ns1 = arg1->nodesetval;
4486 ns2 = arg2->nodesetval;
4487
Daniel Veillard911f49a2001-04-07 15:39:35 +00004488 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004489 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004490 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004491 return(0);
4492
4493 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004494 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004495 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004496 if (neq == 0)
4497 for (i = 0;i < ns1->nodeNr;i++)
4498 for (j = 0;j < ns2->nodeNr;j++)
4499 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4500 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004501
4502 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004503 if (values1 == NULL) {
4504 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004505 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004506 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004507 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4508 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004509 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004510 xmlFree(values1);
4511 return(0);
4512 }
Owen Taylor3473f882001-02-23 17:55:21 +00004513 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4514 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4515 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004516 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004517 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004518 xmlFree(values1);
4519 return(0);
4520 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004521 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4522 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004523 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004524 xmlFree(hashs1);
4525 xmlFree(values1);
4526 xmlFree(values2);
4527 return(0);
4528 }
Owen Taylor3473f882001-02-23 17:55:21 +00004529 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4530 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004531 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004532 for (j = 0;j < ns2->nodeNr;j++) {
4533 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004534 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004535 if (hashs1[i] != hashs2[j]) {
4536 if (neq) {
4537 ret = 1;
4538 break;
4539 }
4540 }
4541 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004542 if (values1[i] == NULL)
4543 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4544 if (values2[j] == NULL)
4545 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004546 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004547 if (ret)
4548 break;
4549 }
Owen Taylor3473f882001-02-23 17:55:21 +00004550 }
4551 if (ret)
4552 break;
4553 }
4554 for (i = 0;i < ns1->nodeNr;i++)
4555 if (values1[i] != NULL)
4556 xmlFree(values1[i]);
4557 for (j = 0;j < ns2->nodeNr;j++)
4558 if (values2[j] != NULL)
4559 xmlFree(values2[j]);
4560 xmlFree(values1);
4561 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004562 xmlFree(hashs1);
4563 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004564 return(ret);
4565}
4566
William M. Brack0c022ad2002-07-12 00:56:01 +00004567static int
4568xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4569 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004570 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004571 /*
4572 *At this point we are assured neither arg1 nor arg2
4573 *is a nodeset, so we can just pick the appropriate routine.
4574 */
Owen Taylor3473f882001-02-23 17:55:21 +00004575 switch (arg1->type) {
4576 case XPATH_UNDEFINED:
4577#ifdef DEBUG_EXPR
4578 xmlGenericError(xmlGenericErrorContext,
4579 "Equal: undefined\n");
4580#endif
4581 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004582 case XPATH_BOOLEAN:
4583 switch (arg2->type) {
4584 case XPATH_UNDEFINED:
4585#ifdef DEBUG_EXPR
4586 xmlGenericError(xmlGenericErrorContext,
4587 "Equal: undefined\n");
4588#endif
4589 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004590 case XPATH_BOOLEAN:
4591#ifdef DEBUG_EXPR
4592 xmlGenericError(xmlGenericErrorContext,
4593 "Equal: %d boolean %d \n",
4594 arg1->boolval, arg2->boolval);
4595#endif
4596 ret = (arg1->boolval == arg2->boolval);
4597 break;
4598 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004599 ret = (arg1->boolval ==
4600 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004601 break;
4602 case XPATH_STRING:
4603 if ((arg2->stringval == NULL) ||
4604 (arg2->stringval[0] == 0)) ret = 0;
4605 else
4606 ret = 1;
4607 ret = (arg1->boolval == ret);
4608 break;
4609 case XPATH_USERS:
4610 case XPATH_POINT:
4611 case XPATH_RANGE:
4612 case XPATH_LOCATIONSET:
4613 TODO
4614 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004615 case XPATH_NODESET:
4616 case XPATH_XSLT_TREE:
4617 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004618 }
4619 break;
4620 case XPATH_NUMBER:
4621 switch (arg2->type) {
4622 case XPATH_UNDEFINED:
4623#ifdef DEBUG_EXPR
4624 xmlGenericError(xmlGenericErrorContext,
4625 "Equal: undefined\n");
4626#endif
4627 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004628 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004629 ret = (arg2->boolval==
4630 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004631 break;
4632 case XPATH_STRING:
4633 valuePush(ctxt, arg2);
4634 xmlXPathNumberFunction(ctxt, 1);
4635 arg2 = valuePop(ctxt);
4636 /* no break on purpose */
4637 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004638 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004639 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4640 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004641 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4642 if (xmlXPathIsInf(arg2->floatval) == 1)
4643 ret = 1;
4644 else
4645 ret = 0;
4646 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4647 if (xmlXPathIsInf(arg2->floatval) == -1)
4648 ret = 1;
4649 else
4650 ret = 0;
4651 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4652 if (xmlXPathIsInf(arg1->floatval) == 1)
4653 ret = 1;
4654 else
4655 ret = 0;
4656 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4657 if (xmlXPathIsInf(arg1->floatval) == -1)
4658 ret = 1;
4659 else
4660 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004661 } else {
4662 ret = (arg1->floatval == arg2->floatval);
4663 }
Owen Taylor3473f882001-02-23 17:55:21 +00004664 break;
4665 case XPATH_USERS:
4666 case XPATH_POINT:
4667 case XPATH_RANGE:
4668 case XPATH_LOCATIONSET:
4669 TODO
4670 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004671 case XPATH_NODESET:
4672 case XPATH_XSLT_TREE:
4673 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004674 }
4675 break;
4676 case XPATH_STRING:
4677 switch (arg2->type) {
4678 case XPATH_UNDEFINED:
4679#ifdef DEBUG_EXPR
4680 xmlGenericError(xmlGenericErrorContext,
4681 "Equal: undefined\n");
4682#endif
4683 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004684 case XPATH_BOOLEAN:
4685 if ((arg1->stringval == NULL) ||
4686 (arg1->stringval[0] == 0)) ret = 0;
4687 else
4688 ret = 1;
4689 ret = (arg2->boolval == ret);
4690 break;
4691 case XPATH_STRING:
4692 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4693 break;
4694 case XPATH_NUMBER:
4695 valuePush(ctxt, arg1);
4696 xmlXPathNumberFunction(ctxt, 1);
4697 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004698 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004699 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4700 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004701 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4702 if (xmlXPathIsInf(arg2->floatval) == 1)
4703 ret = 1;
4704 else
4705 ret = 0;
4706 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4707 if (xmlXPathIsInf(arg2->floatval) == -1)
4708 ret = 1;
4709 else
4710 ret = 0;
4711 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4712 if (xmlXPathIsInf(arg1->floatval) == 1)
4713 ret = 1;
4714 else
4715 ret = 0;
4716 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4717 if (xmlXPathIsInf(arg1->floatval) == -1)
4718 ret = 1;
4719 else
4720 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004721 } else {
4722 ret = (arg1->floatval == arg2->floatval);
4723 }
Owen Taylor3473f882001-02-23 17:55:21 +00004724 break;
4725 case XPATH_USERS:
4726 case XPATH_POINT:
4727 case XPATH_RANGE:
4728 case XPATH_LOCATIONSET:
4729 TODO
4730 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004731 case XPATH_NODESET:
4732 case XPATH_XSLT_TREE:
4733 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004734 }
4735 break;
4736 case XPATH_USERS:
4737 case XPATH_POINT:
4738 case XPATH_RANGE:
4739 case XPATH_LOCATIONSET:
4740 TODO
4741 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004742 case XPATH_NODESET:
4743 case XPATH_XSLT_TREE:
4744 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004745 }
4746 xmlXPathFreeObject(arg1);
4747 xmlXPathFreeObject(arg2);
4748 return(ret);
4749}
4750
William M. Brack0c022ad2002-07-12 00:56:01 +00004751/**
4752 * xmlXPathEqualValues:
4753 * @ctxt: the XPath Parser context
4754 *
4755 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4756 *
4757 * Returns 0 or 1 depending on the results of the test.
4758 */
4759int
4760xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4761 xmlXPathObjectPtr arg1, arg2, argtmp;
4762 int ret = 0;
4763
4764 arg2 = valuePop(ctxt);
4765 arg1 = valuePop(ctxt);
4766 if ((arg1 == NULL) || (arg2 == NULL)) {
4767 if (arg1 != NULL)
4768 xmlXPathFreeObject(arg1);
4769 else
4770 xmlXPathFreeObject(arg2);
4771 XP_ERROR0(XPATH_INVALID_OPERAND);
4772 }
4773
4774 if (arg1 == arg2) {
4775#ifdef DEBUG_EXPR
4776 xmlGenericError(xmlGenericErrorContext,
4777 "Equal: by pointer\n");
4778#endif
4779 return(1);
4780 }
4781
4782 /*
4783 *If either argument is a nodeset, it's a 'special case'
4784 */
4785 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4786 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4787 /*
4788 *Hack it to assure arg1 is the nodeset
4789 */
4790 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4791 argtmp = arg2;
4792 arg2 = arg1;
4793 arg1 = argtmp;
4794 }
4795 switch (arg2->type) {
4796 case XPATH_UNDEFINED:
4797#ifdef DEBUG_EXPR
4798 xmlGenericError(xmlGenericErrorContext,
4799 "Equal: undefined\n");
4800#endif
4801 break;
4802 case XPATH_NODESET:
4803 case XPATH_XSLT_TREE:
4804 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4805 break;
4806 case XPATH_BOOLEAN:
4807 if ((arg1->nodesetval == NULL) ||
4808 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4809 else
4810 ret = 1;
4811 ret = (ret == arg2->boolval);
4812 break;
4813 case XPATH_NUMBER:
4814 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4815 break;
4816 case XPATH_STRING:
4817 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4818 break;
4819 case XPATH_USERS:
4820 case XPATH_POINT:
4821 case XPATH_RANGE:
4822 case XPATH_LOCATIONSET:
4823 TODO
4824 break;
4825 }
4826 xmlXPathFreeObject(arg1);
4827 xmlXPathFreeObject(arg2);
4828 return(ret);
4829 }
4830
4831 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4832}
4833
4834/**
4835 * xmlXPathNotEqualValues:
4836 * @ctxt: the XPath Parser context
4837 *
4838 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4839 *
4840 * Returns 0 or 1 depending on the results of the test.
4841 */
4842int
4843xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4844 xmlXPathObjectPtr arg1, arg2, argtmp;
4845 int ret = 0;
4846
4847 arg2 = valuePop(ctxt);
4848 arg1 = valuePop(ctxt);
4849 if ((arg1 == NULL) || (arg2 == NULL)) {
4850 if (arg1 != NULL)
4851 xmlXPathFreeObject(arg1);
4852 else
4853 xmlXPathFreeObject(arg2);
4854 XP_ERROR0(XPATH_INVALID_OPERAND);
4855 }
4856
4857 if (arg1 == arg2) {
4858#ifdef DEBUG_EXPR
4859 xmlGenericError(xmlGenericErrorContext,
4860 "NotEqual: by pointer\n");
4861#endif
4862 return(0);
4863 }
4864
4865 /*
4866 *If either argument is a nodeset, it's a 'special case'
4867 */
4868 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4869 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4870 /*
4871 *Hack it to assure arg1 is the nodeset
4872 */
4873 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4874 argtmp = arg2;
4875 arg2 = arg1;
4876 arg1 = argtmp;
4877 }
4878 switch (arg2->type) {
4879 case XPATH_UNDEFINED:
4880#ifdef DEBUG_EXPR
4881 xmlGenericError(xmlGenericErrorContext,
4882 "NotEqual: undefined\n");
4883#endif
4884 break;
4885 case XPATH_NODESET:
4886 case XPATH_XSLT_TREE:
4887 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4888 break;
4889 case XPATH_BOOLEAN:
4890 if ((arg1->nodesetval == NULL) ||
4891 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4892 else
4893 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004894 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004895 break;
4896 case XPATH_NUMBER:
4897 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4898 break;
4899 case XPATH_STRING:
4900 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4901 break;
4902 case XPATH_USERS:
4903 case XPATH_POINT:
4904 case XPATH_RANGE:
4905 case XPATH_LOCATIONSET:
4906 TODO
4907 break;
4908 }
4909 xmlXPathFreeObject(arg1);
4910 xmlXPathFreeObject(arg2);
4911 return(ret);
4912 }
4913
4914 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4915}
Owen Taylor3473f882001-02-23 17:55:21 +00004916
4917/**
4918 * xmlXPathCompareValues:
4919 * @ctxt: the XPath Parser context
4920 * @inf: less than (1) or greater than (0)
4921 * @strict: is the comparison strict
4922 *
4923 * Implement the compare operation on XPath objects:
4924 * @arg1 < @arg2 (1, 1, ...
4925 * @arg1 <= @arg2 (1, 0, ...
4926 * @arg1 > @arg2 (0, 1, ...
4927 * @arg1 >= @arg2 (0, 0, ...
4928 *
4929 * When neither object to be compared is a node-set and the operator is
4930 * <=, <, >=, >, then the objects are compared by converted both objects
4931 * to numbers and comparing the numbers according to IEEE 754. The <
4932 * comparison will be true if and only if the first number is less than the
4933 * second number. The <= comparison will be true if and only if the first
4934 * number is less than or equal to the second number. The > comparison
4935 * will be true if and only if the first number is greater than the second
4936 * number. The >= comparison will be true if and only if the first number
4937 * is greater than or equal to the second number.
4938 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004939 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004940 */
4941int
4942xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004943 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004944 xmlXPathObjectPtr arg1, arg2;
4945
William M. Brack0c022ad2002-07-12 00:56:01 +00004946 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004947 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004948 if ((arg1 == NULL) || (arg2 == NULL)) {
4949 if (arg1 != NULL)
4950 xmlXPathFreeObject(arg1);
4951 else
4952 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004953 XP_ERROR0(XPATH_INVALID_OPERAND);
4954 }
4955
William M. Brack0c022ad2002-07-12 00:56:01 +00004956 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4957 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4958 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4959 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004960 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004961 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004962 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004963 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4964 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004965 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004966 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4967 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004968 }
4969 }
4970 return(ret);
4971 }
4972
4973 if (arg1->type != XPATH_NUMBER) {
4974 valuePush(ctxt, arg1);
4975 xmlXPathNumberFunction(ctxt, 1);
4976 arg1 = valuePop(ctxt);
4977 }
4978 if (arg1->type != XPATH_NUMBER) {
4979 xmlXPathFreeObject(arg1);
4980 xmlXPathFreeObject(arg2);
4981 XP_ERROR0(XPATH_INVALID_OPERAND);
4982 }
4983 if (arg2->type != XPATH_NUMBER) {
4984 valuePush(ctxt, arg2);
4985 xmlXPathNumberFunction(ctxt, 1);
4986 arg2 = valuePop(ctxt);
4987 }
4988 if (arg2->type != XPATH_NUMBER) {
4989 xmlXPathFreeObject(arg1);
4990 xmlXPathFreeObject(arg2);
4991 XP_ERROR0(XPATH_INVALID_OPERAND);
4992 }
4993 /*
4994 * Add tests for infinity and nan
4995 * => feedback on 3.4 for Inf and NaN
4996 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004997 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004998 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004999 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005000 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005001 arg1i=xmlXPathIsInf(arg1->floatval);
5002 arg2i=xmlXPathIsInf(arg2->floatval);
5003 if (inf && strict) {
5004 if ((arg1i == -1 && arg2i != -1) ||
5005 (arg2i == 1 && arg1i != 1)) {
5006 ret = 1;
5007 } else if (arg1i == 0 && arg2i == 0) {
5008 ret = (arg1->floatval < arg2->floatval);
5009 } else {
5010 ret = 0;
5011 }
5012 }
5013 else if (inf && !strict) {
5014 if (arg1i == -1 || arg2i == 1) {
5015 ret = 1;
5016 } else if (arg1i == 0 && arg2i == 0) {
5017 ret = (arg1->floatval <= arg2->floatval);
5018 } else {
5019 ret = 0;
5020 }
5021 }
5022 else if (!inf && strict) {
5023 if ((arg1i == 1 && arg2i != 1) ||
5024 (arg2i == -1 && arg1i != -1)) {
5025 ret = 1;
5026 } else if (arg1i == 0 && arg2i == 0) {
5027 ret = (arg1->floatval > arg2->floatval);
5028 } else {
5029 ret = 0;
5030 }
5031 }
5032 else if (!inf && !strict) {
5033 if (arg1i == 1 || arg2i == -1) {
5034 ret = 1;
5035 } else if (arg1i == 0 && arg2i == 0) {
5036 ret = (arg1->floatval >= arg2->floatval);
5037 } else {
5038 ret = 0;
5039 }
5040 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005041 }
Owen Taylor3473f882001-02-23 17:55:21 +00005042 xmlXPathFreeObject(arg1);
5043 xmlXPathFreeObject(arg2);
5044 return(ret);
5045}
5046
5047/**
5048 * xmlXPathValueFlipSign:
5049 * @ctxt: the XPath Parser context
5050 *
5051 * Implement the unary - operation on an XPath object
5052 * The numeric operators convert their operands to numbers as if
5053 * by calling the number function.
5054 */
5055void
5056xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005057 CAST_TO_NUMBER;
5058 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005059 if (xmlXPathIsNaN(ctxt->value->floatval))
5060 ctxt->value->floatval=xmlXPathNAN;
5061 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5062 ctxt->value->floatval=xmlXPathNINF;
5063 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5064 ctxt->value->floatval=xmlXPathPINF;
5065 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005066 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5067 ctxt->value->floatval = xmlXPathNZERO;
5068 else
5069 ctxt->value->floatval = 0;
5070 }
5071 else
5072 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005073}
5074
5075/**
5076 * xmlXPathAddValues:
5077 * @ctxt: the XPath Parser context
5078 *
5079 * Implement the add operation on XPath objects:
5080 * The numeric operators convert their operands to numbers as if
5081 * by calling the number function.
5082 */
5083void
5084xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5085 xmlXPathObjectPtr arg;
5086 double val;
5087
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005088 arg = valuePop(ctxt);
5089 if (arg == NULL)
5090 XP_ERROR(XPATH_INVALID_OPERAND);
5091 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005092 xmlXPathFreeObject(arg);
5093
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005094 CAST_TO_NUMBER;
5095 CHECK_TYPE(XPATH_NUMBER);
5096 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005097}
5098
5099/**
5100 * xmlXPathSubValues:
5101 * @ctxt: the XPath Parser context
5102 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005103 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005104 * The numeric operators convert their operands to numbers as if
5105 * by calling the number function.
5106 */
5107void
5108xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5109 xmlXPathObjectPtr arg;
5110 double val;
5111
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005112 arg = valuePop(ctxt);
5113 if (arg == NULL)
5114 XP_ERROR(XPATH_INVALID_OPERAND);
5115 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005116 xmlXPathFreeObject(arg);
5117
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005118 CAST_TO_NUMBER;
5119 CHECK_TYPE(XPATH_NUMBER);
5120 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005121}
5122
5123/**
5124 * xmlXPathMultValues:
5125 * @ctxt: the XPath Parser context
5126 *
5127 * Implement the multiply operation on XPath objects:
5128 * The numeric operators convert their operands to numbers as if
5129 * by calling the number function.
5130 */
5131void
5132xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5133 xmlXPathObjectPtr arg;
5134 double val;
5135
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005136 arg = valuePop(ctxt);
5137 if (arg == NULL)
5138 XP_ERROR(XPATH_INVALID_OPERAND);
5139 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005140 xmlXPathFreeObject(arg);
5141
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005142 CAST_TO_NUMBER;
5143 CHECK_TYPE(XPATH_NUMBER);
5144 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005145}
5146
5147/**
5148 * xmlXPathDivValues:
5149 * @ctxt: the XPath Parser context
5150 *
5151 * Implement the div operation on XPath objects @arg1 / @arg2:
5152 * The numeric operators convert their operands to numbers as if
5153 * by calling the number function.
5154 */
5155void
5156xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5157 xmlXPathObjectPtr arg;
5158 double val;
5159
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005160 arg = valuePop(ctxt);
5161 if (arg == NULL)
5162 XP_ERROR(XPATH_INVALID_OPERAND);
5163 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005164 xmlXPathFreeObject(arg);
5165
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005166 CAST_TO_NUMBER;
5167 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005168 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5169 ctxt->value->floatval = xmlXPathNAN;
5170 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005171 if (ctxt->value->floatval == 0)
5172 ctxt->value->floatval = xmlXPathNAN;
5173 else if (ctxt->value->floatval > 0)
5174 ctxt->value->floatval = xmlXPathNINF;
5175 else if (ctxt->value->floatval < 0)
5176 ctxt->value->floatval = xmlXPathPINF;
5177 }
5178 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005179 if (ctxt->value->floatval == 0)
5180 ctxt->value->floatval = xmlXPathNAN;
5181 else if (ctxt->value->floatval > 0)
5182 ctxt->value->floatval = xmlXPathPINF;
5183 else if (ctxt->value->floatval < 0)
5184 ctxt->value->floatval = xmlXPathNINF;
5185 } else
5186 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005187}
5188
5189/**
5190 * xmlXPathModValues:
5191 * @ctxt: the XPath Parser context
5192 *
5193 * Implement the mod operation on XPath objects: @arg1 / @arg2
5194 * The numeric operators convert their operands to numbers as if
5195 * by calling the number function.
5196 */
5197void
5198xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5199 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005200 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005201
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005202 arg = valuePop(ctxt);
5203 if (arg == NULL)
5204 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005205 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005206 xmlXPathFreeObject(arg);
5207
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005208 CAST_TO_NUMBER;
5209 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005210 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005211 if (arg2 == 0)
5212 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005213 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005214 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005215 }
Owen Taylor3473f882001-02-23 17:55:21 +00005216}
5217
5218/************************************************************************
5219 * *
5220 * The traversal functions *
5221 * *
5222 ************************************************************************/
5223
Owen Taylor3473f882001-02-23 17:55:21 +00005224/*
5225 * A traversal function enumerates nodes along an axis.
5226 * Initially it must be called with NULL, and it indicates
5227 * termination on the axis by returning NULL.
5228 */
5229typedef xmlNodePtr (*xmlXPathTraversalFunction)
5230 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5231
5232/**
5233 * xmlXPathNextSelf:
5234 * @ctxt: the XPath Parser context
5235 * @cur: the current node in the traversal
5236 *
5237 * Traversal function for the "self" direction
5238 * The self axis contains just the context node itself
5239 *
5240 * Returns the next element following that axis
5241 */
5242xmlNodePtr
5243xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5244 if (cur == NULL)
5245 return(ctxt->context->node);
5246 return(NULL);
5247}
5248
5249/**
5250 * xmlXPathNextChild:
5251 * @ctxt: the XPath Parser context
5252 * @cur: the current node in the traversal
5253 *
5254 * Traversal function for the "child" direction
5255 * The child axis contains the children of the context node in document order.
5256 *
5257 * Returns the next element following that axis
5258 */
5259xmlNodePtr
5260xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5261 if (cur == NULL) {
5262 if (ctxt->context->node == NULL) return(NULL);
5263 switch (ctxt->context->node->type) {
5264 case XML_ELEMENT_NODE:
5265 case XML_TEXT_NODE:
5266 case XML_CDATA_SECTION_NODE:
5267 case XML_ENTITY_REF_NODE:
5268 case XML_ENTITY_NODE:
5269 case XML_PI_NODE:
5270 case XML_COMMENT_NODE:
5271 case XML_NOTATION_NODE:
5272 case XML_DTD_NODE:
5273 return(ctxt->context->node->children);
5274 case XML_DOCUMENT_NODE:
5275 case XML_DOCUMENT_TYPE_NODE:
5276 case XML_DOCUMENT_FRAG_NODE:
5277 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005278#ifdef LIBXML_DOCB_ENABLED
5279 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005280#endif
5281 return(((xmlDocPtr) ctxt->context->node)->children);
5282 case XML_ELEMENT_DECL:
5283 case XML_ATTRIBUTE_DECL:
5284 case XML_ENTITY_DECL:
5285 case XML_ATTRIBUTE_NODE:
5286 case XML_NAMESPACE_DECL:
5287 case XML_XINCLUDE_START:
5288 case XML_XINCLUDE_END:
5289 return(NULL);
5290 }
5291 return(NULL);
5292 }
5293 if ((cur->type == XML_DOCUMENT_NODE) ||
5294 (cur->type == XML_HTML_DOCUMENT_NODE))
5295 return(NULL);
5296 return(cur->next);
5297}
5298
5299/**
5300 * xmlXPathNextDescendant:
5301 * @ctxt: the XPath Parser context
5302 * @cur: the current node in the traversal
5303 *
5304 * Traversal function for the "descendant" direction
5305 * the descendant axis contains the descendants of the context node in document
5306 * order; a descendant is a child or a child of a child and so on.
5307 *
5308 * Returns the next element following that axis
5309 */
5310xmlNodePtr
5311xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5312 if (cur == NULL) {
5313 if (ctxt->context->node == NULL)
5314 return(NULL);
5315 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5316 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5317 return(NULL);
5318
5319 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5320 return(ctxt->context->doc->children);
5321 return(ctxt->context->node->children);
5322 }
5323
Daniel Veillard567e1b42001-08-01 15:53:47 +00005324 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005325 /*
5326 * Do not descend on entities declarations
5327 */
5328 if (cur->children->type != XML_ENTITY_DECL) {
5329 cur = cur->children;
5330 /*
5331 * Skip DTDs
5332 */
5333 if (cur->type != XML_DTD_NODE)
5334 return(cur);
5335 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005336 }
5337
5338 if (cur == ctxt->context->node) return(NULL);
5339
Daniel Veillard68e9e742002-11-16 15:35:11 +00005340 while (cur->next != NULL) {
5341 cur = cur->next;
5342 if ((cur->type != XML_ENTITY_DECL) &&
5343 (cur->type != XML_DTD_NODE))
5344 return(cur);
5345 }
Owen Taylor3473f882001-02-23 17:55:21 +00005346
5347 do {
5348 cur = cur->parent;
5349 if (cur == NULL) return(NULL);
5350 if (cur == ctxt->context->node) return(NULL);
5351 if (cur->next != NULL) {
5352 cur = cur->next;
5353 return(cur);
5354 }
5355 } while (cur != NULL);
5356 return(cur);
5357}
5358
5359/**
5360 * xmlXPathNextDescendantOrSelf:
5361 * @ctxt: the XPath Parser context
5362 * @cur: the current node in the traversal
5363 *
5364 * Traversal function for the "descendant-or-self" direction
5365 * the descendant-or-self axis contains the context node and the descendants
5366 * of the context node in document order; thus the context node is the first
5367 * node on the axis, and the first child of the context node is the second node
5368 * on the axis
5369 *
5370 * Returns the next element following that axis
5371 */
5372xmlNodePtr
5373xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5374 if (cur == NULL) {
5375 if (ctxt->context->node == NULL)
5376 return(NULL);
5377 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5378 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5379 return(NULL);
5380 return(ctxt->context->node);
5381 }
5382
5383 return(xmlXPathNextDescendant(ctxt, cur));
5384}
5385
5386/**
5387 * xmlXPathNextParent:
5388 * @ctxt: the XPath Parser context
5389 * @cur: the current node in the traversal
5390 *
5391 * Traversal function for the "parent" direction
5392 * The parent axis contains the parent of the context node, if there is one.
5393 *
5394 * Returns the next element following that axis
5395 */
5396xmlNodePtr
5397xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5398 /*
5399 * the parent of an attribute or namespace node is the element
5400 * to which the attribute or namespace node is attached
5401 * Namespace handling !!!
5402 */
5403 if (cur == NULL) {
5404 if (ctxt->context->node == NULL) return(NULL);
5405 switch (ctxt->context->node->type) {
5406 case XML_ELEMENT_NODE:
5407 case XML_TEXT_NODE:
5408 case XML_CDATA_SECTION_NODE:
5409 case XML_ENTITY_REF_NODE:
5410 case XML_ENTITY_NODE:
5411 case XML_PI_NODE:
5412 case XML_COMMENT_NODE:
5413 case XML_NOTATION_NODE:
5414 case XML_DTD_NODE:
5415 case XML_ELEMENT_DECL:
5416 case XML_ATTRIBUTE_DECL:
5417 case XML_XINCLUDE_START:
5418 case XML_XINCLUDE_END:
5419 case XML_ENTITY_DECL:
5420 if (ctxt->context->node->parent == NULL)
5421 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005422 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005423 ((ctxt->context->node->parent->name[0] == ' ') ||
5424 (xmlStrEqual(ctxt->context->node->parent->name,
5425 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005426 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005427 return(ctxt->context->node->parent);
5428 case XML_ATTRIBUTE_NODE: {
5429 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5430
5431 return(att->parent);
5432 }
5433 case XML_DOCUMENT_NODE:
5434 case XML_DOCUMENT_TYPE_NODE:
5435 case XML_DOCUMENT_FRAG_NODE:
5436 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005437#ifdef LIBXML_DOCB_ENABLED
5438 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005439#endif
5440 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005441 case XML_NAMESPACE_DECL: {
5442 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5443
5444 if ((ns->next != NULL) &&
5445 (ns->next->type != XML_NAMESPACE_DECL))
5446 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005447 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005448 }
Owen Taylor3473f882001-02-23 17:55:21 +00005449 }
5450 }
5451 return(NULL);
5452}
5453
5454/**
5455 * xmlXPathNextAncestor:
5456 * @ctxt: the XPath Parser context
5457 * @cur: the current node in the traversal
5458 *
5459 * Traversal function for the "ancestor" direction
5460 * the ancestor axis contains the ancestors of the context node; the ancestors
5461 * of the context node consist of the parent of context node and the parent's
5462 * parent and so on; the nodes are ordered in reverse document order; thus the
5463 * parent is the first node on the axis, and the parent's parent is the second
5464 * node on the axis
5465 *
5466 * Returns the next element following that axis
5467 */
5468xmlNodePtr
5469xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5470 /*
5471 * the parent of an attribute or namespace node is the element
5472 * to which the attribute or namespace node is attached
5473 * !!!!!!!!!!!!!
5474 */
5475 if (cur == NULL) {
5476 if (ctxt->context->node == NULL) return(NULL);
5477 switch (ctxt->context->node->type) {
5478 case XML_ELEMENT_NODE:
5479 case XML_TEXT_NODE:
5480 case XML_CDATA_SECTION_NODE:
5481 case XML_ENTITY_REF_NODE:
5482 case XML_ENTITY_NODE:
5483 case XML_PI_NODE:
5484 case XML_COMMENT_NODE:
5485 case XML_DTD_NODE:
5486 case XML_ELEMENT_DECL:
5487 case XML_ATTRIBUTE_DECL:
5488 case XML_ENTITY_DECL:
5489 case XML_NOTATION_NODE:
5490 case XML_XINCLUDE_START:
5491 case XML_XINCLUDE_END:
5492 if (ctxt->context->node->parent == NULL)
5493 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005494 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005495 ((ctxt->context->node->parent->name[0] == ' ') ||
5496 (xmlStrEqual(ctxt->context->node->parent->name,
5497 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005498 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005499 return(ctxt->context->node->parent);
5500 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005501 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005502
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005503 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005504 }
5505 case XML_DOCUMENT_NODE:
5506 case XML_DOCUMENT_TYPE_NODE:
5507 case XML_DOCUMENT_FRAG_NODE:
5508 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005509#ifdef LIBXML_DOCB_ENABLED
5510 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005511#endif
5512 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005513 case XML_NAMESPACE_DECL: {
5514 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5515
5516 if ((ns->next != NULL) &&
5517 (ns->next->type != XML_NAMESPACE_DECL))
5518 return((xmlNodePtr) ns->next);
5519 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005520 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005521 }
Owen Taylor3473f882001-02-23 17:55:21 +00005522 }
5523 return(NULL);
5524 }
5525 if (cur == ctxt->context->doc->children)
5526 return((xmlNodePtr) ctxt->context->doc);
5527 if (cur == (xmlNodePtr) ctxt->context->doc)
5528 return(NULL);
5529 switch (cur->type) {
5530 case XML_ELEMENT_NODE:
5531 case XML_TEXT_NODE:
5532 case XML_CDATA_SECTION_NODE:
5533 case XML_ENTITY_REF_NODE:
5534 case XML_ENTITY_NODE:
5535 case XML_PI_NODE:
5536 case XML_COMMENT_NODE:
5537 case XML_NOTATION_NODE:
5538 case XML_DTD_NODE:
5539 case XML_ELEMENT_DECL:
5540 case XML_ATTRIBUTE_DECL:
5541 case XML_ENTITY_DECL:
5542 case XML_XINCLUDE_START:
5543 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005544 if (cur->parent == NULL)
5545 return(NULL);
5546 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005547 ((cur->parent->name[0] == ' ') ||
5548 (xmlStrEqual(cur->parent->name,
5549 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005550 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005551 return(cur->parent);
5552 case XML_ATTRIBUTE_NODE: {
5553 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5554
5555 return(att->parent);
5556 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005557 case XML_NAMESPACE_DECL: {
5558 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5559
5560 if ((ns->next != NULL) &&
5561 (ns->next->type != XML_NAMESPACE_DECL))
5562 return((xmlNodePtr) ns->next);
5563 /* Bad, how did that namespace ended-up there ? */
5564 return(NULL);
5565 }
Owen Taylor3473f882001-02-23 17:55:21 +00005566 case XML_DOCUMENT_NODE:
5567 case XML_DOCUMENT_TYPE_NODE:
5568 case XML_DOCUMENT_FRAG_NODE:
5569 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005570#ifdef LIBXML_DOCB_ENABLED
5571 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005572#endif
5573 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005574 }
5575 return(NULL);
5576}
5577
5578/**
5579 * xmlXPathNextAncestorOrSelf:
5580 * @ctxt: the XPath Parser context
5581 * @cur: the current node in the traversal
5582 *
5583 * Traversal function for the "ancestor-or-self" direction
5584 * he ancestor-or-self axis contains the context node and ancestors of
5585 * the context node in reverse document order; thus the context node is
5586 * the first node on the axis, and the context node's parent the second;
5587 * parent here is defined the same as with the parent axis.
5588 *
5589 * Returns the next element following that axis
5590 */
5591xmlNodePtr
5592xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5593 if (cur == NULL)
5594 return(ctxt->context->node);
5595 return(xmlXPathNextAncestor(ctxt, cur));
5596}
5597
5598/**
5599 * xmlXPathNextFollowingSibling:
5600 * @ctxt: the XPath Parser context
5601 * @cur: the current node in the traversal
5602 *
5603 * Traversal function for the "following-sibling" direction
5604 * The following-sibling axis contains the following siblings of the context
5605 * node in document order.
5606 *
5607 * Returns the next element following that axis
5608 */
5609xmlNodePtr
5610xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5611 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5612 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5613 return(NULL);
5614 if (cur == (xmlNodePtr) ctxt->context->doc)
5615 return(NULL);
5616 if (cur == NULL)
5617 return(ctxt->context->node->next);
5618 return(cur->next);
5619}
5620
5621/**
5622 * xmlXPathNextPrecedingSibling:
5623 * @ctxt: the XPath Parser context
5624 * @cur: the current node in the traversal
5625 *
5626 * Traversal function for the "preceding-sibling" direction
5627 * The preceding-sibling axis contains the preceding siblings of the context
5628 * node in reverse document order; the first preceding sibling is first on the
5629 * axis; the sibling preceding that node is the second on the axis and so on.
5630 *
5631 * Returns the next element following that axis
5632 */
5633xmlNodePtr
5634xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5635 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5636 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5637 return(NULL);
5638 if (cur == (xmlNodePtr) ctxt->context->doc)
5639 return(NULL);
5640 if (cur == NULL)
5641 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005642 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5643 cur = cur->prev;
5644 if (cur == NULL)
5645 return(ctxt->context->node->prev);
5646 }
Owen Taylor3473f882001-02-23 17:55:21 +00005647 return(cur->prev);
5648}
5649
5650/**
5651 * xmlXPathNextFollowing:
5652 * @ctxt: the XPath Parser context
5653 * @cur: the current node in the traversal
5654 *
5655 * Traversal function for the "following" direction
5656 * The following axis contains all nodes in the same document as the context
5657 * node that are after the context node in document order, excluding any
5658 * descendants and excluding attribute nodes and namespace nodes; the nodes
5659 * are ordered in document order
5660 *
5661 * Returns the next element following that axis
5662 */
5663xmlNodePtr
5664xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5665 if (cur != NULL && cur->children != NULL)
5666 return cur->children ;
5667 if (cur == NULL) cur = ctxt->context->node;
5668 if (cur == NULL) return(NULL) ; /* ERROR */
5669 if (cur->next != NULL) return(cur->next) ;
5670 do {
5671 cur = cur->parent;
5672 if (cur == NULL) return(NULL);
5673 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5674 if (cur->next != NULL) return(cur->next);
5675 } while (cur != NULL);
5676 return(cur);
5677}
5678
5679/*
5680 * xmlXPathIsAncestor:
5681 * @ancestor: the ancestor node
5682 * @node: the current node
5683 *
5684 * Check that @ancestor is a @node's ancestor
5685 *
5686 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5687 */
5688static int
5689xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5690 if ((ancestor == NULL) || (node == NULL)) return(0);
5691 /* nodes need to be in the same document */
5692 if (ancestor->doc != node->doc) return(0);
5693 /* avoid searching if ancestor or node is the root node */
5694 if (ancestor == (xmlNodePtr) node->doc) return(1);
5695 if (node == (xmlNodePtr) ancestor->doc) return(0);
5696 while (node->parent != NULL) {
5697 if (node->parent == ancestor)
5698 return(1);
5699 node = node->parent;
5700 }
5701 return(0);
5702}
5703
5704/**
5705 * xmlXPathNextPreceding:
5706 * @ctxt: the XPath Parser context
5707 * @cur: the current node in the traversal
5708 *
5709 * Traversal function for the "preceding" direction
5710 * the preceding axis contains all nodes in the same document as the context
5711 * node that are before the context node in document order, excluding any
5712 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5713 * ordered in reverse document order
5714 *
5715 * Returns the next element following that axis
5716 */
5717xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005718xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5719{
Owen Taylor3473f882001-02-23 17:55:21 +00005720 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005721 cur = ctxt->context->node;
5722 if (cur == NULL)
5723 return (NULL);
5724 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5725 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005726 do {
5727 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005728 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5729 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005730 }
5731
5732 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005733 if (cur == NULL)
5734 return (NULL);
5735 if (cur == ctxt->context->doc->children)
5736 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005737 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005738 return (cur);
5739}
5740
5741/**
5742 * xmlXPathNextPrecedingInternal:
5743 * @ctxt: the XPath Parser context
5744 * @cur: the current node in the traversal
5745 *
5746 * Traversal function for the "preceding" direction
5747 * the preceding axis contains all nodes in the same document as the context
5748 * node that are before the context node in document order, excluding any
5749 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5750 * ordered in reverse document order
5751 * This is a faster implementation but internal only since it requires a
5752 * state kept in the parser context: ctxt->ancestor.
5753 *
5754 * Returns the next element following that axis
5755 */
5756static xmlNodePtr
5757xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5758 xmlNodePtr cur)
5759{
5760 if (cur == NULL) {
5761 cur = ctxt->context->node;
5762 if (cur == NULL)
5763 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005764 if (cur->type == XML_NAMESPACE_DECL)
5765 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005766 ctxt->ancestor = cur->parent;
5767 }
5768 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5769 cur = cur->prev;
5770 while (cur->prev == NULL) {
5771 cur = cur->parent;
5772 if (cur == NULL)
5773 return (NULL);
5774 if (cur == ctxt->context->doc->children)
5775 return (NULL);
5776 if (cur != ctxt->ancestor)
5777 return (cur);
5778 ctxt->ancestor = cur->parent;
5779 }
5780 cur = cur->prev;
5781 while (cur->last != NULL)
5782 cur = cur->last;
5783 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005784}
5785
5786/**
5787 * xmlXPathNextNamespace:
5788 * @ctxt: the XPath Parser context
5789 * @cur: the current attribute in the traversal
5790 *
5791 * Traversal function for the "namespace" direction
5792 * the namespace axis contains the namespace nodes of the context node;
5793 * the order of nodes on this axis is implementation-defined; the axis will
5794 * be empty unless the context node is an element
5795 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005796 * We keep the XML namespace node at the end of the list.
5797 *
Owen Taylor3473f882001-02-23 17:55:21 +00005798 * Returns the next element following that axis
5799 */
5800xmlNodePtr
5801xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5802 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005803 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005804 if (ctxt->context->tmpNsList != NULL)
5805 xmlFree(ctxt->context->tmpNsList);
5806 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005807 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005808 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005809 if (ctxt->context->tmpNsList != NULL) {
5810 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5811 ctxt->context->tmpNsNr++;
5812 }
5813 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005814 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005815 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005816 if (ctxt->context->tmpNsNr > 0) {
5817 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5818 } else {
5819 if (ctxt->context->tmpNsList != NULL)
5820 xmlFree(ctxt->context->tmpNsList);
5821 ctxt->context->tmpNsList = NULL;
5822 return(NULL);
5823 }
Owen Taylor3473f882001-02-23 17:55:21 +00005824}
5825
5826/**
5827 * xmlXPathNextAttribute:
5828 * @ctxt: the XPath Parser context
5829 * @cur: the current attribute in the traversal
5830 *
5831 * Traversal function for the "attribute" direction
5832 * TODO: support DTD inherited default attributes
5833 *
5834 * Returns the next element following that axis
5835 */
5836xmlNodePtr
5837xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005838 if (ctxt->context->node == NULL)
5839 return(NULL);
5840 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5841 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005842 if (cur == NULL) {
5843 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5844 return(NULL);
5845 return((xmlNodePtr)ctxt->context->node->properties);
5846 }
5847 return((xmlNodePtr)cur->next);
5848}
5849
5850/************************************************************************
5851 * *
5852 * NodeTest Functions *
5853 * *
5854 ************************************************************************/
5855
Owen Taylor3473f882001-02-23 17:55:21 +00005856#define IS_FUNCTION 200
5857
Owen Taylor3473f882001-02-23 17:55:21 +00005858
5859/************************************************************************
5860 * *
5861 * Implicit tree core function library *
5862 * *
5863 ************************************************************************/
5864
5865/**
5866 * xmlXPathRoot:
5867 * @ctxt: the XPath Parser context
5868 *
5869 * Initialize the context to the root of the document
5870 */
5871void
5872xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5873 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5874 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5875}
5876
5877/************************************************************************
5878 * *
5879 * The explicit core function library *
5880 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5881 * *
5882 ************************************************************************/
5883
5884
5885/**
5886 * xmlXPathLastFunction:
5887 * @ctxt: the XPath Parser context
5888 * @nargs: the number of arguments
5889 *
5890 * Implement the last() XPath function
5891 * number last()
5892 * The last function returns the number of nodes in the context node list.
5893 */
5894void
5895xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5896 CHECK_ARITY(0);
5897 if (ctxt->context->contextSize >= 0) {
5898 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5899#ifdef DEBUG_EXPR
5900 xmlGenericError(xmlGenericErrorContext,
5901 "last() : %d\n", ctxt->context->contextSize);
5902#endif
5903 } else {
5904 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5905 }
5906}
5907
5908/**
5909 * xmlXPathPositionFunction:
5910 * @ctxt: the XPath Parser context
5911 * @nargs: the number of arguments
5912 *
5913 * Implement the position() XPath function
5914 * number position()
5915 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005916 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005917 * will be equal to last().
5918 */
5919void
5920xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5921 CHECK_ARITY(0);
5922 if (ctxt->context->proximityPosition >= 0) {
5923 valuePush(ctxt,
5924 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5925#ifdef DEBUG_EXPR
5926 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5927 ctxt->context->proximityPosition);
5928#endif
5929 } else {
5930 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5931 }
5932}
5933
5934/**
5935 * xmlXPathCountFunction:
5936 * @ctxt: the XPath Parser context
5937 * @nargs: the number of arguments
5938 *
5939 * Implement the count() XPath function
5940 * number count(node-set)
5941 */
5942void
5943xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5944 xmlXPathObjectPtr cur;
5945
5946 CHECK_ARITY(1);
5947 if ((ctxt->value == NULL) ||
5948 ((ctxt->value->type != XPATH_NODESET) &&
5949 (ctxt->value->type != XPATH_XSLT_TREE)))
5950 XP_ERROR(XPATH_INVALID_TYPE);
5951 cur = valuePop(ctxt);
5952
Daniel Veillard911f49a2001-04-07 15:39:35 +00005953 if ((cur == NULL) || (cur->nodesetval == NULL))
5954 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005955 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005956 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005957 } else {
5958 if ((cur->nodesetval->nodeNr != 1) ||
5959 (cur->nodesetval->nodeTab == NULL)) {
5960 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5961 } else {
5962 xmlNodePtr tmp;
5963 int i = 0;
5964
5965 tmp = cur->nodesetval->nodeTab[0];
5966 if (tmp != NULL) {
5967 tmp = tmp->children;
5968 while (tmp != NULL) {
5969 tmp = tmp->next;
5970 i++;
5971 }
5972 }
5973 valuePush(ctxt, xmlXPathNewFloat((double) i));
5974 }
5975 }
Owen Taylor3473f882001-02-23 17:55:21 +00005976 xmlXPathFreeObject(cur);
5977}
5978
5979/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005980 * xmlXPathGetElementsByIds:
5981 * @doc: the document
5982 * @ids: a whitespace separated list of IDs
5983 *
5984 * Selects elements by their unique ID.
5985 *
5986 * Returns a node-set of selected elements.
5987 */
5988static xmlNodeSetPtr
5989xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5990 xmlNodeSetPtr ret;
5991 const xmlChar *cur = ids;
5992 xmlChar *ID;
5993 xmlAttrPtr attr;
5994 xmlNodePtr elem = NULL;
5995
Daniel Veillard7a985a12003-07-06 17:57:42 +00005996 if (ids == NULL) return(NULL);
5997
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005998 ret = xmlXPathNodeSetCreate(NULL);
5999
William M. Brack76e95df2003-10-18 16:20:14 +00006000 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006001 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006002 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006003 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006004
6005 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006006 if (ID != NULL) {
6007 if (xmlValidateNCName(ID, 1) == 0) {
6008 attr = xmlGetID(doc, ID);
6009 if (attr != NULL) {
6010 if (attr->type == XML_ATTRIBUTE_NODE)
6011 elem = attr->parent;
6012 else if (attr->type == XML_ELEMENT_NODE)
6013 elem = (xmlNodePtr) attr;
6014 else
6015 elem = NULL;
6016 if (elem != NULL)
6017 xmlXPathNodeSetAdd(ret, elem);
6018 }
6019 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006020 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006021 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006022
William M. Brack76e95df2003-10-18 16:20:14 +00006023 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006024 ids = cur;
6025 }
6026 return(ret);
6027}
6028
6029/**
Owen Taylor3473f882001-02-23 17:55:21 +00006030 * xmlXPathIdFunction:
6031 * @ctxt: the XPath Parser context
6032 * @nargs: the number of arguments
6033 *
6034 * Implement the id() XPath function
6035 * node-set id(object)
6036 * The id function selects elements by their unique ID
6037 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6038 * then the result is the union of the result of applying id to the
6039 * string value of each of the nodes in the argument node-set. When the
6040 * argument to id is of any other type, the argument is converted to a
6041 * string as if by a call to the string function; the string is split
6042 * into a whitespace-separated list of tokens (whitespace is any sequence
6043 * of characters matching the production S); the result is a node-set
6044 * containing the elements in the same document as the context node that
6045 * have a unique ID equal to any of the tokens in the list.
6046 */
6047void
6048xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006049 xmlChar *tokens;
6050 xmlNodeSetPtr ret;
6051 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006052
6053 CHECK_ARITY(1);
6054 obj = valuePop(ctxt);
6055 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006056 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006057 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006058 int i;
6059
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006060 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006061
Daniel Veillard911f49a2001-04-07 15:39:35 +00006062 if (obj->nodesetval != NULL) {
6063 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006064 tokens =
6065 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6066 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6067 ret = xmlXPathNodeSetMerge(ret, ns);
6068 xmlXPathFreeNodeSet(ns);
6069 if (tokens != NULL)
6070 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006071 }
Owen Taylor3473f882001-02-23 17:55:21 +00006072 }
6073
6074 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006075 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006076 return;
6077 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006078 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006079
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006080 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6081 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006082
Owen Taylor3473f882001-02-23 17:55:21 +00006083 xmlXPathFreeObject(obj);
6084 return;
6085}
6086
6087/**
6088 * xmlXPathLocalNameFunction:
6089 * @ctxt: the XPath Parser context
6090 * @nargs: the number of arguments
6091 *
6092 * Implement the local-name() XPath function
6093 * string local-name(node-set?)
6094 * The local-name function returns a string containing the local part
6095 * of the name of the node in the argument node-set that is first in
6096 * document order. If the node-set is empty or the first node has no
6097 * name, an empty string is returned. If the argument is omitted it
6098 * defaults to the context node.
6099 */
6100void
6101xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6102 xmlXPathObjectPtr cur;
6103
6104 if (nargs == 0) {
6105 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6106 nargs = 1;
6107 }
6108
6109 CHECK_ARITY(1);
6110 if ((ctxt->value == NULL) ||
6111 ((ctxt->value->type != XPATH_NODESET) &&
6112 (ctxt->value->type != XPATH_XSLT_TREE)))
6113 XP_ERROR(XPATH_INVALID_TYPE);
6114 cur = valuePop(ctxt);
6115
Daniel Veillard911f49a2001-04-07 15:39:35 +00006116 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006117 valuePush(ctxt, xmlXPathNewCString(""));
6118 } else {
6119 int i = 0; /* Should be first in document order !!!!! */
6120 switch (cur->nodesetval->nodeTab[i]->type) {
6121 case XML_ELEMENT_NODE:
6122 case XML_ATTRIBUTE_NODE:
6123 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006124 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6125 valuePush(ctxt, xmlXPathNewCString(""));
6126 else
6127 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006128 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6129 break;
6130 case XML_NAMESPACE_DECL:
6131 valuePush(ctxt, xmlXPathNewString(
6132 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6133 break;
6134 default:
6135 valuePush(ctxt, xmlXPathNewCString(""));
6136 }
6137 }
6138 xmlXPathFreeObject(cur);
6139}
6140
6141/**
6142 * xmlXPathNamespaceURIFunction:
6143 * @ctxt: the XPath Parser context
6144 * @nargs: the number of arguments
6145 *
6146 * Implement the namespace-uri() XPath function
6147 * string namespace-uri(node-set?)
6148 * The namespace-uri function returns a string containing the
6149 * namespace URI of the expanded name of the node in the argument
6150 * node-set that is first in document order. If the node-set is empty,
6151 * the first node has no name, or the expanded name has no namespace
6152 * URI, an empty string is returned. If the argument is omitted it
6153 * defaults to the context node.
6154 */
6155void
6156xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6157 xmlXPathObjectPtr cur;
6158
6159 if (nargs == 0) {
6160 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6161 nargs = 1;
6162 }
6163 CHECK_ARITY(1);
6164 if ((ctxt->value == NULL) ||
6165 ((ctxt->value->type != XPATH_NODESET) &&
6166 (ctxt->value->type != XPATH_XSLT_TREE)))
6167 XP_ERROR(XPATH_INVALID_TYPE);
6168 cur = valuePop(ctxt);
6169
Daniel Veillard911f49a2001-04-07 15:39:35 +00006170 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006171 valuePush(ctxt, xmlXPathNewCString(""));
6172 } else {
6173 int i = 0; /* Should be first in document order !!!!! */
6174 switch (cur->nodesetval->nodeTab[i]->type) {
6175 case XML_ELEMENT_NODE:
6176 case XML_ATTRIBUTE_NODE:
6177 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6178 valuePush(ctxt, xmlXPathNewCString(""));
6179 else
6180 valuePush(ctxt, xmlXPathNewString(
6181 cur->nodesetval->nodeTab[i]->ns->href));
6182 break;
6183 default:
6184 valuePush(ctxt, xmlXPathNewCString(""));
6185 }
6186 }
6187 xmlXPathFreeObject(cur);
6188}
6189
6190/**
6191 * xmlXPathNameFunction:
6192 * @ctxt: the XPath Parser context
6193 * @nargs: the number of arguments
6194 *
6195 * Implement the name() XPath function
6196 * string name(node-set?)
6197 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006198 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006199 * order. The QName must represent the name with respect to the namespace
6200 * declarations in effect on the node whose name is being represented.
6201 * Typically, this will be the form in which the name occurred in the XML
6202 * source. This need not be the case if there are namespace declarations
6203 * in effect on the node that associate multiple prefixes with the same
6204 * namespace. However, an implementation may include information about
6205 * the original prefix in its representation of nodes; in this case, an
6206 * implementation can ensure that the returned string is always the same
6207 * as the QName used in the XML source. If the argument it omitted it
6208 * defaults to the context node.
6209 * Libxml keep the original prefix so the "real qualified name" used is
6210 * returned.
6211 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006212static void
Daniel Veillard04383752001-07-08 14:27:15 +00006213xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6214{
Owen Taylor3473f882001-02-23 17:55:21 +00006215 xmlXPathObjectPtr cur;
6216
6217 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006218 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6219 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006220 }
6221
6222 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006223 if ((ctxt->value == NULL) ||
6224 ((ctxt->value->type != XPATH_NODESET) &&
6225 (ctxt->value->type != XPATH_XSLT_TREE)))
6226 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006227 cur = valuePop(ctxt);
6228
Daniel Veillard911f49a2001-04-07 15:39:35 +00006229 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006230 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006231 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006232 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006233
Daniel Veillard04383752001-07-08 14:27:15 +00006234 switch (cur->nodesetval->nodeTab[i]->type) {
6235 case XML_ELEMENT_NODE:
6236 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006237 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6238 valuePush(ctxt, xmlXPathNewCString(""));
6239 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6240 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006241 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006242 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006243
Daniel Veillard652d8a92003-02-04 19:28:49 +00006244 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006245 xmlChar *fullname;
6246
6247 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6248 cur->nodesetval->nodeTab[i]->ns->prefix,
6249 NULL, 0);
6250 if (fullname == cur->nodesetval->nodeTab[i]->name)
6251 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6252 if (fullname == NULL) {
6253 XP_ERROR(XPATH_MEMORY_ERROR);
6254 }
6255 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006256 }
6257 break;
6258 default:
6259 valuePush(ctxt,
6260 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6261 xmlXPathLocalNameFunction(ctxt, 1);
6262 }
Owen Taylor3473f882001-02-23 17:55:21 +00006263 }
6264 xmlXPathFreeObject(cur);
6265}
6266
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006267
6268/**
Owen Taylor3473f882001-02-23 17:55:21 +00006269 * xmlXPathStringFunction:
6270 * @ctxt: the XPath Parser context
6271 * @nargs: the number of arguments
6272 *
6273 * Implement the string() XPath function
6274 * string string(object?)
6275 * he string function converts an object to a string as follows:
6276 * - A node-set is converted to a string by returning the value of
6277 * the node in the node-set that is first in document order.
6278 * If the node-set is empty, an empty string is returned.
6279 * - A number is converted to a string as follows
6280 * + NaN is converted to the string NaN
6281 * + positive zero is converted to the string 0
6282 * + negative zero is converted to the string 0
6283 * + positive infinity is converted to the string Infinity
6284 * + negative infinity is converted to the string -Infinity
6285 * + if the number is an integer, the number is represented in
6286 * decimal form as a Number with no decimal point and no leading
6287 * zeros, preceded by a minus sign (-) if the number is negative
6288 * + otherwise, the number is represented in decimal form as a
6289 * Number including a decimal point with at least one digit
6290 * before the decimal point and at least one digit after the
6291 * decimal point, preceded by a minus sign (-) if the number
6292 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006293 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006294 * before the decimal point; beyond the one required digit
6295 * after the decimal point there must be as many, but only as
6296 * many, more digits as are needed to uniquely distinguish the
6297 * number from all other IEEE 754 numeric values.
6298 * - The boolean false value is converted to the string false.
6299 * The boolean true value is converted to the string true.
6300 *
6301 * If the argument is omitted, it defaults to a node-set with the
6302 * context node as its only member.
6303 */
6304void
6305xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6306 xmlXPathObjectPtr cur;
6307
6308 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006309 valuePush(ctxt,
6310 xmlXPathWrapString(
6311 xmlXPathCastNodeToString(ctxt->context->node)));
6312 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006313 }
6314
6315 CHECK_ARITY(1);
6316 cur = valuePop(ctxt);
6317 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006318 cur = xmlXPathConvertString(cur);
6319 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006320}
6321
6322/**
6323 * xmlXPathStringLengthFunction:
6324 * @ctxt: the XPath Parser context
6325 * @nargs: the number of arguments
6326 *
6327 * Implement the string-length() XPath function
6328 * number string-length(string?)
6329 * The string-length returns the number of characters in the string
6330 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6331 * the context node converted to a string, in other words the value
6332 * of the context node.
6333 */
6334void
6335xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6336 xmlXPathObjectPtr cur;
6337
6338 if (nargs == 0) {
6339 if (ctxt->context->node == NULL) {
6340 valuePush(ctxt, xmlXPathNewFloat(0));
6341 } else {
6342 xmlChar *content;
6343
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006344 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006345 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006346 xmlFree(content);
6347 }
6348 return;
6349 }
6350 CHECK_ARITY(1);
6351 CAST_TO_STRING;
6352 CHECK_TYPE(XPATH_STRING);
6353 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006354 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006355 xmlXPathFreeObject(cur);
6356}
6357
6358/**
6359 * xmlXPathConcatFunction:
6360 * @ctxt: the XPath Parser context
6361 * @nargs: the number of arguments
6362 *
6363 * Implement the concat() XPath function
6364 * string concat(string, string, string*)
6365 * The concat function returns the concatenation of its arguments.
6366 */
6367void
6368xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6369 xmlXPathObjectPtr cur, newobj;
6370 xmlChar *tmp;
6371
6372 if (nargs < 2) {
6373 CHECK_ARITY(2);
6374 }
6375
6376 CAST_TO_STRING;
6377 cur = valuePop(ctxt);
6378 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6379 xmlXPathFreeObject(cur);
6380 return;
6381 }
6382 nargs--;
6383
6384 while (nargs > 0) {
6385 CAST_TO_STRING;
6386 newobj = valuePop(ctxt);
6387 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6388 xmlXPathFreeObject(newobj);
6389 xmlXPathFreeObject(cur);
6390 XP_ERROR(XPATH_INVALID_TYPE);
6391 }
6392 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6393 newobj->stringval = cur->stringval;
6394 cur->stringval = tmp;
6395
6396 xmlXPathFreeObject(newobj);
6397 nargs--;
6398 }
6399 valuePush(ctxt, cur);
6400}
6401
6402/**
6403 * xmlXPathContainsFunction:
6404 * @ctxt: the XPath Parser context
6405 * @nargs: the number of arguments
6406 *
6407 * Implement the contains() XPath function
6408 * boolean contains(string, string)
6409 * The contains function returns true if the first argument string
6410 * contains the second argument string, and otherwise returns false.
6411 */
6412void
6413xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6414 xmlXPathObjectPtr hay, needle;
6415
6416 CHECK_ARITY(2);
6417 CAST_TO_STRING;
6418 CHECK_TYPE(XPATH_STRING);
6419 needle = valuePop(ctxt);
6420 CAST_TO_STRING;
6421 hay = valuePop(ctxt);
6422 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6423 xmlXPathFreeObject(hay);
6424 xmlXPathFreeObject(needle);
6425 XP_ERROR(XPATH_INVALID_TYPE);
6426 }
6427 if (xmlStrstr(hay->stringval, needle->stringval))
6428 valuePush(ctxt, xmlXPathNewBoolean(1));
6429 else
6430 valuePush(ctxt, xmlXPathNewBoolean(0));
6431 xmlXPathFreeObject(hay);
6432 xmlXPathFreeObject(needle);
6433}
6434
6435/**
6436 * xmlXPathStartsWithFunction:
6437 * @ctxt: the XPath Parser context
6438 * @nargs: the number of arguments
6439 *
6440 * Implement the starts-with() XPath function
6441 * boolean starts-with(string, string)
6442 * The starts-with function returns true if the first argument string
6443 * starts with the second argument string, and otherwise returns false.
6444 */
6445void
6446xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6447 xmlXPathObjectPtr hay, needle;
6448 int n;
6449
6450 CHECK_ARITY(2);
6451 CAST_TO_STRING;
6452 CHECK_TYPE(XPATH_STRING);
6453 needle = valuePop(ctxt);
6454 CAST_TO_STRING;
6455 hay = valuePop(ctxt);
6456 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6457 xmlXPathFreeObject(hay);
6458 xmlXPathFreeObject(needle);
6459 XP_ERROR(XPATH_INVALID_TYPE);
6460 }
6461 n = xmlStrlen(needle->stringval);
6462 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6463 valuePush(ctxt, xmlXPathNewBoolean(0));
6464 else
6465 valuePush(ctxt, xmlXPathNewBoolean(1));
6466 xmlXPathFreeObject(hay);
6467 xmlXPathFreeObject(needle);
6468}
6469
6470/**
6471 * xmlXPathSubstringFunction:
6472 * @ctxt: the XPath Parser context
6473 * @nargs: the number of arguments
6474 *
6475 * Implement the substring() XPath function
6476 * string substring(string, number, number?)
6477 * The substring function returns the substring of the first argument
6478 * starting at the position specified in the second argument with
6479 * length specified in the third argument. For example,
6480 * substring("12345",2,3) returns "234". If the third argument is not
6481 * specified, it returns the substring starting at the position specified
6482 * in the second argument and continuing to the end of the string. For
6483 * example, substring("12345",2) returns "2345". More precisely, each
6484 * character in the string (see [3.6 Strings]) is considered to have a
6485 * numeric position: the position of the first character is 1, the position
6486 * of the second character is 2 and so on. The returned substring contains
6487 * those characters for which the position of the character is greater than
6488 * or equal to the second argument and, if the third argument is specified,
6489 * less than the sum of the second and third arguments; the comparisons
6490 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6491 * - substring("12345", 1.5, 2.6) returns "234"
6492 * - substring("12345", 0, 3) returns "12"
6493 * - substring("12345", 0 div 0, 3) returns ""
6494 * - substring("12345", 1, 0 div 0) returns ""
6495 * - substring("12345", -42, 1 div 0) returns "12345"
6496 * - substring("12345", -1 div 0, 1 div 0) returns ""
6497 */
6498void
6499xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6500 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006501 double le=0, in;
6502 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006503 xmlChar *ret;
6504
Owen Taylor3473f882001-02-23 17:55:21 +00006505 if (nargs < 2) {
6506 CHECK_ARITY(2);
6507 }
6508 if (nargs > 3) {
6509 CHECK_ARITY(3);
6510 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006511 /*
6512 * take care of possible last (position) argument
6513 */
Owen Taylor3473f882001-02-23 17:55:21 +00006514 if (nargs == 3) {
6515 CAST_TO_NUMBER;
6516 CHECK_TYPE(XPATH_NUMBER);
6517 len = valuePop(ctxt);
6518 le = len->floatval;
6519 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006520 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006521
Owen Taylor3473f882001-02-23 17:55:21 +00006522 CAST_TO_NUMBER;
6523 CHECK_TYPE(XPATH_NUMBER);
6524 start = valuePop(ctxt);
6525 in = start->floatval;
6526 xmlXPathFreeObject(start);
6527 CAST_TO_STRING;
6528 CHECK_TYPE(XPATH_STRING);
6529 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006530 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006531
Daniel Veillard97ac1312001-05-30 19:14:17 +00006532 /*
6533 * If last pos not present, calculate last position
6534 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006535 if (nargs != 3) {
6536 le = (double)m;
6537 if (in < 1.0)
6538 in = 1.0;
6539 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006540
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006541 /* Need to check for the special cases where either
6542 * the index is NaN, the length is NaN, or both
6543 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006544 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006545 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006546 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006547 * To meet the requirements of the spec, the arguments
6548 * must be converted to integer format before
6549 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006550 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006551 * First we go to integer form, rounding up
6552 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006553 */
6554 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006555 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006556
Daniel Veillard9e412302002-06-10 15:59:44 +00006557 if (xmlXPathIsInf(le) == 1) {
6558 l = m;
6559 if (i < 1)
6560 i = 1;
6561 }
6562 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6563 l = 0;
6564 else {
6565 l = (int) le;
6566 if (((double)l)+0.5 <= le) l++;
6567 }
6568
6569 /* Now we normalize inidices */
6570 i -= 1;
6571 l += i;
6572 if (i < 0)
6573 i = 0;
6574 if (l > m)
6575 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006576
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006577 /* number of chars to copy */
6578 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006579
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006580 ret = xmlUTF8Strsub(str->stringval, i, l);
6581 }
6582 else {
6583 ret = NULL;
6584 }
6585
Owen Taylor3473f882001-02-23 17:55:21 +00006586 if (ret == NULL)
6587 valuePush(ctxt, xmlXPathNewCString(""));
6588 else {
6589 valuePush(ctxt, xmlXPathNewString(ret));
6590 xmlFree(ret);
6591 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006592
Owen Taylor3473f882001-02-23 17:55:21 +00006593 xmlXPathFreeObject(str);
6594}
6595
6596/**
6597 * xmlXPathSubstringBeforeFunction:
6598 * @ctxt: the XPath Parser context
6599 * @nargs: the number of arguments
6600 *
6601 * Implement the substring-before() XPath function
6602 * string substring-before(string, string)
6603 * The substring-before function returns the substring of the first
6604 * argument string that precedes the first occurrence of the second
6605 * argument string in the first argument string, or the empty string
6606 * if the first argument string does not contain the second argument
6607 * string. For example, substring-before("1999/04/01","/") returns 1999.
6608 */
6609void
6610xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6611 xmlXPathObjectPtr str;
6612 xmlXPathObjectPtr find;
6613 xmlBufferPtr target;
6614 const xmlChar *point;
6615 int offset;
6616
6617 CHECK_ARITY(2);
6618 CAST_TO_STRING;
6619 find = valuePop(ctxt);
6620 CAST_TO_STRING;
6621 str = valuePop(ctxt);
6622
6623 target = xmlBufferCreate();
6624 if (target) {
6625 point = xmlStrstr(str->stringval, find->stringval);
6626 if (point) {
6627 offset = (int)(point - str->stringval);
6628 xmlBufferAdd(target, str->stringval, offset);
6629 }
6630 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6631 xmlBufferFree(target);
6632 }
6633
6634 xmlXPathFreeObject(str);
6635 xmlXPathFreeObject(find);
6636}
6637
6638/**
6639 * xmlXPathSubstringAfterFunction:
6640 * @ctxt: the XPath Parser context
6641 * @nargs: the number of arguments
6642 *
6643 * Implement the substring-after() XPath function
6644 * string substring-after(string, string)
6645 * The substring-after function returns the substring of the first
6646 * argument string that follows the first occurrence of the second
6647 * argument string in the first argument string, or the empty stringi
6648 * if the first argument string does not contain the second argument
6649 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6650 * and substring-after("1999/04/01","19") returns 99/04/01.
6651 */
6652void
6653xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6654 xmlXPathObjectPtr str;
6655 xmlXPathObjectPtr find;
6656 xmlBufferPtr target;
6657 const xmlChar *point;
6658 int offset;
6659
6660 CHECK_ARITY(2);
6661 CAST_TO_STRING;
6662 find = valuePop(ctxt);
6663 CAST_TO_STRING;
6664 str = valuePop(ctxt);
6665
6666 target = xmlBufferCreate();
6667 if (target) {
6668 point = xmlStrstr(str->stringval, find->stringval);
6669 if (point) {
6670 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6671 xmlBufferAdd(target, &str->stringval[offset],
6672 xmlStrlen(str->stringval) - offset);
6673 }
6674 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6675 xmlBufferFree(target);
6676 }
6677
6678 xmlXPathFreeObject(str);
6679 xmlXPathFreeObject(find);
6680}
6681
6682/**
6683 * xmlXPathNormalizeFunction:
6684 * @ctxt: the XPath Parser context
6685 * @nargs: the number of arguments
6686 *
6687 * Implement the normalize-space() XPath function
6688 * string normalize-space(string?)
6689 * The normalize-space function returns the argument string with white
6690 * space normalized by stripping leading and trailing whitespace
6691 * and replacing sequences of whitespace characters by a single
6692 * space. Whitespace characters are the same allowed by the S production
6693 * in XML. If the argument is omitted, it defaults to the context
6694 * node converted to a string, in other words the value of the context node.
6695 */
6696void
6697xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6698 xmlXPathObjectPtr obj = NULL;
6699 xmlChar *source = NULL;
6700 xmlBufferPtr target;
6701 xmlChar blank;
6702
6703 if (nargs == 0) {
6704 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006705 valuePush(ctxt,
6706 xmlXPathWrapString(
6707 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006708 nargs = 1;
6709 }
6710
6711 CHECK_ARITY(1);
6712 CAST_TO_STRING;
6713 CHECK_TYPE(XPATH_STRING);
6714 obj = valuePop(ctxt);
6715 source = obj->stringval;
6716
6717 target = xmlBufferCreate();
6718 if (target && source) {
6719
6720 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006721 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006722 source++;
6723
6724 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6725 blank = 0;
6726 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006727 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006728 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006729 } else {
6730 if (blank) {
6731 xmlBufferAdd(target, &blank, 1);
6732 blank = 0;
6733 }
6734 xmlBufferAdd(target, source, 1);
6735 }
6736 source++;
6737 }
6738
6739 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6740 xmlBufferFree(target);
6741 }
6742 xmlXPathFreeObject(obj);
6743}
6744
6745/**
6746 * xmlXPathTranslateFunction:
6747 * @ctxt: the XPath Parser context
6748 * @nargs: the number of arguments
6749 *
6750 * Implement the translate() XPath function
6751 * string translate(string, string, string)
6752 * The translate function returns the first argument string with
6753 * occurrences of characters in the second argument string replaced
6754 * by the character at the corresponding position in the third argument
6755 * string. For example, translate("bar","abc","ABC") returns the string
6756 * BAr. If there is a character in the second argument string with no
6757 * character at a corresponding position in the third argument string
6758 * (because the second argument string is longer than the third argument
6759 * string), then occurrences of that character in the first argument
6760 * string are removed. For example, translate("--aaa--","abc-","ABC")
6761 * returns "AAA". If a character occurs more than once in second
6762 * argument string, then the first occurrence determines the replacement
6763 * character. If the third argument string is longer than the second
6764 * argument string, then excess characters are ignored.
6765 */
6766void
6767xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006768 xmlXPathObjectPtr str;
6769 xmlXPathObjectPtr from;
6770 xmlXPathObjectPtr to;
6771 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006772 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006773 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006774 xmlChar *point;
6775 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006776
Daniel Veillarde043ee12001-04-16 14:08:07 +00006777 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006778
Daniel Veillarde043ee12001-04-16 14:08:07 +00006779 CAST_TO_STRING;
6780 to = valuePop(ctxt);
6781 CAST_TO_STRING;
6782 from = valuePop(ctxt);
6783 CAST_TO_STRING;
6784 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006785
Daniel Veillarde043ee12001-04-16 14:08:07 +00006786 target = xmlBufferCreate();
6787 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006788 max = xmlUTF8Strlen(to->stringval);
6789 for (cptr = str->stringval; (ch=*cptr); ) {
6790 offset = xmlUTF8Strloc(from->stringval, cptr);
6791 if (offset >= 0) {
6792 if (offset < max) {
6793 point = xmlUTF8Strpos(to->stringval, offset);
6794 if (point)
6795 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6796 }
6797 } else
6798 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6799
6800 /* Step to next character in input */
6801 cptr++;
6802 if ( ch & 0x80 ) {
6803 /* if not simple ascii, verify proper format */
6804 if ( (ch & 0xc0) != 0xc0 ) {
6805 xmlGenericError(xmlGenericErrorContext,
6806 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6807 break;
6808 }
6809 /* then skip over remaining bytes for this char */
6810 while ( (ch <<= 1) & 0x80 )
6811 if ( (*cptr++ & 0xc0) != 0x80 ) {
6812 xmlGenericError(xmlGenericErrorContext,
6813 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6814 break;
6815 }
6816 if (ch & 0x80) /* must have had error encountered */
6817 break;
6818 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006819 }
Owen Taylor3473f882001-02-23 17:55:21 +00006820 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006821 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6822 xmlBufferFree(target);
6823 xmlXPathFreeObject(str);
6824 xmlXPathFreeObject(from);
6825 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006826}
6827
6828/**
6829 * xmlXPathBooleanFunction:
6830 * @ctxt: the XPath Parser context
6831 * @nargs: the number of arguments
6832 *
6833 * Implement the boolean() XPath function
6834 * boolean boolean(object)
6835 * he boolean function converts its argument to a boolean as follows:
6836 * - a number is true if and only if it is neither positive or
6837 * negative zero nor NaN
6838 * - a node-set is true if and only if it is non-empty
6839 * - a string is true if and only if its length is non-zero
6840 */
6841void
6842xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6843 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006844
6845 CHECK_ARITY(1);
6846 cur = valuePop(ctxt);
6847 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006848 cur = xmlXPathConvertBoolean(cur);
6849 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006850}
6851
6852/**
6853 * xmlXPathNotFunction:
6854 * @ctxt: the XPath Parser context
6855 * @nargs: the number of arguments
6856 *
6857 * Implement the not() XPath function
6858 * boolean not(boolean)
6859 * The not function returns true if its argument is false,
6860 * and false otherwise.
6861 */
6862void
6863xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6864 CHECK_ARITY(1);
6865 CAST_TO_BOOLEAN;
6866 CHECK_TYPE(XPATH_BOOLEAN);
6867 ctxt->value->boolval = ! ctxt->value->boolval;
6868}
6869
6870/**
6871 * xmlXPathTrueFunction:
6872 * @ctxt: the XPath Parser context
6873 * @nargs: the number of arguments
6874 *
6875 * Implement the true() XPath function
6876 * boolean true()
6877 */
6878void
6879xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6880 CHECK_ARITY(0);
6881 valuePush(ctxt, xmlXPathNewBoolean(1));
6882}
6883
6884/**
6885 * xmlXPathFalseFunction:
6886 * @ctxt: the XPath Parser context
6887 * @nargs: the number of arguments
6888 *
6889 * Implement the false() XPath function
6890 * boolean false()
6891 */
6892void
6893xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6894 CHECK_ARITY(0);
6895 valuePush(ctxt, xmlXPathNewBoolean(0));
6896}
6897
6898/**
6899 * xmlXPathLangFunction:
6900 * @ctxt: the XPath Parser context
6901 * @nargs: the number of arguments
6902 *
6903 * Implement the lang() XPath function
6904 * boolean lang(string)
6905 * The lang function returns true or false depending on whether the
6906 * language of the context node as specified by xml:lang attributes
6907 * is the same as or is a sublanguage of the language specified by
6908 * the argument string. The language of the context node is determined
6909 * by the value of the xml:lang attribute on the context node, or, if
6910 * the context node has no xml:lang attribute, by the value of the
6911 * xml:lang attribute on the nearest ancestor of the context node that
6912 * has an xml:lang attribute. If there is no such attribute, then lang
6913 * returns false. If there is such an attribute, then lang returns
6914 * true if the attribute value is equal to the argument ignoring case,
6915 * or if there is some suffix starting with - such that the attribute
6916 * value is equal to the argument ignoring that suffix of the attribute
6917 * value and ignoring case.
6918 */
6919void
6920xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6921 xmlXPathObjectPtr val;
6922 const xmlChar *theLang;
6923 const xmlChar *lang;
6924 int ret = 0;
6925 int i;
6926
6927 CHECK_ARITY(1);
6928 CAST_TO_STRING;
6929 CHECK_TYPE(XPATH_STRING);
6930 val = valuePop(ctxt);
6931 lang = val->stringval;
6932 theLang = xmlNodeGetLang(ctxt->context->node);
6933 if ((theLang != NULL) && (lang != NULL)) {
6934 for (i = 0;lang[i] != 0;i++)
6935 if (toupper(lang[i]) != toupper(theLang[i]))
6936 goto not_equal;
6937 ret = 1;
6938 }
6939not_equal:
6940 xmlXPathFreeObject(val);
6941 valuePush(ctxt, xmlXPathNewBoolean(ret));
6942}
6943
6944/**
6945 * xmlXPathNumberFunction:
6946 * @ctxt: the XPath Parser context
6947 * @nargs: the number of arguments
6948 *
6949 * Implement the number() XPath function
6950 * number number(object?)
6951 */
6952void
6953xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6954 xmlXPathObjectPtr cur;
6955 double res;
6956
6957 if (nargs == 0) {
6958 if (ctxt->context->node == NULL) {
6959 valuePush(ctxt, xmlXPathNewFloat(0.0));
6960 } else {
6961 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6962
6963 res = xmlXPathStringEvalNumber(content);
6964 valuePush(ctxt, xmlXPathNewFloat(res));
6965 xmlFree(content);
6966 }
6967 return;
6968 }
6969
6970 CHECK_ARITY(1);
6971 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006972 cur = xmlXPathConvertNumber(cur);
6973 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006974}
6975
6976/**
6977 * xmlXPathSumFunction:
6978 * @ctxt: the XPath Parser context
6979 * @nargs: the number of arguments
6980 *
6981 * Implement the sum() XPath function
6982 * number sum(node-set)
6983 * The sum function returns the sum of the values of the nodes in
6984 * the argument node-set.
6985 */
6986void
6987xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6988 xmlXPathObjectPtr cur;
6989 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006990 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006991
6992 CHECK_ARITY(1);
6993 if ((ctxt->value == NULL) ||
6994 ((ctxt->value->type != XPATH_NODESET) &&
6995 (ctxt->value->type != XPATH_XSLT_TREE)))
6996 XP_ERROR(XPATH_INVALID_TYPE);
6997 cur = valuePop(ctxt);
6998
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006999 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007000 valuePush(ctxt, xmlXPathNewFloat(0.0));
7001 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007002 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7003 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007004 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007005 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007006 }
7007 xmlXPathFreeObject(cur);
7008}
7009
7010/**
7011 * xmlXPathFloorFunction:
7012 * @ctxt: the XPath Parser context
7013 * @nargs: the number of arguments
7014 *
7015 * Implement the floor() XPath function
7016 * number floor(number)
7017 * The floor function returns the largest (closest to positive infinity)
7018 * number that is not greater than the argument and that is an integer.
7019 */
7020void
7021xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007022 double f;
7023
Owen Taylor3473f882001-02-23 17:55:21 +00007024 CHECK_ARITY(1);
7025 CAST_TO_NUMBER;
7026 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007027
7028 f = (double)((int) ctxt->value->floatval);
7029 if (f != ctxt->value->floatval) {
7030 if (ctxt->value->floatval > 0)
7031 ctxt->value->floatval = f;
7032 else
7033 ctxt->value->floatval = f - 1;
7034 }
Owen Taylor3473f882001-02-23 17:55:21 +00007035}
7036
7037/**
7038 * xmlXPathCeilingFunction:
7039 * @ctxt: the XPath Parser context
7040 * @nargs: the number of arguments
7041 *
7042 * Implement the ceiling() XPath function
7043 * number ceiling(number)
7044 * The ceiling function returns the smallest (closest to negative infinity)
7045 * number that is not less than the argument and that is an integer.
7046 */
7047void
7048xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7049 double f;
7050
7051 CHECK_ARITY(1);
7052 CAST_TO_NUMBER;
7053 CHECK_TYPE(XPATH_NUMBER);
7054
7055#if 0
7056 ctxt->value->floatval = ceil(ctxt->value->floatval);
7057#else
7058 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007059 if (f != ctxt->value->floatval) {
7060 if (ctxt->value->floatval > 0)
7061 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007062 else {
7063 if (ctxt->value->floatval < 0 && f == 0)
7064 ctxt->value->floatval = xmlXPathNZERO;
7065 else
7066 ctxt->value->floatval = f;
7067 }
7068
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007069 }
Owen Taylor3473f882001-02-23 17:55:21 +00007070#endif
7071}
7072
7073/**
7074 * xmlXPathRoundFunction:
7075 * @ctxt: the XPath Parser context
7076 * @nargs: the number of arguments
7077 *
7078 * Implement the round() XPath function
7079 * number round(number)
7080 * The round function returns the number that is closest to the
7081 * argument and that is an integer. If there are two such numbers,
7082 * then the one that is even is returned.
7083 */
7084void
7085xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7086 double f;
7087
7088 CHECK_ARITY(1);
7089 CAST_TO_NUMBER;
7090 CHECK_TYPE(XPATH_NUMBER);
7091
Daniel Veillardcda96922001-08-21 10:56:31 +00007092 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7093 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7094 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007095 (ctxt->value->floatval == 0.0))
7096 return;
7097
Owen Taylor3473f882001-02-23 17:55:21 +00007098 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007099 if (ctxt->value->floatval < 0) {
7100 if (ctxt->value->floatval < f - 0.5)
7101 ctxt->value->floatval = f - 1;
7102 else
7103 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007104 if (ctxt->value->floatval == 0)
7105 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007106 } else {
7107 if (ctxt->value->floatval < f + 0.5)
7108 ctxt->value->floatval = f;
7109 else
7110 ctxt->value->floatval = f + 1;
7111 }
Owen Taylor3473f882001-02-23 17:55:21 +00007112}
7113
7114/************************************************************************
7115 * *
7116 * The Parser *
7117 * *
7118 ************************************************************************/
7119
7120/*
7121 * a couple of forward declarations since we use a recursive call based
7122 * implementation.
7123 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007124static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007125static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007126static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007127static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007128static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7129 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007130
7131/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007132 * xmlXPathCurrentChar:
7133 * @ctxt: the XPath parser context
7134 * @cur: pointer to the beginning of the char
7135 * @len: pointer to the length of the char read
7136 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007137 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007138 * bytes in the input buffer.
7139 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007140 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007141 */
7142
7143static int
7144xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7145 unsigned char c;
7146 unsigned int val;
7147 const xmlChar *cur;
7148
7149 if (ctxt == NULL)
7150 return(0);
7151 cur = ctxt->cur;
7152
7153 /*
7154 * We are supposed to handle UTF8, check it's valid
7155 * From rfc2044: encoding of the Unicode values on UTF-8:
7156 *
7157 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7158 * 0000 0000-0000 007F 0xxxxxxx
7159 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7160 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7161 *
7162 * Check for the 0x110000 limit too
7163 */
7164 c = *cur;
7165 if (c & 0x80) {
7166 if ((cur[1] & 0xc0) != 0x80)
7167 goto encoding_error;
7168 if ((c & 0xe0) == 0xe0) {
7169
7170 if ((cur[2] & 0xc0) != 0x80)
7171 goto encoding_error;
7172 if ((c & 0xf0) == 0xf0) {
7173 if (((c & 0xf8) != 0xf0) ||
7174 ((cur[3] & 0xc0) != 0x80))
7175 goto encoding_error;
7176 /* 4-byte code */
7177 *len = 4;
7178 val = (cur[0] & 0x7) << 18;
7179 val |= (cur[1] & 0x3f) << 12;
7180 val |= (cur[2] & 0x3f) << 6;
7181 val |= cur[3] & 0x3f;
7182 } else {
7183 /* 3-byte code */
7184 *len = 3;
7185 val = (cur[0] & 0xf) << 12;
7186 val |= (cur[1] & 0x3f) << 6;
7187 val |= cur[2] & 0x3f;
7188 }
7189 } else {
7190 /* 2-byte code */
7191 *len = 2;
7192 val = (cur[0] & 0x1f) << 6;
7193 val |= cur[1] & 0x3f;
7194 }
7195 if (!IS_CHAR(val)) {
7196 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7197 }
7198 return(val);
7199 } else {
7200 /* 1-byte code */
7201 *len = 1;
7202 return((int) *cur);
7203 }
7204encoding_error:
7205 /*
7206 * If we detect an UTF8 error that probably mean that the
7207 * input encoding didn't get properly advertized in the
7208 * declaration header. Report the error and switch the encoding
7209 * to ISO-Latin-1 (if you don't like this policy, just declare the
7210 * encoding !)
7211 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007212 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007213 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007214}
7215
7216/**
Owen Taylor3473f882001-02-23 17:55:21 +00007217 * xmlXPathParseNCName:
7218 * @ctxt: the XPath Parser context
7219 *
7220 * parse an XML namespace non qualified name.
7221 *
7222 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7223 *
7224 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7225 * CombiningChar | Extender
7226 *
7227 * Returns the namespace name or NULL
7228 */
7229
7230xmlChar *
7231xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007232 const xmlChar *in;
7233 xmlChar *ret;
7234 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007235
Daniel Veillard2156a562001-04-28 12:24:34 +00007236 /*
7237 * Accelerator for simple ASCII names
7238 */
7239 in = ctxt->cur;
7240 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7241 ((*in >= 0x41) && (*in <= 0x5A)) ||
7242 (*in == '_')) {
7243 in++;
7244 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7245 ((*in >= 0x41) && (*in <= 0x5A)) ||
7246 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007247 (*in == '_') || (*in == '.') ||
7248 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007249 in++;
7250 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7251 (*in == '[') || (*in == ']') || (*in == ':') ||
7252 (*in == '@') || (*in == '*')) {
7253 count = in - ctxt->cur;
7254 if (count == 0)
7255 return(NULL);
7256 ret = xmlStrndup(ctxt->cur, count);
7257 ctxt->cur = in;
7258 return(ret);
7259 }
7260 }
7261 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007262}
7263
Daniel Veillard2156a562001-04-28 12:24:34 +00007264
Owen Taylor3473f882001-02-23 17:55:21 +00007265/**
7266 * xmlXPathParseQName:
7267 * @ctxt: the XPath Parser context
7268 * @prefix: a xmlChar **
7269 *
7270 * parse an XML qualified name
7271 *
7272 * [NS 5] QName ::= (Prefix ':')? LocalPart
7273 *
7274 * [NS 6] Prefix ::= NCName
7275 *
7276 * [NS 7] LocalPart ::= NCName
7277 *
7278 * Returns the function returns the local part, and prefix is updated
7279 * to get the Prefix if any.
7280 */
7281
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007282static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007283xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7284 xmlChar *ret = NULL;
7285
7286 *prefix = NULL;
7287 ret = xmlXPathParseNCName(ctxt);
7288 if (CUR == ':') {
7289 *prefix = ret;
7290 NEXT;
7291 ret = xmlXPathParseNCName(ctxt);
7292 }
7293 return(ret);
7294}
7295
7296/**
7297 * xmlXPathParseName:
7298 * @ctxt: the XPath Parser context
7299 *
7300 * parse an XML name
7301 *
7302 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7303 * CombiningChar | Extender
7304 *
7305 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7306 *
7307 * Returns the namespace name or NULL
7308 */
7309
7310xmlChar *
7311xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007312 const xmlChar *in;
7313 xmlChar *ret;
7314 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007315
Daniel Veillard61d80a22001-04-27 17:13:01 +00007316 /*
7317 * Accelerator for simple ASCII names
7318 */
7319 in = ctxt->cur;
7320 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7321 ((*in >= 0x41) && (*in <= 0x5A)) ||
7322 (*in == '_') || (*in == ':')) {
7323 in++;
7324 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7325 ((*in >= 0x41) && (*in <= 0x5A)) ||
7326 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007327 (*in == '_') || (*in == '-') ||
7328 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007329 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007330 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007331 count = in - ctxt->cur;
7332 ret = xmlStrndup(ctxt->cur, count);
7333 ctxt->cur = in;
7334 return(ret);
7335 }
7336 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007337 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007338}
7339
Daniel Veillard61d80a22001-04-27 17:13:01 +00007340static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007341xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007342 xmlChar buf[XML_MAX_NAMELEN + 5];
7343 int len = 0, l;
7344 int c;
7345
7346 /*
7347 * Handler for more complex cases
7348 */
7349 c = CUR_CHAR(l);
7350 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007351 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7352 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007353 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007354 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007355 return(NULL);
7356 }
7357
7358 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7359 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7360 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007361 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007362 (IS_COMBINING(c)) ||
7363 (IS_EXTENDER(c)))) {
7364 COPY_BUF(l,buf,len,c);
7365 NEXTL(l);
7366 c = CUR_CHAR(l);
7367 if (len >= XML_MAX_NAMELEN) {
7368 /*
7369 * Okay someone managed to make a huge name, so he's ready to pay
7370 * for the processing speed.
7371 */
7372 xmlChar *buffer;
7373 int max = len * 2;
7374
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007375 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007376 if (buffer == NULL) {
7377 XP_ERROR0(XPATH_MEMORY_ERROR);
7378 }
7379 memcpy(buffer, buf, len);
7380 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7381 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007382 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007383 (IS_COMBINING(c)) ||
7384 (IS_EXTENDER(c))) {
7385 if (len + 10 > max) {
7386 max *= 2;
7387 buffer = (xmlChar *) xmlRealloc(buffer,
7388 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007389 if (buffer == NULL) {
7390 XP_ERROR0(XPATH_MEMORY_ERROR);
7391 }
7392 }
7393 COPY_BUF(l,buffer,len,c);
7394 NEXTL(l);
7395 c = CUR_CHAR(l);
7396 }
7397 buffer[len] = 0;
7398 return(buffer);
7399 }
7400 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007401 if (len == 0)
7402 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007403 return(xmlStrndup(buf, len));
7404}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007405
7406#define MAX_FRAC 20
7407
7408static double my_pow10[MAX_FRAC] = {
7409 1.0, 10.0, 100.0, 1000.0, 10000.0,
7410 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7411 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7412 100000000000000.0,
7413 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7414 1000000000000000000.0, 10000000000000000000.0
7415};
7416
Owen Taylor3473f882001-02-23 17:55:21 +00007417/**
7418 * xmlXPathStringEvalNumber:
7419 * @str: A string to scan
7420 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007421 * [30a] Float ::= Number ('e' Digits?)?
7422 *
Owen Taylor3473f882001-02-23 17:55:21 +00007423 * [30] Number ::= Digits ('.' Digits?)?
7424 * | '.' Digits
7425 * [31] Digits ::= [0-9]+
7426 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007427 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007428 * In complement of the Number expression, this function also handles
7429 * negative values : '-' Number.
7430 *
7431 * Returns the double value.
7432 */
7433double
7434xmlXPathStringEvalNumber(const xmlChar *str) {
7435 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007436 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007437 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007438 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007439 int exponent = 0;
7440 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007441#ifdef __GNUC__
7442 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007443 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007444#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007445 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007446 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007447 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7448 return(xmlXPathNAN);
7449 }
7450 if (*cur == '-') {
7451 isneg = 1;
7452 cur++;
7453 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007454
7455#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007456 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007457 * tmp/temp is a workaround against a gcc compiler bug
7458 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007459 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007460 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007461 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007462 ret = ret * 10;
7463 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007464 ok = 1;
7465 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007466 temp = (double) tmp;
7467 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007468 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007469#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007470 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007471 while ((*cur >= '0') && (*cur <= '9')) {
7472 ret = ret * 10 + (*cur - '0');
7473 ok = 1;
7474 cur++;
7475 }
7476#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007477
Owen Taylor3473f882001-02-23 17:55:21 +00007478 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007479 int v, frac = 0;
7480 double fraction = 0;
7481
Owen Taylor3473f882001-02-23 17:55:21 +00007482 cur++;
7483 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7484 return(xmlXPathNAN);
7485 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007486 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7487 v = (*cur - '0');
7488 fraction = fraction * 10 + v;
7489 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007490 cur++;
7491 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007492 fraction /= my_pow10[frac];
7493 ret = ret + fraction;
7494 while ((*cur >= '0') && (*cur <= '9'))
7495 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007496 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007497 if ((*cur == 'e') || (*cur == 'E')) {
7498 cur++;
7499 if (*cur == '-') {
7500 is_exponent_negative = 1;
7501 cur++;
7502 }
7503 while ((*cur >= '0') && (*cur <= '9')) {
7504 exponent = exponent * 10 + (*cur - '0');
7505 cur++;
7506 }
7507 }
William M. Brack76e95df2003-10-18 16:20:14 +00007508 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007509 if (*cur != 0) return(xmlXPathNAN);
7510 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007511 if (is_exponent_negative) exponent = -exponent;
7512 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007513 return(ret);
7514}
7515
7516/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007517 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007518 * @ctxt: the XPath Parser context
7519 *
7520 * [30] Number ::= Digits ('.' Digits?)?
7521 * | '.' Digits
7522 * [31] Digits ::= [0-9]+
7523 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007524 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007525 *
7526 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007527static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007528xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7529{
Owen Taylor3473f882001-02-23 17:55:21 +00007530 double ret = 0.0;
7531 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007532 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007533 int exponent = 0;
7534 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007535#ifdef __GNUC__
7536 unsigned long tmp = 0;
7537 double temp;
7538#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007539
7540 CHECK_ERROR;
7541 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7542 XP_ERROR(XPATH_NUMBER_ERROR);
7543 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007544#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007545 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007546 * tmp/temp is a workaround against a gcc compiler bug
7547 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007548 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007549 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007550 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007551 ret = ret * 10;
7552 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007553 ok = 1;
7554 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007555 temp = (double) tmp;
7556 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007557 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007558#else
7559 ret = 0;
7560 while ((CUR >= '0') && (CUR <= '9')) {
7561 ret = ret * 10 + (CUR - '0');
7562 ok = 1;
7563 NEXT;
7564 }
7565#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007566 if (CUR == '.') {
7567 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007568 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7569 XP_ERROR(XPATH_NUMBER_ERROR);
7570 }
7571 while ((CUR >= '0') && (CUR <= '9')) {
7572 mult /= 10;
7573 ret = ret + (CUR - '0') * mult;
7574 NEXT;
7575 }
Owen Taylor3473f882001-02-23 17:55:21 +00007576 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007577 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007578 NEXT;
7579 if (CUR == '-') {
7580 is_exponent_negative = 1;
7581 NEXT;
7582 }
7583 while ((CUR >= '0') && (CUR <= '9')) {
7584 exponent = exponent * 10 + (CUR - '0');
7585 NEXT;
7586 }
7587 if (is_exponent_negative)
7588 exponent = -exponent;
7589 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007590 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007591 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007592 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007593}
7594
7595/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007596 * xmlXPathParseLiteral:
7597 * @ctxt: the XPath Parser context
7598 *
7599 * Parse a Literal
7600 *
7601 * [29] Literal ::= '"' [^"]* '"'
7602 * | "'" [^']* "'"
7603 *
7604 * Returns the value found or NULL in case of error
7605 */
7606static xmlChar *
7607xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7608 const xmlChar *q;
7609 xmlChar *ret = NULL;
7610
7611 if (CUR == '"') {
7612 NEXT;
7613 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007614 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007615 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007616 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007617 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7618 } else {
7619 ret = xmlStrndup(q, CUR_PTR - q);
7620 NEXT;
7621 }
7622 } else if (CUR == '\'') {
7623 NEXT;
7624 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007625 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007626 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007627 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007628 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7629 } else {
7630 ret = xmlStrndup(q, CUR_PTR - q);
7631 NEXT;
7632 }
7633 } else {
7634 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7635 }
7636 return(ret);
7637}
7638
7639/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007640 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007641 * @ctxt: the XPath Parser context
7642 *
7643 * Parse a Literal and push it on the stack.
7644 *
7645 * [29] Literal ::= '"' [^"]* '"'
7646 * | "'" [^']* "'"
7647 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007648 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007649 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007650static void
7651xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007652 const xmlChar *q;
7653 xmlChar *ret = NULL;
7654
7655 if (CUR == '"') {
7656 NEXT;
7657 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007658 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007659 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007660 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007661 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7662 } else {
7663 ret = xmlStrndup(q, CUR_PTR - q);
7664 NEXT;
7665 }
7666 } else if (CUR == '\'') {
7667 NEXT;
7668 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007669 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007670 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007671 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007672 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7673 } else {
7674 ret = xmlStrndup(q, CUR_PTR - q);
7675 NEXT;
7676 }
7677 } else {
7678 XP_ERROR(XPATH_START_LITERAL_ERROR);
7679 }
7680 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007681 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7682 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007683 xmlFree(ret);
7684}
7685
7686/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007687 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007688 * @ctxt: the XPath Parser context
7689 *
7690 * Parse a VariableReference, evaluate it and push it on the stack.
7691 *
7692 * The variable bindings consist of a mapping from variable names
7693 * to variable values. The value of a variable is an object, which
7694 * of any of the types that are possible for the value of an expression,
7695 * and may also be of additional types not specified here.
7696 *
7697 * Early evaluation is possible since:
7698 * The variable bindings [...] used to evaluate a subexpression are
7699 * always the same as those used to evaluate the containing expression.
7700 *
7701 * [36] VariableReference ::= '$' QName
7702 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007703static void
7704xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007705 xmlChar *name;
7706 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007707
7708 SKIP_BLANKS;
7709 if (CUR != '$') {
7710 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7711 }
7712 NEXT;
7713 name = xmlXPathParseQName(ctxt, &prefix);
7714 if (name == NULL) {
7715 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7716 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007717 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007718 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7719 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007720 SKIP_BLANKS;
7721}
7722
7723/**
7724 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007725 * @name: a name string
7726 *
7727 * Is the name given a NodeType one.
7728 *
7729 * [38] NodeType ::= 'comment'
7730 * | 'text'
7731 * | 'processing-instruction'
7732 * | 'node'
7733 *
7734 * Returns 1 if true 0 otherwise
7735 */
7736int
7737xmlXPathIsNodeType(const xmlChar *name) {
7738 if (name == NULL)
7739 return(0);
7740
Daniel Veillard1971ee22002-01-31 20:29:19 +00007741 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007742 return(1);
7743 if (xmlStrEqual(name, BAD_CAST "text"))
7744 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007745 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007746 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007747 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007748 return(1);
7749 return(0);
7750}
7751
7752/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007753 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007754 * @ctxt: the XPath Parser context
7755 *
7756 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7757 * [17] Argument ::= Expr
7758 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007759 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007760 * pushed on the stack
7761 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007762static void
7763xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007764 xmlChar *name;
7765 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007766 int nbargs = 0;
7767
7768 name = xmlXPathParseQName(ctxt, &prefix);
7769 if (name == NULL) {
7770 XP_ERROR(XPATH_EXPR_ERROR);
7771 }
7772 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007773#ifdef DEBUG_EXPR
7774 if (prefix == NULL)
7775 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7776 name);
7777 else
7778 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7779 prefix, name);
7780#endif
7781
Owen Taylor3473f882001-02-23 17:55:21 +00007782 if (CUR != '(') {
7783 XP_ERROR(XPATH_EXPR_ERROR);
7784 }
7785 NEXT;
7786 SKIP_BLANKS;
7787
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007788 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007789 if (CUR != ')') {
7790 while (CUR != 0) {
7791 int op1 = ctxt->comp->last;
7792 ctxt->comp->last = -1;
7793 xmlXPathCompileExpr(ctxt);
7794 CHECK_ERROR;
7795 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7796 nbargs++;
7797 if (CUR == ')') break;
7798 if (CUR != ',') {
7799 XP_ERROR(XPATH_EXPR_ERROR);
7800 }
7801 NEXT;
7802 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007803 }
Owen Taylor3473f882001-02-23 17:55:21 +00007804 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007805 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7806 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007807 NEXT;
7808 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007809}
7810
7811/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007812 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007813 * @ctxt: the XPath Parser context
7814 *
7815 * [15] PrimaryExpr ::= VariableReference
7816 * | '(' Expr ')'
7817 * | Literal
7818 * | Number
7819 * | FunctionCall
7820 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007821 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007822 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007823static void
7824xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007825 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007826 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007827 else if (CUR == '(') {
7828 NEXT;
7829 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007830 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007831 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007832 if (CUR != ')') {
7833 XP_ERROR(XPATH_EXPR_ERROR);
7834 }
7835 NEXT;
7836 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007837 } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007838 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007839 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007840 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007841 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007842 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007843 }
7844 SKIP_BLANKS;
7845}
7846
7847/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007848 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007849 * @ctxt: the XPath Parser context
7850 *
7851 * [20] FilterExpr ::= PrimaryExpr
7852 * | FilterExpr Predicate
7853 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007854 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007855 * Square brackets are used to filter expressions in the same way that
7856 * they are used in location paths. It is an error if the expression to
7857 * be filtered does not evaluate to a node-set. The context node list
7858 * used for evaluating the expression in square brackets is the node-set
7859 * to be filtered listed in document order.
7860 */
7861
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007862static void
7863xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7864 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007865 CHECK_ERROR;
7866 SKIP_BLANKS;
7867
7868 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007869 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007870 SKIP_BLANKS;
7871 }
7872
7873
7874}
7875
7876/**
7877 * xmlXPathScanName:
7878 * @ctxt: the XPath Parser context
7879 *
7880 * Trickery: parse an XML name but without consuming the input flow
7881 * Needed to avoid insanity in the parser state.
7882 *
7883 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7884 * CombiningChar | Extender
7885 *
7886 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7887 *
7888 * [6] Names ::= Name (S Name)*
7889 *
7890 * Returns the Name parsed or NULL
7891 */
7892
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007893static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007894xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7895 xmlChar buf[XML_MAX_NAMELEN];
7896 int len = 0;
7897
7898 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007899 if (!IS_LETTER_CH(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00007900 (CUR != ':')) {
7901 return(NULL);
7902 }
7903
William M. Brack76e95df2003-10-18 16:20:14 +00007904 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007905 (NXT(len) == '.') || (NXT(len) == '-') ||
7906 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007907 (IS_COMBINING_CH(NXT(len))) ||
7908 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007909 buf[len] = NXT(len);
7910 len++;
7911 if (len >= XML_MAX_NAMELEN) {
7912 xmlGenericError(xmlGenericErrorContext,
7913 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brack76e95df2003-10-18 16:20:14 +00007914 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007915 (NXT(len) == '.') || (NXT(len) == '-') ||
7916 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007917 (IS_COMBINING_CH(NXT(len))) ||
7918 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00007919 len++;
7920 break;
7921 }
7922 }
7923 return(xmlStrndup(buf, len));
7924}
7925
7926/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007927 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007928 * @ctxt: the XPath Parser context
7929 *
7930 * [19] PathExpr ::= LocationPath
7931 * | FilterExpr
7932 * | FilterExpr '/' RelativeLocationPath
7933 * | FilterExpr '//' RelativeLocationPath
7934 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007935 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007936 * The / operator and // operators combine an arbitrary expression
7937 * and a relative location path. It is an error if the expression
7938 * does not evaluate to a node-set.
7939 * The / operator does composition in the same way as when / is
7940 * used in a location path. As in location paths, // is short for
7941 * /descendant-or-self::node()/.
7942 */
7943
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007944static void
7945xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007946 int lc = 1; /* Should we branch to LocationPath ? */
7947 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7948
7949 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007950 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
7951 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007952 lc = 0;
7953 } else if (CUR == '*') {
7954 /* relative or absolute location path */
7955 lc = 1;
7956 } else if (CUR == '/') {
7957 /* relative or absolute location path */
7958 lc = 1;
7959 } else if (CUR == '@') {
7960 /* relative abbreviated attribute location path */
7961 lc = 1;
7962 } else if (CUR == '.') {
7963 /* relative abbreviated attribute location path */
7964 lc = 1;
7965 } else {
7966 /*
7967 * Problem is finding if we have a name here whether it's:
7968 * - a nodetype
7969 * - a function call in which case it's followed by '('
7970 * - an axis in which case it's followed by ':'
7971 * - a element name
7972 * We do an a priori analysis here rather than having to
7973 * maintain parsed token content through the recursive function
7974 * calls. This looks uglier but makes the code quite easier to
7975 * read/write/debug.
7976 */
7977 SKIP_BLANKS;
7978 name = xmlXPathScanName(ctxt);
7979 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7980#ifdef DEBUG_STEP
7981 xmlGenericError(xmlGenericErrorContext,
7982 "PathExpr: Axis\n");
7983#endif
7984 lc = 1;
7985 xmlFree(name);
7986 } else if (name != NULL) {
7987 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00007988
7989
7990 while (NXT(len) != 0) {
7991 if (NXT(len) == '/') {
7992 /* element name */
7993#ifdef DEBUG_STEP
7994 xmlGenericError(xmlGenericErrorContext,
7995 "PathExpr: AbbrRelLocation\n");
7996#endif
7997 lc = 1;
7998 break;
William M. Brack76e95df2003-10-18 16:20:14 +00007999 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008000 /* ignore blanks */
8001 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008002 } else if (NXT(len) == ':') {
8003#ifdef DEBUG_STEP
8004 xmlGenericError(xmlGenericErrorContext,
8005 "PathExpr: AbbrRelLocation\n");
8006#endif
8007 lc = 1;
8008 break;
8009 } else if ((NXT(len) == '(')) {
8010 /* Note Type or Function */
8011 if (xmlXPathIsNodeType(name)) {
8012#ifdef DEBUG_STEP
8013 xmlGenericError(xmlGenericErrorContext,
8014 "PathExpr: Type search\n");
8015#endif
8016 lc = 1;
8017 } else {
8018#ifdef DEBUG_STEP
8019 xmlGenericError(xmlGenericErrorContext,
8020 "PathExpr: function call\n");
8021#endif
8022 lc = 0;
8023 }
8024 break;
8025 } else if ((NXT(len) == '[')) {
8026 /* element name */
8027#ifdef DEBUG_STEP
8028 xmlGenericError(xmlGenericErrorContext,
8029 "PathExpr: AbbrRelLocation\n");
8030#endif
8031 lc = 1;
8032 break;
8033 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8034 (NXT(len) == '=')) {
8035 lc = 1;
8036 break;
8037 } else {
8038 lc = 1;
8039 break;
8040 }
8041 len++;
8042 }
8043 if (NXT(len) == 0) {
8044#ifdef DEBUG_STEP
8045 xmlGenericError(xmlGenericErrorContext,
8046 "PathExpr: AbbrRelLocation\n");
8047#endif
8048 /* element name */
8049 lc = 1;
8050 }
8051 xmlFree(name);
8052 } else {
8053 /* make sure all cases are covered explicitely */
8054 XP_ERROR(XPATH_EXPR_ERROR);
8055 }
8056 }
8057
8058 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008059 if (CUR == '/') {
8060 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8061 } else {
8062 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008063 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008064 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008065 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008066 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008067 CHECK_ERROR;
8068 if ((CUR == '/') && (NXT(1) == '/')) {
8069 SKIP(2);
8070 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008071
8072 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8073 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8074 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8075
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008076 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008077 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008078 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008079 }
8080 }
8081 SKIP_BLANKS;
8082}
8083
8084/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008085 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008086 * @ctxt: the XPath Parser context
8087 *
8088 * [18] UnionExpr ::= PathExpr
8089 * | UnionExpr '|' PathExpr
8090 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008091 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008092 */
8093
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008094static void
8095xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8096 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008097 CHECK_ERROR;
8098 SKIP_BLANKS;
8099 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008100 int op1 = ctxt->comp->last;
8101 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008102
8103 NEXT;
8104 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008105 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008106
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008107 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8108
Owen Taylor3473f882001-02-23 17:55:21 +00008109 SKIP_BLANKS;
8110 }
Owen Taylor3473f882001-02-23 17:55:21 +00008111}
8112
8113/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008114 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008115 * @ctxt: the XPath Parser context
8116 *
8117 * [27] UnaryExpr ::= UnionExpr
8118 * | '-' UnaryExpr
8119 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008120 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008121 */
8122
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008123static void
8124xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008125 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008126 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008127
8128 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008129 while (CUR == '-') {
8130 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008131 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008132 NEXT;
8133 SKIP_BLANKS;
8134 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008135
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008136 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008137 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008138 if (found) {
8139 if (minus)
8140 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8141 else
8142 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008143 }
8144}
8145
8146/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008147 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008148 * @ctxt: the XPath Parser context
8149 *
8150 * [26] MultiplicativeExpr ::= UnaryExpr
8151 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8152 * | MultiplicativeExpr 'div' UnaryExpr
8153 * | MultiplicativeExpr 'mod' UnaryExpr
8154 * [34] MultiplyOperator ::= '*'
8155 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008156 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008157 */
8158
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008159static void
8160xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8161 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008162 CHECK_ERROR;
8163 SKIP_BLANKS;
8164 while ((CUR == '*') ||
8165 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8166 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8167 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008168 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008169
8170 if (CUR == '*') {
8171 op = 0;
8172 NEXT;
8173 } else if (CUR == 'd') {
8174 op = 1;
8175 SKIP(3);
8176 } else if (CUR == 'm') {
8177 op = 2;
8178 SKIP(3);
8179 }
8180 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008181 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008182 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008183 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008184 SKIP_BLANKS;
8185 }
8186}
8187
8188/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008189 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008190 * @ctxt: the XPath Parser context
8191 *
8192 * [25] AdditiveExpr ::= MultiplicativeExpr
8193 * | AdditiveExpr '+' MultiplicativeExpr
8194 * | AdditiveExpr '-' MultiplicativeExpr
8195 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008196 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008197 */
8198
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008199static void
8200xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008201
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008202 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008203 CHECK_ERROR;
8204 SKIP_BLANKS;
8205 while ((CUR == '+') || (CUR == '-')) {
8206 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008207 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008208
8209 if (CUR == '+') plus = 1;
8210 else plus = 0;
8211 NEXT;
8212 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008213 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008214 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008215 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008216 SKIP_BLANKS;
8217 }
8218}
8219
8220/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008221 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008222 * @ctxt: the XPath Parser context
8223 *
8224 * [24] RelationalExpr ::= AdditiveExpr
8225 * | RelationalExpr '<' AdditiveExpr
8226 * | RelationalExpr '>' AdditiveExpr
8227 * | RelationalExpr '<=' AdditiveExpr
8228 * | RelationalExpr '>=' AdditiveExpr
8229 *
8230 * A <= B > C is allowed ? Answer from James, yes with
8231 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8232 * which is basically what got implemented.
8233 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008234 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008235 * on the stack
8236 */
8237
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008238static void
8239xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8240 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008241 CHECK_ERROR;
8242 SKIP_BLANKS;
8243 while ((CUR == '<') ||
8244 (CUR == '>') ||
8245 ((CUR == '<') && (NXT(1) == '=')) ||
8246 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008247 int inf, strict;
8248 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008249
8250 if (CUR == '<') inf = 1;
8251 else inf = 0;
8252 if (NXT(1) == '=') strict = 0;
8253 else strict = 1;
8254 NEXT;
8255 if (!strict) NEXT;
8256 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008257 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008258 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008259 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008260 SKIP_BLANKS;
8261 }
8262}
8263
8264/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008265 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008266 * @ctxt: the XPath Parser context
8267 *
8268 * [23] EqualityExpr ::= RelationalExpr
8269 * | EqualityExpr '=' RelationalExpr
8270 * | EqualityExpr '!=' RelationalExpr
8271 *
8272 * A != B != C is allowed ? Answer from James, yes with
8273 * (RelationalExpr = RelationalExpr) = RelationalExpr
8274 * (RelationalExpr != RelationalExpr) != RelationalExpr
8275 * which is basically what got implemented.
8276 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008277 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008278 *
8279 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008280static void
8281xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8282 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008283 CHECK_ERROR;
8284 SKIP_BLANKS;
8285 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008286 int eq;
8287 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008288
8289 if (CUR == '=') eq = 1;
8290 else eq = 0;
8291 NEXT;
8292 if (!eq) NEXT;
8293 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008294 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008295 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008296 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008297 SKIP_BLANKS;
8298 }
8299}
8300
8301/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008302 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008303 * @ctxt: the XPath Parser context
8304 *
8305 * [22] AndExpr ::= EqualityExpr
8306 * | AndExpr 'and' EqualityExpr
8307 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008308 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008309 *
8310 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008311static void
8312xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8313 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008314 CHECK_ERROR;
8315 SKIP_BLANKS;
8316 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008317 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008318 SKIP(3);
8319 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008320 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008321 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008322 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008323 SKIP_BLANKS;
8324 }
8325}
8326
8327/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008328 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008329 * @ctxt: the XPath Parser context
8330 *
8331 * [14] Expr ::= OrExpr
8332 * [21] OrExpr ::= AndExpr
8333 * | OrExpr 'or' AndExpr
8334 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008335 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008336 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008337static void
8338xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8339 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008340 CHECK_ERROR;
8341 SKIP_BLANKS;
8342 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008343 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008344 SKIP(2);
8345 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008346 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008347 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008348 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8349 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008350 SKIP_BLANKS;
8351 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008352 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8353 /* more ops could be optimized too */
8354 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8355 }
Owen Taylor3473f882001-02-23 17:55:21 +00008356}
8357
8358/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008359 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008360 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008361 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008362 *
8363 * [8] Predicate ::= '[' PredicateExpr ']'
8364 * [9] PredicateExpr ::= Expr
8365 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008366 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008367 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008368static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008369xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008370 int op1 = ctxt->comp->last;
8371
8372 SKIP_BLANKS;
8373 if (CUR != '[') {
8374 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8375 }
8376 NEXT;
8377 SKIP_BLANKS;
8378
8379 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008380 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008381 CHECK_ERROR;
8382
8383 if (CUR != ']') {
8384 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8385 }
8386
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008387 if (filter)
8388 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8389 else
8390 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008391
8392 NEXT;
8393 SKIP_BLANKS;
8394}
8395
8396/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008397 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008398 * @ctxt: the XPath Parser context
8399 * @test: pointer to a xmlXPathTestVal
8400 * @type: pointer to a xmlXPathTypeVal
8401 * @prefix: placeholder for a possible name prefix
8402 *
8403 * [7] NodeTest ::= NameTest
8404 * | NodeType '(' ')'
8405 * | 'processing-instruction' '(' Literal ')'
8406 *
8407 * [37] NameTest ::= '*'
8408 * | NCName ':' '*'
8409 * | QName
8410 * [38] NodeType ::= 'comment'
8411 * | 'text'
8412 * | 'processing-instruction'
8413 * | 'node'
8414 *
8415 * Returns the name found and update @test, @type and @prefix appropriately
8416 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008417static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008418xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8419 xmlXPathTypeVal *type, const xmlChar **prefix,
8420 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008421 int blanks;
8422
8423 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8424 STRANGE;
8425 return(NULL);
8426 }
William M. Brack78637da2003-07-31 14:47:38 +00008427 *type = (xmlXPathTypeVal) 0;
8428 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008429 *prefix = NULL;
8430 SKIP_BLANKS;
8431
8432 if ((name == NULL) && (CUR == '*')) {
8433 /*
8434 * All elements
8435 */
8436 NEXT;
8437 *test = NODE_TEST_ALL;
8438 return(NULL);
8439 }
8440
8441 if (name == NULL)
8442 name = xmlXPathParseNCName(ctxt);
8443 if (name == NULL) {
8444 XP_ERROR0(XPATH_EXPR_ERROR);
8445 }
8446
William M. Brack76e95df2003-10-18 16:20:14 +00008447 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008448 SKIP_BLANKS;
8449 if (CUR == '(') {
8450 NEXT;
8451 /*
8452 * NodeType or PI search
8453 */
8454 if (xmlStrEqual(name, BAD_CAST "comment"))
8455 *type = NODE_TYPE_COMMENT;
8456 else if (xmlStrEqual(name, BAD_CAST "node"))
8457 *type = NODE_TYPE_NODE;
8458 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8459 *type = NODE_TYPE_PI;
8460 else if (xmlStrEqual(name, BAD_CAST "text"))
8461 *type = NODE_TYPE_TEXT;
8462 else {
8463 if (name != NULL)
8464 xmlFree(name);
8465 XP_ERROR0(XPATH_EXPR_ERROR);
8466 }
8467
8468 *test = NODE_TEST_TYPE;
8469
8470 SKIP_BLANKS;
8471 if (*type == NODE_TYPE_PI) {
8472 /*
8473 * Specific case: search a PI by name.
8474 */
Owen Taylor3473f882001-02-23 17:55:21 +00008475 if (name != NULL)
8476 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008477 name = NULL;
8478 if (CUR != ')') {
8479 name = xmlXPathParseLiteral(ctxt);
8480 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008481 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008482 SKIP_BLANKS;
8483 }
Owen Taylor3473f882001-02-23 17:55:21 +00008484 }
8485 if (CUR != ')') {
8486 if (name != NULL)
8487 xmlFree(name);
8488 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8489 }
8490 NEXT;
8491 return(name);
8492 }
8493 *test = NODE_TEST_NAME;
8494 if ((!blanks) && (CUR == ':')) {
8495 NEXT;
8496
8497 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008498 * Since currently the parser context don't have a
8499 * namespace list associated:
8500 * The namespace name for this prefix can be computed
8501 * only at evaluation time. The compilation is done
8502 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008503 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008504#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008505 *prefix = xmlXPathNsLookup(ctxt->context, name);
8506 if (name != NULL)
8507 xmlFree(name);
8508 if (*prefix == NULL) {
8509 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8510 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008511#else
8512 *prefix = name;
8513#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008514
8515 if (CUR == '*') {
8516 /*
8517 * All elements
8518 */
8519 NEXT;
8520 *test = NODE_TEST_ALL;
8521 return(NULL);
8522 }
8523
8524 name = xmlXPathParseNCName(ctxt);
8525 if (name == NULL) {
8526 XP_ERROR0(XPATH_EXPR_ERROR);
8527 }
8528 }
8529 return(name);
8530}
8531
8532/**
8533 * xmlXPathIsAxisName:
8534 * @name: a preparsed name token
8535 *
8536 * [6] AxisName ::= 'ancestor'
8537 * | 'ancestor-or-self'
8538 * | 'attribute'
8539 * | 'child'
8540 * | 'descendant'
8541 * | 'descendant-or-self'
8542 * | 'following'
8543 * | 'following-sibling'
8544 * | 'namespace'
8545 * | 'parent'
8546 * | 'preceding'
8547 * | 'preceding-sibling'
8548 * | 'self'
8549 *
8550 * Returns the axis or 0
8551 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008552static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008553xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008554 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008555 switch (name[0]) {
8556 case 'a':
8557 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8558 ret = AXIS_ANCESTOR;
8559 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8560 ret = AXIS_ANCESTOR_OR_SELF;
8561 if (xmlStrEqual(name, BAD_CAST "attribute"))
8562 ret = AXIS_ATTRIBUTE;
8563 break;
8564 case 'c':
8565 if (xmlStrEqual(name, BAD_CAST "child"))
8566 ret = AXIS_CHILD;
8567 break;
8568 case 'd':
8569 if (xmlStrEqual(name, BAD_CAST "descendant"))
8570 ret = AXIS_DESCENDANT;
8571 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8572 ret = AXIS_DESCENDANT_OR_SELF;
8573 break;
8574 case 'f':
8575 if (xmlStrEqual(name, BAD_CAST "following"))
8576 ret = AXIS_FOLLOWING;
8577 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8578 ret = AXIS_FOLLOWING_SIBLING;
8579 break;
8580 case 'n':
8581 if (xmlStrEqual(name, BAD_CAST "namespace"))
8582 ret = AXIS_NAMESPACE;
8583 break;
8584 case 'p':
8585 if (xmlStrEqual(name, BAD_CAST "parent"))
8586 ret = AXIS_PARENT;
8587 if (xmlStrEqual(name, BAD_CAST "preceding"))
8588 ret = AXIS_PRECEDING;
8589 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8590 ret = AXIS_PRECEDING_SIBLING;
8591 break;
8592 case 's':
8593 if (xmlStrEqual(name, BAD_CAST "self"))
8594 ret = AXIS_SELF;
8595 break;
8596 }
8597 return(ret);
8598}
8599
8600/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008601 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008602 * @ctxt: the XPath Parser context
8603 *
8604 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8605 * | AbbreviatedStep
8606 *
8607 * [12] AbbreviatedStep ::= '.' | '..'
8608 *
8609 * [5] AxisSpecifier ::= AxisName '::'
8610 * | AbbreviatedAxisSpecifier
8611 *
8612 * [13] AbbreviatedAxisSpecifier ::= '@'?
8613 *
8614 * Modified for XPtr range support as:
8615 *
8616 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8617 * | AbbreviatedStep
8618 * | 'range-to' '(' Expr ')' Predicate*
8619 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008620 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008621 * A location step of . is short for self::node(). This is
8622 * particularly useful in conjunction with //. For example, the
8623 * location path .//para is short for
8624 * self::node()/descendant-or-self::node()/child::para
8625 * and so will select all para descendant elements of the context
8626 * node.
8627 * Similarly, a location step of .. is short for parent::node().
8628 * For example, ../title is short for parent::node()/child::title
8629 * and so will select the title children of the parent of the context
8630 * node.
8631 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008632static void
8633xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008634#ifdef LIBXML_XPTR_ENABLED
8635 int rangeto = 0;
8636 int op2 = -1;
8637#endif
8638
Owen Taylor3473f882001-02-23 17:55:21 +00008639 SKIP_BLANKS;
8640 if ((CUR == '.') && (NXT(1) == '.')) {
8641 SKIP(2);
8642 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008643 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8644 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008645 } else if (CUR == '.') {
8646 NEXT;
8647 SKIP_BLANKS;
8648 } else {
8649 xmlChar *name = NULL;
8650 const xmlChar *prefix = NULL;
8651 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008652 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008653 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008654 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008655
8656 /*
8657 * The modification needed for XPointer change to the production
8658 */
8659#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008660 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008661 name = xmlXPathParseNCName(ctxt);
8662 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008663 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008664 xmlFree(name);
8665 SKIP_BLANKS;
8666 if (CUR != '(') {
8667 XP_ERROR(XPATH_EXPR_ERROR);
8668 }
8669 NEXT;
8670 SKIP_BLANKS;
8671
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008672 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008673 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008674 CHECK_ERROR;
8675
8676 SKIP_BLANKS;
8677 if (CUR != ')') {
8678 XP_ERROR(XPATH_EXPR_ERROR);
8679 }
8680 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008681 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008682 goto eval_predicates;
8683 }
8684 }
8685#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008686 if (CUR == '*') {
8687 axis = AXIS_CHILD;
8688 } else {
8689 if (name == NULL)
8690 name = xmlXPathParseNCName(ctxt);
8691 if (name != NULL) {
8692 axis = xmlXPathIsAxisName(name);
8693 if (axis != 0) {
8694 SKIP_BLANKS;
8695 if ((CUR == ':') && (NXT(1) == ':')) {
8696 SKIP(2);
8697 xmlFree(name);
8698 name = NULL;
8699 } else {
8700 /* an element name can conflict with an axis one :-\ */
8701 axis = AXIS_CHILD;
8702 }
Owen Taylor3473f882001-02-23 17:55:21 +00008703 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008704 axis = AXIS_CHILD;
8705 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008706 } else if (CUR == '@') {
8707 NEXT;
8708 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008709 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008710 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008711 }
Owen Taylor3473f882001-02-23 17:55:21 +00008712 }
8713
8714 CHECK_ERROR;
8715
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008716 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008717 if (test == 0)
8718 return;
8719
8720#ifdef DEBUG_STEP
8721 xmlGenericError(xmlGenericErrorContext,
8722 "Basis : computing new set\n");
8723#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008724
Owen Taylor3473f882001-02-23 17:55:21 +00008725#ifdef DEBUG_STEP
8726 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008727 if (ctxt->value == NULL)
8728 xmlGenericError(xmlGenericErrorContext, "no value\n");
8729 else if (ctxt->value->nodesetval == NULL)
8730 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8731 else
8732 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008733#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008734
8735eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008736 op1 = ctxt->comp->last;
8737 ctxt->comp->last = -1;
8738
Owen Taylor3473f882001-02-23 17:55:21 +00008739 SKIP_BLANKS;
8740 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008741 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008742 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008743
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008744#ifdef LIBXML_XPTR_ENABLED
8745 if (rangeto) {
8746 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8747 } else
8748#endif
8749 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8750 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008751
Owen Taylor3473f882001-02-23 17:55:21 +00008752 }
8753#ifdef DEBUG_STEP
8754 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008755 if (ctxt->value == NULL)
8756 xmlGenericError(xmlGenericErrorContext, "no value\n");
8757 else if (ctxt->value->nodesetval == NULL)
8758 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8759 else
8760 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8761 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008762#endif
8763}
8764
8765/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008766 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008767 * @ctxt: the XPath Parser context
8768 *
8769 * [3] RelativeLocationPath ::= Step
8770 * | RelativeLocationPath '/' Step
8771 * | AbbreviatedRelativeLocationPath
8772 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8773 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008774 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008775 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008776static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008777xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008778(xmlXPathParserContextPtr ctxt) {
8779 SKIP_BLANKS;
8780 if ((CUR == '/') && (NXT(1) == '/')) {
8781 SKIP(2);
8782 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008783 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8784 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008785 } else if (CUR == '/') {
8786 NEXT;
8787 SKIP_BLANKS;
8788 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008789 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008790 SKIP_BLANKS;
8791 while (CUR == '/') {
8792 if ((CUR == '/') && (NXT(1) == '/')) {
8793 SKIP(2);
8794 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008795 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008796 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008797 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008798 } else if (CUR == '/') {
8799 NEXT;
8800 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008801 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008802 }
8803 SKIP_BLANKS;
8804 }
8805}
8806
8807/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008808 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008809 * @ctxt: the XPath Parser context
8810 *
8811 * [1] LocationPath ::= RelativeLocationPath
8812 * | AbsoluteLocationPath
8813 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8814 * | AbbreviatedAbsoluteLocationPath
8815 * [10] AbbreviatedAbsoluteLocationPath ::=
8816 * '//' RelativeLocationPath
8817 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008818 * Compile a location path
8819 *
Owen Taylor3473f882001-02-23 17:55:21 +00008820 * // is short for /descendant-or-self::node()/. For example,
8821 * //para is short for /descendant-or-self::node()/child::para and
8822 * so will select any para element in the document (even a para element
8823 * that is a document element will be selected by //para since the
8824 * document element node is a child of the root node); div//para is
8825 * short for div/descendant-or-self::node()/child::para and so will
8826 * select all para descendants of div children.
8827 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008828static void
8829xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008830 SKIP_BLANKS;
8831 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008832 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008833 } else {
8834 while (CUR == '/') {
8835 if ((CUR == '/') && (NXT(1) == '/')) {
8836 SKIP(2);
8837 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008838 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8839 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008840 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008841 } else if (CUR == '/') {
8842 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008843 SKIP_BLANKS;
8844 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008845 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008846 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008847 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008848 }
8849 }
8850 }
8851}
8852
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008853/************************************************************************
8854 * *
8855 * XPath precompiled expression evaluation *
8856 * *
8857 ************************************************************************/
8858
Daniel Veillardf06307e2001-07-03 10:35:50 +00008859static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008860xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8861
8862/**
8863 * xmlXPathNodeCollectAndTest:
8864 * @ctxt: the XPath Parser context
8865 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008866 * @first: pointer to the first element in document order
8867 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008868 *
8869 * This is the function implementing a step: based on the current list
8870 * of nodes, it builds up a new list, looking at all nodes under that
8871 * axis and selecting them it also do the predicate filtering
8872 *
8873 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008874 *
8875 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008876 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008877static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008878xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008879 xmlXPathStepOpPtr op,
8880 xmlNodePtr * first, xmlNodePtr * last)
8881{
William M. Brack78637da2003-07-31 14:47:38 +00008882 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8883 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8884 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008885 const xmlChar *prefix = op->value4;
8886 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008887 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008888
8889#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008890 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008891#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008892 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008893 xmlNodeSetPtr ret, list;
8894 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008895 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008896 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008897 xmlNodePtr cur = NULL;
8898 xmlXPathObjectPtr obj;
8899 xmlNodeSetPtr nodelist;
8900 xmlNodePtr tmp;
8901
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008903 obj = valuePop(ctxt);
8904 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008905 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008906 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008907 URI = xmlXPathNsLookup(ctxt->context, prefix);
8908 if (URI == NULL)
8909 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008910 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008911#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008913#endif
8914 switch (axis) {
8915 case AXIS_ANCESTOR:
8916#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008918#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008919 first = NULL;
8920 next = xmlXPathNextAncestor;
8921 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008922 case AXIS_ANCESTOR_OR_SELF:
8923#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008924 xmlGenericError(xmlGenericErrorContext,
8925 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008927 first = NULL;
8928 next = xmlXPathNextAncestorOrSelf;
8929 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008930 case AXIS_ATTRIBUTE:
8931#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008932 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008933#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008934 first = NULL;
8935 last = NULL;
8936 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008937 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008939 case AXIS_CHILD:
8940#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008941 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008942#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008943 last = NULL;
8944 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008945 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008946 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008947 case AXIS_DESCENDANT:
8948#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008949 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008950#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008951 last = NULL;
8952 next = xmlXPathNextDescendant;
8953 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008954 case AXIS_DESCENDANT_OR_SELF:
8955#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008956 xmlGenericError(xmlGenericErrorContext,
8957 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008958#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008959 last = NULL;
8960 next = xmlXPathNextDescendantOrSelf;
8961 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008962 case AXIS_FOLLOWING:
8963#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008964 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008965#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008966 last = NULL;
8967 next = xmlXPathNextFollowing;
8968 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008969 case AXIS_FOLLOWING_SIBLING:
8970#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008971 xmlGenericError(xmlGenericErrorContext,
8972 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974 last = NULL;
8975 next = xmlXPathNextFollowingSibling;
8976 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977 case AXIS_NAMESPACE:
8978#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008979 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008980#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008981 first = NULL;
8982 last = NULL;
8983 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008984 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008985 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008986 case AXIS_PARENT:
8987#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008988 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008989#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 first = NULL;
8991 next = xmlXPathNextParent;
8992 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008993 case AXIS_PRECEDING:
8994#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008995 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008996#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008997 first = NULL;
8998 next = xmlXPathNextPrecedingInternal;
8999 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009000 case AXIS_PRECEDING_SIBLING:
9001#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009002 xmlGenericError(xmlGenericErrorContext,
9003 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009004#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009005 first = NULL;
9006 next = xmlXPathNextPrecedingSibling;
9007 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009008 case AXIS_SELF:
9009#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009010 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009011#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009012 first = NULL;
9013 last = NULL;
9014 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009015 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009016 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009017 }
9018 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009019 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009020
9021 nodelist = obj->nodesetval;
9022 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009023 xmlXPathFreeObject(obj);
9024 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9025 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009026 }
9027 addNode = xmlXPathNodeSetAddUnique;
9028 ret = NULL;
9029#ifdef DEBUG_STEP
9030 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009031 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009032 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009033 case NODE_TEST_NONE:
9034 xmlGenericError(xmlGenericErrorContext,
9035 " searching for none !!!\n");
9036 break;
9037 case NODE_TEST_TYPE:
9038 xmlGenericError(xmlGenericErrorContext,
9039 " searching for type %d\n", type);
9040 break;
9041 case NODE_TEST_PI:
9042 xmlGenericError(xmlGenericErrorContext,
9043 " searching for PI !!!\n");
9044 break;
9045 case NODE_TEST_ALL:
9046 xmlGenericError(xmlGenericErrorContext,
9047 " searching for *\n");
9048 break;
9049 case NODE_TEST_NS:
9050 xmlGenericError(xmlGenericErrorContext,
9051 " searching for namespace %s\n",
9052 prefix);
9053 break;
9054 case NODE_TEST_NAME:
9055 xmlGenericError(xmlGenericErrorContext,
9056 " searching for name %s\n", name);
9057 if (prefix != NULL)
9058 xmlGenericError(xmlGenericErrorContext,
9059 " with namespace %s\n", prefix);
9060 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009061 }
9062 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9063#endif
9064 /*
9065 * 2.3 Node Tests
9066 * - For the attribute axis, the principal node type is attribute.
9067 * - For the namespace axis, the principal node type is namespace.
9068 * - For other axes, the principal node type is element.
9069 *
9070 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009071 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009072 * select all element children of the context node
9073 */
9074 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009075 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009076 ctxt->context->node = nodelist->nodeTab[i];
9077
Daniel Veillardf06307e2001-07-03 10:35:50 +00009078 cur = NULL;
9079 list = xmlXPathNodeSetCreate(NULL);
9080 do {
9081 cur = next(ctxt, cur);
9082 if (cur == NULL)
9083 break;
9084 if ((first != NULL) && (*first == cur))
9085 break;
9086 if (((t % 256) == 0) &&
9087 (first != NULL) && (*first != NULL) &&
9088 (xmlXPathCmpNodes(*first, cur) >= 0))
9089 break;
9090 if ((last != NULL) && (*last == cur))
9091 break;
9092 if (((t % 256) == 0) &&
9093 (last != NULL) && (*last != NULL) &&
9094 (xmlXPathCmpNodes(cur, *last) >= 0))
9095 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009096 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009097#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009098 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9099#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009101 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009102 ctxt->context->node = tmp;
9103 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009104 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 if ((cur->type == type) ||
9106 ((type == NODE_TYPE_NODE) &&
9107 ((cur->type == XML_DOCUMENT_NODE) ||
9108 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9109 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009110 (cur->type == XML_NAMESPACE_DECL) ||
9111 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009112 (cur->type == XML_PI_NODE) ||
9113 (cur->type == XML_COMMENT_NODE) ||
9114 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009115 (cur->type == XML_TEXT_NODE))) ||
9116 ((type == NODE_TYPE_TEXT) &&
9117 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009118#ifdef DEBUG_STEP
9119 n++;
9120#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 addNode(list, cur);
9122 }
9123 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009124 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009125 if (cur->type == XML_PI_NODE) {
9126 if ((name != NULL) &&
9127 (!xmlStrEqual(name, cur->name)))
9128 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009129#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009130 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009131#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 addNode(list, cur);
9133 }
9134 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 if (axis == AXIS_ATTRIBUTE) {
9137 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009138#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009140#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 addNode(list, cur);
9142 }
9143 } else if (axis == AXIS_NAMESPACE) {
9144 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009145#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009146 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009147#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009148 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9149 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009150 }
9151 } else {
9152 if (cur->type == XML_ELEMENT_NODE) {
9153 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009154#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009155 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009156#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009157 addNode(list, cur);
9158 } else if ((cur->ns != NULL) &&
9159 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009160#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009161 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009162#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009163 addNode(list, cur);
9164 }
9165 }
9166 }
9167 break;
9168 case NODE_TEST_NS:{
9169 TODO;
9170 break;
9171 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009172 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009173 switch (cur->type) {
9174 case XML_ELEMENT_NODE:
9175 if (xmlStrEqual(name, cur->name)) {
9176 if (prefix == NULL) {
9177 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009178#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009179 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009180#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009181 addNode(list, cur);
9182 }
9183 } else {
9184 if ((cur->ns != NULL) &&
9185 (xmlStrEqual(URI,
9186 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009187#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009188 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009189#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009190 addNode(list, cur);
9191 }
9192 }
9193 }
9194 break;
9195 case XML_ATTRIBUTE_NODE:{
9196 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009197
Daniel Veillardf06307e2001-07-03 10:35:50 +00009198 if (xmlStrEqual(name, attr->name)) {
9199 if (prefix == NULL) {
9200 if ((attr->ns == NULL) ||
9201 (attr->ns->prefix == NULL)) {
9202#ifdef DEBUG_STEP
9203 n++;
9204#endif
9205 addNode(list,
9206 (xmlNodePtr) attr);
9207 }
9208 } else {
9209 if ((attr->ns != NULL) &&
9210 (xmlStrEqual(URI,
9211 attr->ns->
9212 href))) {
9213#ifdef DEBUG_STEP
9214 n++;
9215#endif
9216 addNode(list,
9217 (xmlNodePtr) attr);
9218 }
9219 }
9220 }
9221 break;
9222 }
9223 case XML_NAMESPACE_DECL:
9224 if (cur->type == XML_NAMESPACE_DECL) {
9225 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009226
Daniel Veillardf06307e2001-07-03 10:35:50 +00009227 if ((ns->prefix != NULL) && (name != NULL)
9228 && (xmlStrEqual(ns->prefix, name))) {
9229#ifdef DEBUG_STEP
9230 n++;
9231#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009232 xmlXPathNodeSetAddNs(list,
9233 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009234 }
9235 }
9236 break;
9237 default:
9238 break;
9239 }
9240 break;
9241 break;
9242 }
9243 } while (cur != NULL);
9244
9245 /*
9246 * If there is some predicate filtering do it now
9247 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009248 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009249 xmlXPathObjectPtr obj2;
9250
9251 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9252 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9253 CHECK_TYPE0(XPATH_NODESET);
9254 obj2 = valuePop(ctxt);
9255 list = obj2->nodesetval;
9256 obj2->nodesetval = NULL;
9257 xmlXPathFreeObject(obj2);
9258 }
9259 if (ret == NULL) {
9260 ret = list;
9261 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009262 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009263 xmlXPathFreeNodeSet(list);
9264 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009265 }
9266 ctxt->context->node = tmp;
9267#ifdef DEBUG_STEP
9268 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009269 "\nExamined %d nodes, found %d nodes at that step\n",
9270 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009271#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009272 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009273 if ((obj->boolval) && (obj->user != NULL)) {
9274 ctxt->value->boolval = 1;
9275 ctxt->value->user = obj->user;
9276 obj->user = NULL;
9277 obj->boolval = 0;
9278 }
9279 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009280 return(t);
9281}
9282
9283/**
9284 * xmlXPathNodeCollectAndTestNth:
9285 * @ctxt: the XPath Parser context
9286 * @op: the XPath precompiled step operation
9287 * @indx: the index to collect
9288 * @first: pointer to the first element in document order
9289 * @last: pointer to the last element in document order
9290 *
9291 * This is the function implementing a step: based on the current list
9292 * of nodes, it builds up a new list, looking at all nodes under that
9293 * axis and selecting them it also do the predicate filtering
9294 *
9295 * Pushes the new NodeSet resulting from the search.
9296 * Returns the number of node traversed
9297 */
9298static int
9299xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9300 xmlXPathStepOpPtr op, int indx,
9301 xmlNodePtr * first, xmlNodePtr * last)
9302{
William M. Brack78637da2003-07-31 14:47:38 +00009303 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9304 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9305 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009306 const xmlChar *prefix = op->value4;
9307 const xmlChar *name = op->value5;
9308 const xmlChar *URI = NULL;
9309 int n = 0, t = 0;
9310
9311 int i;
9312 xmlNodeSetPtr list;
9313 xmlXPathTraversalFunction next = NULL;
9314 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9315 xmlNodePtr cur = NULL;
9316 xmlXPathObjectPtr obj;
9317 xmlNodeSetPtr nodelist;
9318 xmlNodePtr tmp;
9319
9320 CHECK_TYPE0(XPATH_NODESET);
9321 obj = valuePop(ctxt);
9322 addNode = xmlXPathNodeSetAdd;
9323 if (prefix != NULL) {
9324 URI = xmlXPathNsLookup(ctxt->context, prefix);
9325 if (URI == NULL)
9326 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9327 }
9328#ifdef DEBUG_STEP_NTH
9329 xmlGenericError(xmlGenericErrorContext, "new step : ");
9330 if (first != NULL) {
9331 if (*first != NULL)
9332 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9333 (*first)->name);
9334 else
9335 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9336 }
9337 if (last != NULL) {
9338 if (*last != NULL)
9339 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9340 (*last)->name);
9341 else
9342 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9343 }
9344#endif
9345 switch (axis) {
9346 case AXIS_ANCESTOR:
9347#ifdef DEBUG_STEP_NTH
9348 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9349#endif
9350 first = NULL;
9351 next = xmlXPathNextAncestor;
9352 break;
9353 case AXIS_ANCESTOR_OR_SELF:
9354#ifdef DEBUG_STEP_NTH
9355 xmlGenericError(xmlGenericErrorContext,
9356 "axis 'ancestors-or-self' ");
9357#endif
9358 first = NULL;
9359 next = xmlXPathNextAncestorOrSelf;
9360 break;
9361 case AXIS_ATTRIBUTE:
9362#ifdef DEBUG_STEP_NTH
9363 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9364#endif
9365 first = NULL;
9366 last = NULL;
9367 next = xmlXPathNextAttribute;
9368 break;
9369 case AXIS_CHILD:
9370#ifdef DEBUG_STEP_NTH
9371 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9372#endif
9373 last = NULL;
9374 next = xmlXPathNextChild;
9375 break;
9376 case AXIS_DESCENDANT:
9377#ifdef DEBUG_STEP_NTH
9378 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9379#endif
9380 last = NULL;
9381 next = xmlXPathNextDescendant;
9382 break;
9383 case AXIS_DESCENDANT_OR_SELF:
9384#ifdef DEBUG_STEP_NTH
9385 xmlGenericError(xmlGenericErrorContext,
9386 "axis 'descendant-or-self' ");
9387#endif
9388 last = NULL;
9389 next = xmlXPathNextDescendantOrSelf;
9390 break;
9391 case AXIS_FOLLOWING:
9392#ifdef DEBUG_STEP_NTH
9393 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9394#endif
9395 last = NULL;
9396 next = xmlXPathNextFollowing;
9397 break;
9398 case AXIS_FOLLOWING_SIBLING:
9399#ifdef DEBUG_STEP_NTH
9400 xmlGenericError(xmlGenericErrorContext,
9401 "axis 'following-siblings' ");
9402#endif
9403 last = NULL;
9404 next = xmlXPathNextFollowingSibling;
9405 break;
9406 case AXIS_NAMESPACE:
9407#ifdef DEBUG_STEP_NTH
9408 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9409#endif
9410 last = NULL;
9411 first = NULL;
9412 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9413 break;
9414 case AXIS_PARENT:
9415#ifdef DEBUG_STEP_NTH
9416 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9417#endif
9418 first = NULL;
9419 next = xmlXPathNextParent;
9420 break;
9421 case AXIS_PRECEDING:
9422#ifdef DEBUG_STEP_NTH
9423 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9424#endif
9425 first = NULL;
9426 next = xmlXPathNextPrecedingInternal;
9427 break;
9428 case AXIS_PRECEDING_SIBLING:
9429#ifdef DEBUG_STEP_NTH
9430 xmlGenericError(xmlGenericErrorContext,
9431 "axis 'preceding-sibling' ");
9432#endif
9433 first = NULL;
9434 next = xmlXPathNextPrecedingSibling;
9435 break;
9436 case AXIS_SELF:
9437#ifdef DEBUG_STEP_NTH
9438 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9439#endif
9440 first = NULL;
9441 last = NULL;
9442 next = xmlXPathNextSelf;
9443 break;
9444 }
9445 if (next == NULL)
9446 return(0);
9447
9448 nodelist = obj->nodesetval;
9449 if (nodelist == NULL) {
9450 xmlXPathFreeObject(obj);
9451 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9452 return(0);
9453 }
9454 addNode = xmlXPathNodeSetAddUnique;
9455#ifdef DEBUG_STEP_NTH
9456 xmlGenericError(xmlGenericErrorContext,
9457 " context contains %d nodes\n", nodelist->nodeNr);
9458 switch (test) {
9459 case NODE_TEST_NONE:
9460 xmlGenericError(xmlGenericErrorContext,
9461 " searching for none !!!\n");
9462 break;
9463 case NODE_TEST_TYPE:
9464 xmlGenericError(xmlGenericErrorContext,
9465 " searching for type %d\n", type);
9466 break;
9467 case NODE_TEST_PI:
9468 xmlGenericError(xmlGenericErrorContext,
9469 " searching for PI !!!\n");
9470 break;
9471 case NODE_TEST_ALL:
9472 xmlGenericError(xmlGenericErrorContext,
9473 " searching for *\n");
9474 break;
9475 case NODE_TEST_NS:
9476 xmlGenericError(xmlGenericErrorContext,
9477 " searching for namespace %s\n",
9478 prefix);
9479 break;
9480 case NODE_TEST_NAME:
9481 xmlGenericError(xmlGenericErrorContext,
9482 " searching for name %s\n", name);
9483 if (prefix != NULL)
9484 xmlGenericError(xmlGenericErrorContext,
9485 " with namespace %s\n", prefix);
9486 break;
9487 }
9488 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9489#endif
9490 /*
9491 * 2.3 Node Tests
9492 * - For the attribute axis, the principal node type is attribute.
9493 * - For the namespace axis, the principal node type is namespace.
9494 * - For other axes, the principal node type is element.
9495 *
9496 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009497 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009498 * select all element children of the context node
9499 */
9500 tmp = ctxt->context->node;
9501 list = xmlXPathNodeSetCreate(NULL);
9502 for (i = 0; i < nodelist->nodeNr; i++) {
9503 ctxt->context->node = nodelist->nodeTab[i];
9504
9505 cur = NULL;
9506 n = 0;
9507 do {
9508 cur = next(ctxt, cur);
9509 if (cur == NULL)
9510 break;
9511 if ((first != NULL) && (*first == cur))
9512 break;
9513 if (((t % 256) == 0) &&
9514 (first != NULL) && (*first != NULL) &&
9515 (xmlXPathCmpNodes(*first, cur) >= 0))
9516 break;
9517 if ((last != NULL) && (*last == cur))
9518 break;
9519 if (((t % 256) == 0) &&
9520 (last != NULL) && (*last != NULL) &&
9521 (xmlXPathCmpNodes(cur, *last) >= 0))
9522 break;
9523 t++;
9524 switch (test) {
9525 case NODE_TEST_NONE:
9526 ctxt->context->node = tmp;
9527 STRANGE return(0);
9528 case NODE_TEST_TYPE:
9529 if ((cur->type == type) ||
9530 ((type == NODE_TYPE_NODE) &&
9531 ((cur->type == XML_DOCUMENT_NODE) ||
9532 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9533 (cur->type == XML_ELEMENT_NODE) ||
9534 (cur->type == XML_PI_NODE) ||
9535 (cur->type == XML_COMMENT_NODE) ||
9536 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009537 (cur->type == XML_TEXT_NODE))) ||
9538 ((type == NODE_TYPE_TEXT) &&
9539 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009540 n++;
9541 if (n == indx)
9542 addNode(list, cur);
9543 }
9544 break;
9545 case NODE_TEST_PI:
9546 if (cur->type == XML_PI_NODE) {
9547 if ((name != NULL) &&
9548 (!xmlStrEqual(name, cur->name)))
9549 break;
9550 n++;
9551 if (n == indx)
9552 addNode(list, cur);
9553 }
9554 break;
9555 case NODE_TEST_ALL:
9556 if (axis == AXIS_ATTRIBUTE) {
9557 if (cur->type == XML_ATTRIBUTE_NODE) {
9558 n++;
9559 if (n == indx)
9560 addNode(list, cur);
9561 }
9562 } else if (axis == AXIS_NAMESPACE) {
9563 if (cur->type == XML_NAMESPACE_DECL) {
9564 n++;
9565 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009566 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9567 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009568 }
9569 } else {
9570 if (cur->type == XML_ELEMENT_NODE) {
9571 if (prefix == NULL) {
9572 n++;
9573 if (n == indx)
9574 addNode(list, cur);
9575 } else if ((cur->ns != NULL) &&
9576 (xmlStrEqual(URI, cur->ns->href))) {
9577 n++;
9578 if (n == indx)
9579 addNode(list, cur);
9580 }
9581 }
9582 }
9583 break;
9584 case NODE_TEST_NS:{
9585 TODO;
9586 break;
9587 }
9588 case NODE_TEST_NAME:
9589 switch (cur->type) {
9590 case XML_ELEMENT_NODE:
9591 if (xmlStrEqual(name, cur->name)) {
9592 if (prefix == NULL) {
9593 if (cur->ns == NULL) {
9594 n++;
9595 if (n == indx)
9596 addNode(list, cur);
9597 }
9598 } else {
9599 if ((cur->ns != NULL) &&
9600 (xmlStrEqual(URI,
9601 cur->ns->href))) {
9602 n++;
9603 if (n == indx)
9604 addNode(list, cur);
9605 }
9606 }
9607 }
9608 break;
9609 case XML_ATTRIBUTE_NODE:{
9610 xmlAttrPtr attr = (xmlAttrPtr) cur;
9611
9612 if (xmlStrEqual(name, attr->name)) {
9613 if (prefix == NULL) {
9614 if ((attr->ns == NULL) ||
9615 (attr->ns->prefix == NULL)) {
9616 n++;
9617 if (n == indx)
9618 addNode(list, cur);
9619 }
9620 } else {
9621 if ((attr->ns != NULL) &&
9622 (xmlStrEqual(URI,
9623 attr->ns->
9624 href))) {
9625 n++;
9626 if (n == indx)
9627 addNode(list, cur);
9628 }
9629 }
9630 }
9631 break;
9632 }
9633 case XML_NAMESPACE_DECL:
9634 if (cur->type == XML_NAMESPACE_DECL) {
9635 xmlNsPtr ns = (xmlNsPtr) cur;
9636
9637 if ((ns->prefix != NULL) && (name != NULL)
9638 && (xmlStrEqual(ns->prefix, name))) {
9639 n++;
9640 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009641 xmlXPathNodeSetAddNs(list,
9642 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009643 }
9644 }
9645 break;
9646 default:
9647 break;
9648 }
9649 break;
9650 break;
9651 }
9652 } while (n < indx);
9653 }
9654 ctxt->context->node = tmp;
9655#ifdef DEBUG_STEP_NTH
9656 xmlGenericError(xmlGenericErrorContext,
9657 "\nExamined %d nodes, found %d nodes at that step\n",
9658 t, list->nodeNr);
9659#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009660 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009661 if ((obj->boolval) && (obj->user != NULL)) {
9662 ctxt->value->boolval = 1;
9663 ctxt->value->user = obj->user;
9664 obj->user = NULL;
9665 obj->boolval = 0;
9666 }
9667 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009668 return(t);
9669}
9670
9671/**
9672 * xmlXPathCompOpEvalFirst:
9673 * @ctxt: the XPath parser context with the compiled expression
9674 * @op: an XPath compiled operation
9675 * @first: the first elem found so far
9676 *
9677 * Evaluate the Precompiled XPath operation searching only the first
9678 * element in document order
9679 *
9680 * Returns the number of examined objects.
9681 */
9682static int
9683xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9684 xmlXPathStepOpPtr op, xmlNodePtr * first)
9685{
9686 int total = 0, cur;
9687 xmlXPathCompExprPtr comp;
9688 xmlXPathObjectPtr arg1, arg2;
9689
Daniel Veillard556c6682001-10-06 09:59:51 +00009690 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009691 comp = ctxt->comp;
9692 switch (op->op) {
9693 case XPATH_OP_END:
9694 return (0);
9695 case XPATH_OP_UNION:
9696 total =
9697 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9698 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009699 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009700 if ((ctxt->value != NULL)
9701 && (ctxt->value->type == XPATH_NODESET)
9702 && (ctxt->value->nodesetval != NULL)
9703 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9704 /*
9705 * limit tree traversing to first node in the result
9706 */
9707 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9708 *first = ctxt->value->nodesetval->nodeTab[0];
9709 }
9710 cur =
9711 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9712 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009713 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009714 CHECK_TYPE0(XPATH_NODESET);
9715 arg2 = valuePop(ctxt);
9716
9717 CHECK_TYPE0(XPATH_NODESET);
9718 arg1 = valuePop(ctxt);
9719
9720 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9721 arg2->nodesetval);
9722 valuePush(ctxt, arg1);
9723 xmlXPathFreeObject(arg2);
9724 /* optimizer */
9725 if (total > cur)
9726 xmlXPathCompSwap(op);
9727 return (total + cur);
9728 case XPATH_OP_ROOT:
9729 xmlXPathRoot(ctxt);
9730 return (0);
9731 case XPATH_OP_NODE:
9732 if (op->ch1 != -1)
9733 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009734 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009735 if (op->ch2 != -1)
9736 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009737 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009738 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9739 return (total);
9740 case XPATH_OP_RESET:
9741 if (op->ch1 != -1)
9742 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009743 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009744 if (op->ch2 != -1)
9745 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009746 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009747 ctxt->context->node = NULL;
9748 return (total);
9749 case XPATH_OP_COLLECT:{
9750 if (op->ch1 == -1)
9751 return (total);
9752
9753 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009754 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009755
9756 /*
9757 * Optimization for [n] selection where n is a number
9758 */
9759 if ((op->ch2 != -1) &&
9760 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9761 (comp->steps[op->ch2].ch1 == -1) &&
9762 (comp->steps[op->ch2].ch2 != -1) &&
9763 (comp->steps[comp->steps[op->ch2].ch2].op ==
9764 XPATH_OP_VALUE)) {
9765 xmlXPathObjectPtr val;
9766
9767 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9768 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9769 int indx = (int) val->floatval;
9770
9771 if (val->floatval == (float) indx) {
9772 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9773 first, NULL);
9774 return (total);
9775 }
9776 }
9777 }
9778 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9779 return (total);
9780 }
9781 case XPATH_OP_VALUE:
9782 valuePush(ctxt,
9783 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9784 return (0);
9785 case XPATH_OP_SORT:
9786 if (op->ch1 != -1)
9787 total +=
9788 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9789 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009790 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009791 if ((ctxt->value != NULL)
9792 && (ctxt->value->type == XPATH_NODESET)
9793 && (ctxt->value->nodesetval != NULL))
9794 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9795 return (total);
9796 default:
9797 return (xmlXPathCompOpEval(ctxt, op));
9798 }
9799}
9800
9801/**
9802 * xmlXPathCompOpEvalLast:
9803 * @ctxt: the XPath parser context with the compiled expression
9804 * @op: an XPath compiled operation
9805 * @last: the last elem found so far
9806 *
9807 * Evaluate the Precompiled XPath operation searching only the last
9808 * element in document order
9809 *
9810 * Returns the number of node traversed
9811 */
9812static int
9813xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9814 xmlNodePtr * last)
9815{
9816 int total = 0, cur;
9817 xmlXPathCompExprPtr comp;
9818 xmlXPathObjectPtr arg1, arg2;
9819
Daniel Veillard556c6682001-10-06 09:59:51 +00009820 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009821 comp = ctxt->comp;
9822 switch (op->op) {
9823 case XPATH_OP_END:
9824 return (0);
9825 case XPATH_OP_UNION:
9826 total =
9827 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009828 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009829 if ((ctxt->value != NULL)
9830 && (ctxt->value->type == XPATH_NODESET)
9831 && (ctxt->value->nodesetval != NULL)
9832 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9833 /*
9834 * limit tree traversing to first node in the result
9835 */
9836 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9837 *last =
9838 ctxt->value->nodesetval->nodeTab[ctxt->value->
9839 nodesetval->nodeNr -
9840 1];
9841 }
9842 cur =
9843 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009844 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009845 if ((ctxt->value != NULL)
9846 && (ctxt->value->type == XPATH_NODESET)
9847 && (ctxt->value->nodesetval != NULL)
9848 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9849 }
9850 CHECK_TYPE0(XPATH_NODESET);
9851 arg2 = valuePop(ctxt);
9852
9853 CHECK_TYPE0(XPATH_NODESET);
9854 arg1 = valuePop(ctxt);
9855
9856 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9857 arg2->nodesetval);
9858 valuePush(ctxt, arg1);
9859 xmlXPathFreeObject(arg2);
9860 /* optimizer */
9861 if (total > cur)
9862 xmlXPathCompSwap(op);
9863 return (total + cur);
9864 case XPATH_OP_ROOT:
9865 xmlXPathRoot(ctxt);
9866 return (0);
9867 case XPATH_OP_NODE:
9868 if (op->ch1 != -1)
9869 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009870 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009871 if (op->ch2 != -1)
9872 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009873 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009874 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9875 return (total);
9876 case XPATH_OP_RESET:
9877 if (op->ch1 != -1)
9878 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009879 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009880 if (op->ch2 != -1)
9881 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009882 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009883 ctxt->context->node = NULL;
9884 return (total);
9885 case XPATH_OP_COLLECT:{
9886 if (op->ch1 == -1)
9887 return (0);
9888
9889 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009890 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009891
9892 /*
9893 * Optimization for [n] selection where n is a number
9894 */
9895 if ((op->ch2 != -1) &&
9896 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9897 (comp->steps[op->ch2].ch1 == -1) &&
9898 (comp->steps[op->ch2].ch2 != -1) &&
9899 (comp->steps[comp->steps[op->ch2].ch2].op ==
9900 XPATH_OP_VALUE)) {
9901 xmlXPathObjectPtr val;
9902
9903 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9904 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9905 int indx = (int) val->floatval;
9906
9907 if (val->floatval == (float) indx) {
9908 total +=
9909 xmlXPathNodeCollectAndTestNth(ctxt, op,
9910 indx, NULL,
9911 last);
9912 return (total);
9913 }
9914 }
9915 }
9916 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9917 return (total);
9918 }
9919 case XPATH_OP_VALUE:
9920 valuePush(ctxt,
9921 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9922 return (0);
9923 case XPATH_OP_SORT:
9924 if (op->ch1 != -1)
9925 total +=
9926 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9927 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009928 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009929 if ((ctxt->value != NULL)
9930 && (ctxt->value->type == XPATH_NODESET)
9931 && (ctxt->value->nodesetval != NULL))
9932 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9933 return (total);
9934 default:
9935 return (xmlXPathCompOpEval(ctxt, op));
9936 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009937}
9938
Owen Taylor3473f882001-02-23 17:55:21 +00009939/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009940 * xmlXPathCompOpEval:
9941 * @ctxt: the XPath parser context with the compiled expression
9942 * @op: an XPath compiled operation
9943 *
9944 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009945 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009946 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009947static int
9948xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9949{
9950 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009951 int equal, ret;
9952 xmlXPathCompExprPtr comp;
9953 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009954 xmlNodePtr bak;
9955 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009956 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009957 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009958
Daniel Veillard556c6682001-10-06 09:59:51 +00009959 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009960 comp = ctxt->comp;
9961 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009962 case XPATH_OP_END:
9963 return (0);
9964 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009965 bakd = ctxt->context->doc;
9966 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009967 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009968 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009969 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009970 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009971 xmlXPathBooleanFunction(ctxt, 1);
9972 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9973 return (total);
9974 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009975 ctxt->context->doc = bakd;
9976 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009977 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009978 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009979 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009980 if (ctxt->error) {
9981 xmlXPathFreeObject(arg2);
9982 return(0);
9983 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009984 xmlXPathBooleanFunction(ctxt, 1);
9985 arg1 = valuePop(ctxt);
9986 arg1->boolval &= arg2->boolval;
9987 valuePush(ctxt, arg1);
9988 xmlXPathFreeObject(arg2);
9989 return (total);
9990 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009991 bakd = ctxt->context->doc;
9992 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009993 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009994 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009995 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009996 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009997 xmlXPathBooleanFunction(ctxt, 1);
9998 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9999 return (total);
10000 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010001 ctxt->context->doc = bakd;
10002 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010003 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010004 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010005 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010006 if (ctxt->error) {
10007 xmlXPathFreeObject(arg2);
10008 return(0);
10009 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010010 xmlXPathBooleanFunction(ctxt, 1);
10011 arg1 = valuePop(ctxt);
10012 arg1->boolval |= arg2->boolval;
10013 valuePush(ctxt, arg1);
10014 xmlXPathFreeObject(arg2);
10015 return (total);
10016 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010017 bakd = ctxt->context->doc;
10018 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010019 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010020 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010021 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010022 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010023 ctxt->context->doc = bakd;
10024 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010025 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010026 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010027 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010028 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010029 if (op->value)
10030 equal = xmlXPathEqualValues(ctxt);
10031 else
10032 equal = xmlXPathNotEqualValues(ctxt);
10033 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010034 return (total);
10035 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010036 bakd = ctxt->context->doc;
10037 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010038 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010039 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010040 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010041 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010042 ctxt->context->doc = bakd;
10043 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010044 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010045 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010046 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010047 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010048 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10049 valuePush(ctxt, xmlXPathNewBoolean(ret));
10050 return (total);
10051 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010052 bakd = ctxt->context->doc;
10053 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010054 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010055 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010057 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010058 if (op->ch2 != -1) {
10059 ctxt->context->doc = bakd;
10060 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010061 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010062 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010063 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010064 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010065 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010066 if (op->value == 0)
10067 xmlXPathSubValues(ctxt);
10068 else if (op->value == 1)
10069 xmlXPathAddValues(ctxt);
10070 else if (op->value == 2)
10071 xmlXPathValueFlipSign(ctxt);
10072 else if (op->value == 3) {
10073 CAST_TO_NUMBER;
10074 CHECK_TYPE0(XPATH_NUMBER);
10075 }
10076 return (total);
10077 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010078 bakd = ctxt->context->doc;
10079 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010080 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010081 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010082 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010083 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010084 ctxt->context->doc = bakd;
10085 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010086 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010087 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010088 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010089 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010090 if (op->value == 0)
10091 xmlXPathMultValues(ctxt);
10092 else if (op->value == 1)
10093 xmlXPathDivValues(ctxt);
10094 else if (op->value == 2)
10095 xmlXPathModValues(ctxt);
10096 return (total);
10097 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010098 bakd = ctxt->context->doc;
10099 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010100 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010101 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010102 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010103 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010104 ctxt->context->doc = bakd;
10105 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010106 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010107 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010108 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010109 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010110 CHECK_TYPE0(XPATH_NODESET);
10111 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010112
Daniel Veillardf06307e2001-07-03 10:35:50 +000010113 CHECK_TYPE0(XPATH_NODESET);
10114 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010115
Daniel Veillardf06307e2001-07-03 10:35:50 +000010116 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10117 arg2->nodesetval);
10118 valuePush(ctxt, arg1);
10119 xmlXPathFreeObject(arg2);
10120 return (total);
10121 case XPATH_OP_ROOT:
10122 xmlXPathRoot(ctxt);
10123 return (total);
10124 case XPATH_OP_NODE:
10125 if (op->ch1 != -1)
10126 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010127 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010128 if (op->ch2 != -1)
10129 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010130 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010131 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10132 return (total);
10133 case XPATH_OP_RESET:
10134 if (op->ch1 != -1)
10135 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010136 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010137 if (op->ch2 != -1)
10138 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010139 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010140 ctxt->context->node = NULL;
10141 return (total);
10142 case XPATH_OP_COLLECT:{
10143 if (op->ch1 == -1)
10144 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010145
Daniel Veillardf06307e2001-07-03 10:35:50 +000010146 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010147 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010148
Daniel Veillardf06307e2001-07-03 10:35:50 +000010149 /*
10150 * Optimization for [n] selection where n is a number
10151 */
10152 if ((op->ch2 != -1) &&
10153 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10154 (comp->steps[op->ch2].ch1 == -1) &&
10155 (comp->steps[op->ch2].ch2 != -1) &&
10156 (comp->steps[comp->steps[op->ch2].ch2].op ==
10157 XPATH_OP_VALUE)) {
10158 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010159
Daniel Veillardf06307e2001-07-03 10:35:50 +000010160 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10161 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10162 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010163
Daniel Veillardf06307e2001-07-03 10:35:50 +000010164 if (val->floatval == (float) indx) {
10165 total +=
10166 xmlXPathNodeCollectAndTestNth(ctxt, op,
10167 indx, NULL,
10168 NULL);
10169 return (total);
10170 }
10171 }
10172 }
10173 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10174 return (total);
10175 }
10176 case XPATH_OP_VALUE:
10177 valuePush(ctxt,
10178 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10179 return (total);
10180 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010181 xmlXPathObjectPtr val;
10182
Daniel Veillardf06307e2001-07-03 10:35:50 +000010183 if (op->ch1 != -1)
10184 total +=
10185 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010186 if (op->value5 == NULL) {
10187 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10188 if (val == NULL) {
10189 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10190 return(0);
10191 }
10192 valuePush(ctxt, val);
10193 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010194 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010195
Daniel Veillardf06307e2001-07-03 10:35:50 +000010196 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10197 if (URI == NULL) {
10198 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010199 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010200 op->value4, op->value5);
10201 return (total);
10202 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010203 val = xmlXPathVariableLookupNS(ctxt->context,
10204 op->value4, URI);
10205 if (val == NULL) {
10206 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10207 return(0);
10208 }
10209 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010210 }
10211 return (total);
10212 }
10213 case XPATH_OP_FUNCTION:{
10214 xmlXPathFunction func;
10215 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010216 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010217
10218 if (op->ch1 != -1)
10219 total +=
10220 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010221 if (ctxt->valueNr < op->value) {
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 }
10227 for (i = 0; i < op->value; i++)
10228 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10229 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010230 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010231 ctxt->error = XPATH_INVALID_OPERAND;
10232 return (total);
10233 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010234 if (op->cache != NULL)
10235 func = (xmlXPathFunction) op->cache;
10236 else {
10237 const xmlChar *URI = NULL;
10238
10239 if (op->value5 == NULL)
10240 func =
10241 xmlXPathFunctionLookup(ctxt->context,
10242 op->value4);
10243 else {
10244 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10245 if (URI == NULL) {
10246 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010247 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010248 op->value4, op->value5);
10249 return (total);
10250 }
10251 func = xmlXPathFunctionLookupNS(ctxt->context,
10252 op->value4, URI);
10253 }
10254 if (func == NULL) {
10255 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010256 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010257 op->value4);
10258 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010259 }
10260 op->cache = (void *) func;
10261 op->cacheURI = (void *) URI;
10262 }
10263 oldFunc = ctxt->context->function;
10264 oldFuncURI = ctxt->context->functionURI;
10265 ctxt->context->function = op->value4;
10266 ctxt->context->functionURI = op->cacheURI;
10267 func(ctxt, op->value);
10268 ctxt->context->function = oldFunc;
10269 ctxt->context->functionURI = oldFuncURI;
10270 return (total);
10271 }
10272 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010273 bakd = ctxt->context->doc;
10274 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010275 if (op->ch1 != -1)
10276 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010277 ctxt->context->doc = bakd;
10278 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010279 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010280 if (op->ch2 != -1)
10281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010282 ctxt->context->doc = bakd;
10283 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010284 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010285 return (total);
10286 case XPATH_OP_PREDICATE:
10287 case XPATH_OP_FILTER:{
10288 xmlXPathObjectPtr res;
10289 xmlXPathObjectPtr obj, tmp;
10290 xmlNodeSetPtr newset = NULL;
10291 xmlNodeSetPtr oldset;
10292 xmlNodePtr oldnode;
10293 int i;
10294
10295 /*
10296 * Optimization for ()[1] selection i.e. the first elem
10297 */
10298 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10299 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10300 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10301 xmlXPathObjectPtr val;
10302
10303 val = comp->steps[op->ch2].value4;
10304 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10305 (val->floatval == 1.0)) {
10306 xmlNodePtr first = NULL;
10307
10308 total +=
10309 xmlXPathCompOpEvalFirst(ctxt,
10310 &comp->steps[op->ch1],
10311 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010312 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010313 /*
10314 * The nodeset should be in document order,
10315 * Keep only the first value
10316 */
10317 if ((ctxt->value != NULL) &&
10318 (ctxt->value->type == XPATH_NODESET) &&
10319 (ctxt->value->nodesetval != NULL) &&
10320 (ctxt->value->nodesetval->nodeNr > 1))
10321 ctxt->value->nodesetval->nodeNr = 1;
10322 return (total);
10323 }
10324 }
10325 /*
10326 * Optimization for ()[last()] selection i.e. the last elem
10327 */
10328 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10329 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10330 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10331 int f = comp->steps[op->ch2].ch1;
10332
10333 if ((f != -1) &&
10334 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10335 (comp->steps[f].value5 == NULL) &&
10336 (comp->steps[f].value == 0) &&
10337 (comp->steps[f].value4 != NULL) &&
10338 (xmlStrEqual
10339 (comp->steps[f].value4, BAD_CAST "last"))) {
10340 xmlNodePtr last = NULL;
10341
10342 total +=
10343 xmlXPathCompOpEvalLast(ctxt,
10344 &comp->steps[op->ch1],
10345 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010346 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010347 /*
10348 * The nodeset should be in document order,
10349 * Keep only the last value
10350 */
10351 if ((ctxt->value != NULL) &&
10352 (ctxt->value->type == XPATH_NODESET) &&
10353 (ctxt->value->nodesetval != NULL) &&
10354 (ctxt->value->nodesetval->nodeTab != NULL) &&
10355 (ctxt->value->nodesetval->nodeNr > 1)) {
10356 ctxt->value->nodesetval->nodeTab[0] =
10357 ctxt->value->nodesetval->nodeTab[ctxt->
10358 value->
10359 nodesetval->
10360 nodeNr -
10361 1];
10362 ctxt->value->nodesetval->nodeNr = 1;
10363 }
10364 return (total);
10365 }
10366 }
10367
10368 if (op->ch1 != -1)
10369 total +=
10370 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010371 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010372 if (op->ch2 == -1)
10373 return (total);
10374 if (ctxt->value == NULL)
10375 return (total);
10376
10377 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010378
10379#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010380 /*
10381 * Hum are we filtering the result of an XPointer expression
10382 */
10383 if (ctxt->value->type == XPATH_LOCATIONSET) {
10384 xmlLocationSetPtr newlocset = NULL;
10385 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010386
Daniel Veillardf06307e2001-07-03 10:35:50 +000010387 /*
10388 * Extract the old locset, and then evaluate the result of the
10389 * expression for all the element in the locset. use it to grow
10390 * up a new locset.
10391 */
10392 CHECK_TYPE0(XPATH_LOCATIONSET);
10393 obj = valuePop(ctxt);
10394 oldlocset = obj->user;
10395 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010396
Daniel Veillardf06307e2001-07-03 10:35:50 +000010397 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10398 ctxt->context->contextSize = 0;
10399 ctxt->context->proximityPosition = 0;
10400 if (op->ch2 != -1)
10401 total +=
10402 xmlXPathCompOpEval(ctxt,
10403 &comp->steps[op->ch2]);
10404 res = valuePop(ctxt);
10405 if (res != NULL)
10406 xmlXPathFreeObject(res);
10407 valuePush(ctxt, obj);
10408 CHECK_ERROR0;
10409 return (total);
10410 }
10411 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010412
Daniel Veillardf06307e2001-07-03 10:35:50 +000010413 for (i = 0; i < oldlocset->locNr; i++) {
10414 /*
10415 * Run the evaluation with a node list made of a
10416 * single item in the nodelocset.
10417 */
10418 ctxt->context->node = oldlocset->locTab[i]->user;
10419 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10420 valuePush(ctxt, tmp);
10421 ctxt->context->contextSize = oldlocset->locNr;
10422 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010423
Daniel Veillardf06307e2001-07-03 10:35:50 +000010424 if (op->ch2 != -1)
10425 total +=
10426 xmlXPathCompOpEval(ctxt,
10427 &comp->steps[op->ch2]);
10428 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010429
Daniel Veillardf06307e2001-07-03 10:35:50 +000010430 /*
10431 * The result of the evaluation need to be tested to
10432 * decided whether the filter succeeded or not
10433 */
10434 res = valuePop(ctxt);
10435 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10436 xmlXPtrLocationSetAdd(newlocset,
10437 xmlXPathObjectCopy
10438 (oldlocset->locTab[i]));
10439 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010440
Daniel Veillardf06307e2001-07-03 10:35:50 +000010441 /*
10442 * Cleanup
10443 */
10444 if (res != NULL)
10445 xmlXPathFreeObject(res);
10446 if (ctxt->value == tmp) {
10447 res = valuePop(ctxt);
10448 xmlXPathFreeObject(res);
10449 }
10450
10451 ctxt->context->node = NULL;
10452 }
10453
10454 /*
10455 * The result is used as the new evaluation locset.
10456 */
10457 xmlXPathFreeObject(obj);
10458 ctxt->context->node = NULL;
10459 ctxt->context->contextSize = -1;
10460 ctxt->context->proximityPosition = -1;
10461 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10462 ctxt->context->node = oldnode;
10463 return (total);
10464 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010465#endif /* LIBXML_XPTR_ENABLED */
10466
Daniel Veillardf06307e2001-07-03 10:35:50 +000010467 /*
10468 * Extract the old set, and then evaluate the result of the
10469 * expression for all the element in the set. use it to grow
10470 * up a new set.
10471 */
10472 CHECK_TYPE0(XPATH_NODESET);
10473 obj = valuePop(ctxt);
10474 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010475
Daniel Veillardf06307e2001-07-03 10:35:50 +000010476 oldnode = ctxt->context->node;
10477 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010478
Daniel Veillardf06307e2001-07-03 10:35:50 +000010479 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10480 ctxt->context->contextSize = 0;
10481 ctxt->context->proximityPosition = 0;
10482 if (op->ch2 != -1)
10483 total +=
10484 xmlXPathCompOpEval(ctxt,
10485 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010486 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010487 res = valuePop(ctxt);
10488 if (res != NULL)
10489 xmlXPathFreeObject(res);
10490 valuePush(ctxt, obj);
10491 ctxt->context->node = oldnode;
10492 CHECK_ERROR0;
10493 } else {
10494 /*
10495 * Initialize the new set.
10496 */
10497 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010498
Daniel Veillardf06307e2001-07-03 10:35:50 +000010499 for (i = 0; i < oldset->nodeNr; i++) {
10500 /*
10501 * Run the evaluation with a node list made of
10502 * a single item in the nodeset.
10503 */
10504 ctxt->context->node = oldset->nodeTab[i];
10505 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10506 valuePush(ctxt, tmp);
10507 ctxt->context->contextSize = oldset->nodeNr;
10508 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010509
Daniel Veillardf06307e2001-07-03 10:35:50 +000010510 if (op->ch2 != -1)
10511 total +=
10512 xmlXPathCompOpEval(ctxt,
10513 &comp->steps[op->ch2]);
10514 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010515
Daniel Veillardf06307e2001-07-03 10:35:50 +000010516 /*
10517 * The result of the evaluation need to be tested to
10518 * decided whether the filter succeeded or not
10519 */
10520 res = valuePop(ctxt);
10521 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10522 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10523 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010524
Daniel Veillardf06307e2001-07-03 10:35:50 +000010525 /*
10526 * Cleanup
10527 */
10528 if (res != NULL)
10529 xmlXPathFreeObject(res);
10530 if (ctxt->value == tmp) {
10531 res = valuePop(ctxt);
10532 xmlXPathFreeObject(res);
10533 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010534
Daniel Veillardf06307e2001-07-03 10:35:50 +000010535 ctxt->context->node = NULL;
10536 }
10537
10538 /*
10539 * The result is used as the new evaluation set.
10540 */
10541 xmlXPathFreeObject(obj);
10542 ctxt->context->node = NULL;
10543 ctxt->context->contextSize = -1;
10544 ctxt->context->proximityPosition = -1;
10545 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10546 }
10547 ctxt->context->node = oldnode;
10548 return (total);
10549 }
10550 case XPATH_OP_SORT:
10551 if (op->ch1 != -1)
10552 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010553 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010554 if ((ctxt->value != NULL) &&
10555 (ctxt->value->type == XPATH_NODESET) &&
10556 (ctxt->value->nodesetval != NULL))
10557 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10558 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010559#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010560 case XPATH_OP_RANGETO:{
10561 xmlXPathObjectPtr range;
10562 xmlXPathObjectPtr res, obj;
10563 xmlXPathObjectPtr tmp;
10564 xmlLocationSetPtr newset = NULL;
10565 xmlNodeSetPtr oldset;
10566 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010567
Daniel Veillardf06307e2001-07-03 10:35:50 +000010568 if (op->ch1 != -1)
10569 total +=
10570 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10571 if (op->ch2 == -1)
10572 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010573
Daniel Veillardf06307e2001-07-03 10:35:50 +000010574 CHECK_TYPE0(XPATH_NODESET);
10575 obj = valuePop(ctxt);
10576 oldset = obj->nodesetval;
10577 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010578
Daniel Veillardf06307e2001-07-03 10:35:50 +000010579 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010580
Daniel Veillardf06307e2001-07-03 10:35:50 +000010581 if (oldset != NULL) {
10582 for (i = 0; i < oldset->nodeNr; i++) {
10583 /*
10584 * Run the evaluation with a node list made of a single item
10585 * in the nodeset.
10586 */
10587 ctxt->context->node = oldset->nodeTab[i];
10588 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10589 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010590
Daniel Veillardf06307e2001-07-03 10:35:50 +000010591 if (op->ch2 != -1)
10592 total +=
10593 xmlXPathCompOpEval(ctxt,
10594 &comp->steps[op->ch2]);
10595 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010596
Daniel Veillardf06307e2001-07-03 10:35:50 +000010597 /*
10598 * The result of the evaluation need to be tested to
10599 * decided whether the filter succeeded or not
10600 */
10601 res = valuePop(ctxt);
10602 range =
10603 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10604 res);
10605 if (range != NULL) {
10606 xmlXPtrLocationSetAdd(newset, range);
10607 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010608
Daniel Veillardf06307e2001-07-03 10:35:50 +000010609 /*
10610 * Cleanup
10611 */
10612 if (res != NULL)
10613 xmlXPathFreeObject(res);
10614 if (ctxt->value == tmp) {
10615 res = valuePop(ctxt);
10616 xmlXPathFreeObject(res);
10617 }
10618
10619 ctxt->context->node = NULL;
10620 }
10621 }
10622
10623 /*
10624 * The result is used as the new evaluation set.
10625 */
10626 xmlXPathFreeObject(obj);
10627 ctxt->context->node = NULL;
10628 ctxt->context->contextSize = -1;
10629 ctxt->context->proximityPosition = -1;
10630 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10631 return (total);
10632 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010633#endif /* LIBXML_XPTR_ENABLED */
10634 }
10635 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010636 "XPath: unknown precompiled operation %d\n", op->op);
10637 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010638}
10639
10640/**
10641 * xmlXPathRunEval:
10642 * @ctxt: the XPath parser context with the compiled expression
10643 *
10644 * Evaluate the Precompiled XPath expression in the given context.
10645 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010646static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010647xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10648 xmlXPathCompExprPtr comp;
10649
10650 if ((ctxt == NULL) || (ctxt->comp == NULL))
10651 return;
10652
10653 if (ctxt->valueTab == NULL) {
10654 /* Allocate the value stack */
10655 ctxt->valueTab = (xmlXPathObjectPtr *)
10656 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10657 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010658 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010659 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010660 }
10661 ctxt->valueNr = 0;
10662 ctxt->valueMax = 10;
10663 ctxt->value = NULL;
10664 }
10665 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010666 if(comp->last < 0) {
10667 xmlGenericError(xmlGenericErrorContext,
10668 "xmlXPathRunEval: last is less than zero\n");
10669 return;
10670 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010671 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10672}
10673
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010674/************************************************************************
10675 * *
10676 * Public interfaces *
10677 * *
10678 ************************************************************************/
10679
10680/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010681 * xmlXPathEvalPredicate:
10682 * @ctxt: the XPath context
10683 * @res: the Predicate Expression evaluation result
10684 *
10685 * Evaluate a predicate result for the current node.
10686 * A PredicateExpr is evaluated by evaluating the Expr and converting
10687 * the result to a boolean. If the result is a number, the result will
10688 * be converted to true if the number is equal to the position of the
10689 * context node in the context node list (as returned by the position
10690 * function) and will be converted to false otherwise; if the result
10691 * is not a number, then the result will be converted as if by a call
10692 * to the boolean function.
10693 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010694 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010695 */
10696int
10697xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10698 if (res == NULL) return(0);
10699 switch (res->type) {
10700 case XPATH_BOOLEAN:
10701 return(res->boolval);
10702 case XPATH_NUMBER:
10703 return(res->floatval == ctxt->proximityPosition);
10704 case XPATH_NODESET:
10705 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010706 if (res->nodesetval == NULL)
10707 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010708 return(res->nodesetval->nodeNr != 0);
10709 case XPATH_STRING:
10710 return((res->stringval != NULL) &&
10711 (xmlStrlen(res->stringval) != 0));
10712 default:
10713 STRANGE
10714 }
10715 return(0);
10716}
10717
10718/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010719 * xmlXPathEvaluatePredicateResult:
10720 * @ctxt: the XPath Parser context
10721 * @res: the Predicate Expression evaluation result
10722 *
10723 * Evaluate a predicate result for the current node.
10724 * A PredicateExpr is evaluated by evaluating the Expr and converting
10725 * the result to a boolean. If the result is a number, the result will
10726 * be converted to true if the number is equal to the position of the
10727 * context node in the context node list (as returned by the position
10728 * function) and will be converted to false otherwise; if the result
10729 * is not a number, then the result will be converted as if by a call
10730 * to the boolean function.
10731 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010732 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010733 */
10734int
10735xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10736 xmlXPathObjectPtr res) {
10737 if (res == NULL) return(0);
10738 switch (res->type) {
10739 case XPATH_BOOLEAN:
10740 return(res->boolval);
10741 case XPATH_NUMBER:
10742 return(res->floatval == ctxt->context->proximityPosition);
10743 case XPATH_NODESET:
10744 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010745 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010746 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010747 return(res->nodesetval->nodeNr != 0);
10748 case XPATH_STRING:
10749 return((res->stringval != NULL) &&
10750 (xmlStrlen(res->stringval) != 0));
10751 default:
10752 STRANGE
10753 }
10754 return(0);
10755}
10756
10757/**
10758 * xmlXPathCompile:
10759 * @str: the XPath expression
10760 *
10761 * Compile an XPath expression
10762 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010763 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010764 * the caller has to free the object.
10765 */
10766xmlXPathCompExprPtr
10767xmlXPathCompile(const xmlChar *str) {
10768 xmlXPathParserContextPtr ctxt;
10769 xmlXPathCompExprPtr comp;
10770
10771 xmlXPathInit();
10772
10773 ctxt = xmlXPathNewParserContext(str, NULL);
10774 xmlXPathCompileExpr(ctxt);
Daniel Veillardae9733a2003-10-28 19:02:21 +000010775
10776 if( ctxt->error != XPATH_EXPRESSION_OK )
10777 {
10778 xmlXPathFreeParserContext(ctxt);
10779 return (0);
10780 }
10781
Daniel Veillard40af6492001-04-22 08:50:55 +000010782 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010783 /*
10784 * aleksey: in some cases this line prints *second* error message
10785 * (see bug #78858) and probably this should be fixed.
10786 * However, we are not sure that all error messages are printed
10787 * out in other places. It's not critical so we leave it as-is for now
10788 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010789 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10790 comp = NULL;
10791 } else {
10792 comp = ctxt->comp;
10793 ctxt->comp = NULL;
10794 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010795 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010796 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010797 comp->expr = xmlStrdup(str);
10798#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010799 comp->string = xmlStrdup(str);
10800 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010801#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010802 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010803 return(comp);
10804}
10805
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010806/**
10807 * xmlXPathCompiledEval:
10808 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010809 * @ctx: the XPath context
10810 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010811 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010812 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010813 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010814 * the caller has to free the object.
10815 */
10816xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010817xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010818 xmlXPathParserContextPtr ctxt;
10819 xmlXPathObjectPtr res, tmp, init = NULL;
10820 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010821#ifndef LIBXML_THREAD_ENABLED
10822 static int reentance = 0;
10823#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010824
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010825 if ((comp == NULL) || (ctx == NULL))
10826 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010827 xmlXPathInit();
10828
10829 CHECK_CONTEXT(ctx)
10830
Daniel Veillard81463942001-10-16 12:34:39 +000010831#ifndef LIBXML_THREAD_ENABLED
10832 reentance++;
10833 if (reentance > 1)
10834 xmlXPathDisableOptimizer = 1;
10835#endif
10836
Daniel Veillardf06307e2001-07-03 10:35:50 +000010837#ifdef DEBUG_EVAL_COUNTS
10838 comp->nb++;
10839 if ((comp->string != NULL) && (comp->nb > 100)) {
10840 fprintf(stderr, "100 x %s\n", comp->string);
10841 comp->nb = 0;
10842 }
10843#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010844 ctxt = xmlXPathCompParserContext(comp, ctx);
10845 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010846
10847 if (ctxt->value == NULL) {
10848 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010849 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010850 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010851 } else {
10852 res = valuePop(ctxt);
10853 }
10854
Daniel Veillardf06307e2001-07-03 10:35:50 +000010855
Owen Taylor3473f882001-02-23 17:55:21 +000010856 do {
10857 tmp = valuePop(ctxt);
10858 if (tmp != NULL) {
10859 if (tmp != init)
10860 stack++;
10861 xmlXPathFreeObject(tmp);
10862 }
10863 } while (tmp != NULL);
10864 if ((stack != 0) && (res != NULL)) {
10865 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010866 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010867 stack);
10868 }
10869 if (ctxt->error != XPATH_EXPRESSION_OK) {
10870 xmlXPathFreeObject(res);
10871 res = NULL;
10872 }
10873
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010874
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010875 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010876 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010877#ifndef LIBXML_THREAD_ENABLED
10878 reentance--;
10879#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010880 return(res);
10881}
10882
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010883/**
10884 * xmlXPathEvalExpr:
10885 * @ctxt: the XPath Parser context
10886 *
10887 * Parse and evaluate an XPath expression in the given context,
10888 * then push the result on the context stack
10889 */
10890void
10891xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10892 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010893 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010894 xmlXPathRunEval(ctxt);
10895}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010896
10897/**
10898 * xmlXPathEval:
10899 * @str: the XPath expression
10900 * @ctx: the XPath context
10901 *
10902 * Evaluate the XPath Location Path in the given context.
10903 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010904 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010905 * the caller has to free the object.
10906 */
10907xmlXPathObjectPtr
10908xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10909 xmlXPathParserContextPtr ctxt;
10910 xmlXPathObjectPtr res, tmp, init = NULL;
10911 int stack = 0;
10912
10913 xmlXPathInit();
10914
10915 CHECK_CONTEXT(ctx)
10916
10917 ctxt = xmlXPathNewParserContext(str, ctx);
10918 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010919
10920 if (ctxt->value == NULL) {
10921 xmlGenericError(xmlGenericErrorContext,
10922 "xmlXPathEval: evaluation failed\n");
10923 res = NULL;
10924 } else if (*ctxt->cur != 0) {
10925 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10926 res = NULL;
10927 } else {
10928 res = valuePop(ctxt);
10929 }
10930
10931 do {
10932 tmp = valuePop(ctxt);
10933 if (tmp != NULL) {
10934 if (tmp != init)
10935 stack++;
10936 xmlXPathFreeObject(tmp);
10937 }
10938 } while (tmp != NULL);
10939 if ((stack != 0) && (res != NULL)) {
10940 xmlGenericError(xmlGenericErrorContext,
10941 "xmlXPathEval: %d object left on the stack\n",
10942 stack);
10943 }
10944 if (ctxt->error != XPATH_EXPRESSION_OK) {
10945 xmlXPathFreeObject(res);
10946 res = NULL;
10947 }
10948
Owen Taylor3473f882001-02-23 17:55:21 +000010949 xmlXPathFreeParserContext(ctxt);
10950 return(res);
10951}
10952
10953/**
10954 * xmlXPathEvalExpression:
10955 * @str: the XPath expression
10956 * @ctxt: the XPath context
10957 *
10958 * Evaluate the XPath expression in the given context.
10959 *
10960 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10961 * the caller has to free the object.
10962 */
10963xmlXPathObjectPtr
10964xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10965 xmlXPathParserContextPtr pctxt;
10966 xmlXPathObjectPtr res, tmp;
10967 int stack = 0;
10968
10969 xmlXPathInit();
10970
10971 CHECK_CONTEXT(ctxt)
10972
10973 pctxt = xmlXPathNewParserContext(str, ctxt);
10974 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010975
10976 if (*pctxt->cur != 0) {
10977 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10978 res = NULL;
10979 } else {
10980 res = valuePop(pctxt);
10981 }
10982 do {
10983 tmp = valuePop(pctxt);
10984 if (tmp != NULL) {
10985 xmlXPathFreeObject(tmp);
10986 stack++;
10987 }
10988 } while (tmp != NULL);
10989 if ((stack != 0) && (res != NULL)) {
10990 xmlGenericError(xmlGenericErrorContext,
10991 "xmlXPathEvalExpression: %d object left on the stack\n",
10992 stack);
10993 }
10994 xmlXPathFreeParserContext(pctxt);
10995 return(res);
10996}
10997
Daniel Veillard42766c02002-08-22 20:52:17 +000010998/************************************************************************
10999 * *
11000 * Extra functions not pertaining to the XPath spec *
11001 * *
11002 ************************************************************************/
11003/**
11004 * xmlXPathEscapeUriFunction:
11005 * @ctxt: the XPath Parser context
11006 * @nargs: the number of arguments
11007 *
11008 * Implement the escape-uri() XPath function
11009 * string escape-uri(string $str, bool $escape-reserved)
11010 *
11011 * This function applies the URI escaping rules defined in section 2 of [RFC
11012 * 2396] to the string supplied as $uri-part, which typically represents all
11013 * or part of a URI. The effect of the function is to replace any special
11014 * character in the string by an escape sequence of the form %xx%yy...,
11015 * where xxyy... is the hexadecimal representation of the octets used to
11016 * represent the character in UTF-8.
11017 *
11018 * The set of characters that are escaped depends on the setting of the
11019 * boolean argument $escape-reserved.
11020 *
11021 * If $escape-reserved is true, all characters are escaped other than lower
11022 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11023 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11024 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11025 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11026 * A-F).
11027 *
11028 * If $escape-reserved is false, the behavior differs in that characters
11029 * referred to in [RFC 2396] as reserved characters are not escaped. These
11030 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11031 *
11032 * [RFC 2396] does not define whether escaped URIs should use lower case or
11033 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11034 * compared using string comparison functions, this function must always use
11035 * the upper-case letters A-F.
11036 *
11037 * Generally, $escape-reserved should be set to true when escaping a string
11038 * that is to form a single part of a URI, and to false when escaping an
11039 * entire URI or URI reference.
11040 *
11041 * In the case of non-ascii characters, the string is encoded according to
11042 * utf-8 and then converted according to RFC 2396.
11043 *
11044 * Examples
11045 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11046 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11047 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11048 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11049 *
11050 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011051static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011052xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11053 xmlXPathObjectPtr str;
11054 int escape_reserved;
11055 xmlBufferPtr target;
11056 xmlChar *cptr;
11057 xmlChar escape[4];
11058
11059 CHECK_ARITY(2);
11060
11061 escape_reserved = xmlXPathPopBoolean(ctxt);
11062
11063 CAST_TO_STRING;
11064 str = valuePop(ctxt);
11065
11066 target = xmlBufferCreate();
11067
11068 escape[0] = '%';
11069 escape[3] = 0;
11070
11071 if (target) {
11072 for (cptr = str->stringval; *cptr; cptr++) {
11073 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11074 (*cptr >= 'a' && *cptr <= 'z') ||
11075 (*cptr >= '0' && *cptr <= '9') ||
11076 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11077 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11078 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11079 (*cptr == '%' &&
11080 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11081 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11082 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11083 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11084 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11085 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11086 (!escape_reserved &&
11087 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11088 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11089 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11090 *cptr == ','))) {
11091 xmlBufferAdd(target, cptr, 1);
11092 } else {
11093 if ((*cptr >> 4) < 10)
11094 escape[1] = '0' + (*cptr >> 4);
11095 else
11096 escape[1] = 'A' - 10 + (*cptr >> 4);
11097 if ((*cptr & 0xF) < 10)
11098 escape[2] = '0' + (*cptr & 0xF);
11099 else
11100 escape[2] = 'A' - 10 + (*cptr & 0xF);
11101
11102 xmlBufferAdd(target, &escape[0], 3);
11103 }
11104 }
11105 }
11106 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11107 xmlBufferFree(target);
11108 xmlXPathFreeObject(str);
11109}
11110
Owen Taylor3473f882001-02-23 17:55:21 +000011111/**
11112 * xmlXPathRegisterAllFunctions:
11113 * @ctxt: the XPath context
11114 *
11115 * Registers all default XPath functions in this context
11116 */
11117void
11118xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11119{
11120 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11121 xmlXPathBooleanFunction);
11122 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11123 xmlXPathCeilingFunction);
11124 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11125 xmlXPathCountFunction);
11126 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11127 xmlXPathConcatFunction);
11128 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11129 xmlXPathContainsFunction);
11130 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11131 xmlXPathIdFunction);
11132 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11133 xmlXPathFalseFunction);
11134 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11135 xmlXPathFloorFunction);
11136 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11137 xmlXPathLastFunction);
11138 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11139 xmlXPathLangFunction);
11140 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11141 xmlXPathLocalNameFunction);
11142 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11143 xmlXPathNotFunction);
11144 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11145 xmlXPathNameFunction);
11146 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11147 xmlXPathNamespaceURIFunction);
11148 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11149 xmlXPathNormalizeFunction);
11150 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11151 xmlXPathNumberFunction);
11152 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11153 xmlXPathPositionFunction);
11154 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11155 xmlXPathRoundFunction);
11156 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11157 xmlXPathStringFunction);
11158 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11159 xmlXPathStringLengthFunction);
11160 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11161 xmlXPathStartsWithFunction);
11162 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11163 xmlXPathSubstringFunction);
11164 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11165 xmlXPathSubstringBeforeFunction);
11166 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11167 xmlXPathSubstringAfterFunction);
11168 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11169 xmlXPathSumFunction);
11170 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11171 xmlXPathTrueFunction);
11172 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11173 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011174
11175 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11176 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11177 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011178}
11179
11180#endif /* LIBXML_XPATH_ENABLED */