blob: 627fa20be6cf8528fd5ed96e59c0683c3a88a355 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000054
Daniel Veillardd96f6d32003-10-07 21:25:12 +000055#define TODO \
56 xmlGenericError(xmlGenericErrorContext, \
57 "Unimplemented block at %s:%d\n", \
58 __FILE__, __LINE__);
59
Daniel Veillard4432df22003-09-28 18:58:27 +000060#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000061/************************************************************************
62 * *
63 * Floating point stuff *
64 * *
65 ************************************************************************/
66
Daniel Veillardc0631a62001-09-20 13:56:06 +000067#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000068#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000069#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000070#include "trionan.c"
71
Owen Taylor3473f882001-02-23 17:55:21 +000072/*
Owen Taylor3473f882001-02-23 17:55:21 +000073 * The lack of portability of this section of the libc is annoying !
74 */
75double xmlXPathNAN = 0;
76double xmlXPathPINF = 1;
77double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000078double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000079static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000080
Owen Taylor3473f882001-02-23 17:55:21 +000081/**
82 * xmlXPathInit:
83 *
84 * Initialize the XPath environment
85 */
86void
87xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000088 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000089
Bjorn Reese45029602001-08-21 09:23:53 +000090 xmlXPathPINF = trio_pinf();
91 xmlXPathNINF = trio_ninf();
92 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +000093 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +000094
Daniel Veillard20ee8c02001-10-05 09:18:14 +000095 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000096}
97
Daniel Veillardcda96922001-08-21 10:56:31 +000098/**
99 * xmlXPathIsNaN:
100 * @val: a double value
101 *
102 * Provides a portable isnan() function to detect whether a double
103 * is a NotaNumber. Based on trio code
104 * http://sourceforge.net/projects/ctrio/
105 *
106 * Returns 1 if the value is a NaN, 0 otherwise
107 */
108int
109xmlXPathIsNaN(double val) {
110 return(trio_isnan(val));
111}
112
113/**
114 * xmlXPathIsInf:
115 * @val: a double value
116 *
117 * Provides a portable isinf() function to detect whether a double
118 * is a +Infinite or -Infinite. Based on trio code
119 * http://sourceforge.net/projects/ctrio/
120 *
121 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
122 */
123int
124xmlXPathIsInf(double val) {
125 return(trio_isinf(val));
126}
127
Daniel Veillard4432df22003-09-28 18:58:27 +0000128#endif /* SCHEMAS or XPATH */
129#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000130/**
131 * xmlXPathGetSign:
132 * @val: a double value
133 *
134 * Provides a portable function to detect the sign of a double
135 * Modified from trio code
136 * http://sourceforge.net/projects/ctrio/
137 *
138 * Returns 1 if the value is Negative, 0 if positive
139 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000140static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000141xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000142 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000143}
144
145
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000146/*
147 * TODO: when compatibility allows remove all "fake node libxslt" strings
148 * the test should just be name[0] = ' '
149 */
150/* #define DEBUG */
151/* #define DEBUG_STEP */
152/* #define DEBUG_STEP_NTH */
153/* #define DEBUG_EXPR */
154/* #define DEBUG_EVAL_COUNTS */
155
156static xmlNs xmlXPathXMLNamespaceStruct = {
157 NULL,
158 XML_NAMESPACE_DECL,
159 XML_XML_NAMESPACE,
160 BAD_CAST "xml",
161 NULL
162};
163static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
164#ifndef LIBXML_THREAD_ENABLED
165/*
166 * Optimizer is disabled only when threaded apps are detected while
167 * the library ain't compiled for thread safety.
168 */
169static int xmlXPathDisableOptimizer = 0;
170#endif
171
Owen Taylor3473f882001-02-23 17:55:21 +0000172/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000173 * *
174 * Error handling routines *
175 * *
176 ************************************************************************/
177
178
179static const char *xmlXPathErrorMessages[] = {
180 "Ok\n",
181 "Number encoding\n",
182 "Unfinished literal\n",
183 "Start of literal\n",
184 "Expected $ for variable reference\n",
185 "Undefined variable\n",
186 "Invalid predicate\n",
187 "Invalid expression\n",
188 "Missing closing curly brace\n",
189 "Unregistered function\n",
190 "Invalid operand\n",
191 "Invalid type\n",
192 "Invalid number of arguments\n",
193 "Invalid context size\n",
194 "Invalid context position\n",
195 "Memory allocation error\n",
196 "Syntax error\n",
197 "Resource error\n",
198 "Sub resource error\n",
199 "Undefined namespace prefix\n",
200 "Encoding error\n",
201 "Char out of XML range\n"
202};
203
204
205/**
206 * xmlXPathErrMemory:
207 * @ctxt: an XPath context
208 * @extra: extra informations
209 *
210 * Handle a redefinition of attribute error
211 */
212static void
213xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
214{
215 if (ctxt != NULL) {
216 if (extra) {
217 xmlChar buf[200];
218
219 xmlStrPrintf(buf, 200,
220 BAD_CAST "Memory allocation failed : %s\n",
221 extra);
222 ctxt->lastError.message = (char *) xmlStrdup(buf);
223 } else {
224 ctxt->lastError.message = (char *)
225 xmlStrdup(BAD_CAST "Memory allocation failed\n");
226 }
227 ctxt->lastError.domain = XML_FROM_XPATH;
228 ctxt->lastError.code = XML_ERR_NO_MEMORY;
229 if (ctxt->error != NULL)
230 ctxt->error(ctxt->userData, &ctxt->lastError);
231 } else {
232 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000233 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000234 NULL, NULL, XML_FROM_XPATH,
235 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
236 extra, NULL, NULL, 0, 0,
237 "Memory allocation failed : %s\n", extra);
238 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000239 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000240 NULL, NULL, XML_FROM_XPATH,
241 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
242 NULL, NULL, NULL, 0, 0,
243 "Memory allocation failed\n");
244 }
245}
246
247/**
248 * xmlXPathErrMemory:
249 * @ctxt: an XPath parser context
250 * @extra: extra informations
251 *
252 * Handle a redefinition of attribute error
253 */
254static void
255xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
256{
257 ctxt->error = XPATH_MEMORY_ERROR;
258 if (ctxt == NULL)
259 xmlXPathErrMemory(NULL, extra);
260 else
261 xmlXPathErrMemory(ctxt->context, extra);
262}
263
264/**
265 * xmlXPathErr:
266 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000267 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000268 *
269 * Handle a Relax NG Parsing error
270 */
271void
272xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
273{
274 if (ctxt != NULL)
275 ctxt->error = error;
276 if ((ctxt == NULL) || (ctxt->context == NULL)) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000277 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000278 NULL, NULL, XML_FROM_XPATH,
279 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
280 XML_ERR_ERROR, NULL, 0,
281 NULL, NULL, NULL, 0, 0,
282 xmlXPathErrorMessages[error]);
283 return;
284 }
285 ctxt->context->lastError.domain = XML_FROM_XPATH;
286 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
287 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000288 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000289 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
290 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
291 ctxt->context->lastError.node = ctxt->context->debugNode;
292 if (ctxt->context->error != NULL) {
293 ctxt->context->error(ctxt->context->userData,
294 &ctxt->context->lastError);
295 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000296 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000297 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
298 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
299 XML_ERR_ERROR, NULL, 0,
300 (const char *) ctxt->base, NULL, NULL,
301 ctxt->cur - ctxt->base, 0,
302 xmlXPathErrorMessages[error]);
303 }
304
305}
306
307/**
308 * xmlXPatherror:
309 * @ctxt: the XPath Parser context
310 * @file: the file name
311 * @line: the line number
312 * @no: the error number
313 *
314 * Formats an error message.
315 */
316void
317xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
318 int line ATTRIBUTE_UNUSED, int no) {
319 xmlXPathErr(ctxt, no);
320}
321
322
323/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000324 * *
325 * Parser Types *
326 * *
327 ************************************************************************/
328
329/*
330 * Types are private:
331 */
332
333typedef enum {
334 XPATH_OP_END=0,
335 XPATH_OP_AND,
336 XPATH_OP_OR,
337 XPATH_OP_EQUAL,
338 XPATH_OP_CMP,
339 XPATH_OP_PLUS,
340 XPATH_OP_MULT,
341 XPATH_OP_UNION,
342 XPATH_OP_ROOT,
343 XPATH_OP_NODE,
344 XPATH_OP_RESET,
345 XPATH_OP_COLLECT,
346 XPATH_OP_VALUE,
347 XPATH_OP_VARIABLE,
348 XPATH_OP_FUNCTION,
349 XPATH_OP_ARG,
350 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000351 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000352 XPATH_OP_SORT
353#ifdef LIBXML_XPTR_ENABLED
354 ,XPATH_OP_RANGETO
355#endif
356} xmlXPathOp;
357
358typedef enum {
359 AXIS_ANCESTOR = 1,
360 AXIS_ANCESTOR_OR_SELF,
361 AXIS_ATTRIBUTE,
362 AXIS_CHILD,
363 AXIS_DESCENDANT,
364 AXIS_DESCENDANT_OR_SELF,
365 AXIS_FOLLOWING,
366 AXIS_FOLLOWING_SIBLING,
367 AXIS_NAMESPACE,
368 AXIS_PARENT,
369 AXIS_PRECEDING,
370 AXIS_PRECEDING_SIBLING,
371 AXIS_SELF
372} xmlXPathAxisVal;
373
374typedef enum {
375 NODE_TEST_NONE = 0,
376 NODE_TEST_TYPE = 1,
377 NODE_TEST_PI = 2,
378 NODE_TEST_ALL = 3,
379 NODE_TEST_NS = 4,
380 NODE_TEST_NAME = 5
381} xmlXPathTestVal;
382
383typedef enum {
384 NODE_TYPE_NODE = 0,
385 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
386 NODE_TYPE_TEXT = XML_TEXT_NODE,
387 NODE_TYPE_PI = XML_PI_NODE
388} xmlXPathTypeVal;
389
390
391typedef struct _xmlXPathStepOp xmlXPathStepOp;
392typedef xmlXPathStepOp *xmlXPathStepOpPtr;
393struct _xmlXPathStepOp {
394 xmlXPathOp op;
395 int ch1;
396 int ch2;
397 int value;
398 int value2;
399 int value3;
400 void *value4;
401 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000402 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000403 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000404};
405
406struct _xmlXPathCompExpr {
407 int nbStep;
408 int maxStep;
409 xmlXPathStepOp *steps; /* ops for computation */
410 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000411 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000412#ifdef DEBUG_EVAL_COUNTS
413 int nb;
414 xmlChar *string;
415#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000416};
417
418/************************************************************************
419 * *
420 * Parser Type functions *
421 * *
422 ************************************************************************/
423
424/**
425 * xmlXPathNewCompExpr:
426 *
427 * Create a new Xpath component
428 *
429 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
430 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000431static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000432xmlXPathNewCompExpr(void) {
433 xmlXPathCompExprPtr cur;
434
435 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
436 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000437 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000438 return(NULL);
439 }
440 memset(cur, 0, sizeof(xmlXPathCompExpr));
441 cur->maxStep = 10;
442 cur->nbStep = 0;
443 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
444 sizeof(xmlXPathStepOp));
445 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000446 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000447 xmlFree(cur);
448 return(NULL);
449 }
450 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
451 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000452#ifdef DEBUG_EVAL_COUNTS
453 cur->nb = 0;
454#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000455 return(cur);
456}
457
458/**
459 * xmlXPathFreeCompExpr:
460 * @comp: an XPATH comp
461 *
462 * Free up the memory allocated by @comp
463 */
464void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000465xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
466{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000467 xmlXPathStepOpPtr op;
468 int i;
469
470 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000471 return;
472 for (i = 0; i < comp->nbStep; i++) {
473 op = &comp->steps[i];
474 if (op->value4 != NULL) {
475 if (op->op == XPATH_OP_VALUE)
476 xmlXPathFreeObject(op->value4);
477 else
478 xmlFree(op->value4);
479 }
480 if (op->value5 != NULL)
481 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000482 }
483 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000484 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000485 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000486#ifdef DEBUG_EVAL_COUNTS
487 if (comp->string != NULL) {
488 xmlFree(comp->string);
489 }
490#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000491 if (comp->expr != NULL) {
492 xmlFree(comp->expr);
493 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000494
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000495 xmlFree(comp);
496}
497
498/**
499 * xmlXPathCompExprAdd:
500 * @comp: the compiled expression
501 * @ch1: first child index
502 * @ch2: second child index
503 * @op: an op
504 * @value: the first int value
505 * @value2: the second int value
506 * @value3: the third int value
507 * @value4: the first string value
508 * @value5: the second string value
509 *
510 * Add an step to an XPath Compiled Expression
511 *
512 * Returns -1 in case of failure, the index otherwise
513 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000514static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000515xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
516 xmlXPathOp op, int value,
517 int value2, int value3, void *value4, void *value5) {
518 if (comp->nbStep >= comp->maxStep) {
519 xmlXPathStepOp *real;
520
521 comp->maxStep *= 2;
522 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
523 comp->maxStep * sizeof(xmlXPathStepOp));
524 if (real == NULL) {
525 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000526 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000527 return(-1);
528 }
529 comp->steps = real;
530 }
531 comp->last = comp->nbStep;
532 comp->steps[comp->nbStep].ch1 = ch1;
533 comp->steps[comp->nbStep].ch2 = ch2;
534 comp->steps[comp->nbStep].op = op;
535 comp->steps[comp->nbStep].value = value;
536 comp->steps[comp->nbStep].value2 = value2;
537 comp->steps[comp->nbStep].value3 = value3;
538 comp->steps[comp->nbStep].value4 = value4;
539 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000540 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000541 return(comp->nbStep++);
542}
543
Daniel Veillardf06307e2001-07-03 10:35:50 +0000544/**
545 * xmlXPathCompSwap:
546 * @comp: the compiled expression
547 * @op: operation index
548 *
549 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000550 */
551static void
552xmlXPathCompSwap(xmlXPathStepOpPtr op) {
553 int tmp;
554
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000555#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000556 /*
557 * Since this manipulates possibly shared variables, this is
558 * disable if one detects that the library is used in a multithreaded
559 * application
560 */
561 if (xmlXPathDisableOptimizer)
562 return;
563#endif
564
Daniel Veillardf06307e2001-07-03 10:35:50 +0000565 tmp = op->ch1;
566 op->ch1 = op->ch2;
567 op->ch2 = tmp;
568}
569
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000570#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
571 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
572 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000573#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
574 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
575 (op), (val), (val2), (val3), (val4), (val5))
576
577#define PUSH_LEAVE_EXPR(op, val, val2) \
578xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
579
580#define PUSH_UNARY_EXPR(op, ch, val, val2) \
581xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
582
583#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
584xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
585
586/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000587 * *
588 * Debugging related functions *
589 * *
590 ************************************************************************/
591
Owen Taylor3473f882001-02-23 17:55:21 +0000592#define STRANGE \
593 xmlGenericError(xmlGenericErrorContext, \
594 "Internal error at %s:%d\n", \
595 __FILE__, __LINE__);
596
597#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000598static void
599xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000600 int i;
601 char shift[100];
602
603 for (i = 0;((i < depth) && (i < 25));i++)
604 shift[2 * i] = shift[2 * i + 1] = ' ';
605 shift[2 * i] = shift[2 * i + 1] = 0;
606 if (cur == NULL) {
607 fprintf(output, shift);
608 fprintf(output, "Node is NULL !\n");
609 return;
610
611 }
612
613 if ((cur->type == XML_DOCUMENT_NODE) ||
614 (cur->type == XML_HTML_DOCUMENT_NODE)) {
615 fprintf(output, shift);
616 fprintf(output, " /\n");
617 } else if (cur->type == XML_ATTRIBUTE_NODE)
618 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
619 else
620 xmlDebugDumpOneNode(output, cur, depth);
621}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000622static void
623xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000624 xmlNodePtr tmp;
625 int i;
626 char shift[100];
627
628 for (i = 0;((i < depth) && (i < 25));i++)
629 shift[2 * i] = shift[2 * i + 1] = ' ';
630 shift[2 * i] = shift[2 * i + 1] = 0;
631 if (cur == NULL) {
632 fprintf(output, shift);
633 fprintf(output, "Node is NULL !\n");
634 return;
635
636 }
637
638 while (cur != NULL) {
639 tmp = cur;
640 cur = cur->next;
641 xmlDebugDumpOneNode(output, tmp, depth);
642 }
643}
Owen Taylor3473f882001-02-23 17:55:21 +0000644
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000645static void
646xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000647 int i;
648 char shift[100];
649
650 for (i = 0;((i < depth) && (i < 25));i++)
651 shift[2 * i] = shift[2 * i + 1] = ' ';
652 shift[2 * i] = shift[2 * i + 1] = 0;
653
654 if (cur == NULL) {
655 fprintf(output, shift);
656 fprintf(output, "NodeSet is NULL !\n");
657 return;
658
659 }
660
Daniel Veillard911f49a2001-04-07 15:39:35 +0000661 if (cur != NULL) {
662 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
663 for (i = 0;i < cur->nodeNr;i++) {
664 fprintf(output, shift);
665 fprintf(output, "%d", i + 1);
666 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
667 }
Owen Taylor3473f882001-02-23 17:55:21 +0000668 }
669}
670
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000671static void
672xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000673 int i;
674 char shift[100];
675
676 for (i = 0;((i < depth) && (i < 25));i++)
677 shift[2 * i] = shift[2 * i + 1] = ' ';
678 shift[2 * i] = shift[2 * i + 1] = 0;
679
680 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
681 fprintf(output, shift);
682 fprintf(output, "Value Tree is NULL !\n");
683 return;
684
685 }
686
687 fprintf(output, shift);
688 fprintf(output, "%d", i + 1);
689 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
690}
Owen Taylor3473f882001-02-23 17:55:21 +0000691#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000692static void
693xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000694 int i;
695 char shift[100];
696
697 for (i = 0;((i < depth) && (i < 25));i++)
698 shift[2 * i] = shift[2 * i + 1] = ' ';
699 shift[2 * i] = shift[2 * i + 1] = 0;
700
701 if (cur == NULL) {
702 fprintf(output, shift);
703 fprintf(output, "LocationSet is NULL !\n");
704 return;
705
706 }
707
708 for (i = 0;i < cur->locNr;i++) {
709 fprintf(output, shift);
710 fprintf(output, "%d : ", i + 1);
711 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
712 }
713}
Daniel Veillard017b1082001-06-21 11:20:21 +0000714#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000715
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000716/**
717 * xmlXPathDebugDumpObject:
718 * @output: the FILE * to dump the output
719 * @cur: the object to inspect
720 * @depth: indentation level
721 *
722 * Dump the content of the object for debugging purposes
723 */
724void
725xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000726 int i;
727 char shift[100];
728
729 for (i = 0;((i < depth) && (i < 25));i++)
730 shift[2 * i] = shift[2 * i + 1] = ' ';
731 shift[2 * i] = shift[2 * i + 1] = 0;
732
733 fprintf(output, shift);
734
735 if (cur == NULL) {
736 fprintf(output, "Object is empty (NULL)\n");
737 return;
738 }
739 switch(cur->type) {
740 case XPATH_UNDEFINED:
741 fprintf(output, "Object is uninitialized\n");
742 break;
743 case XPATH_NODESET:
744 fprintf(output, "Object is a Node Set :\n");
745 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
746 break;
747 case XPATH_XSLT_TREE:
748 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000749 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000750 break;
751 case XPATH_BOOLEAN:
752 fprintf(output, "Object is a Boolean : ");
753 if (cur->boolval) fprintf(output, "true\n");
754 else fprintf(output, "false\n");
755 break;
756 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000757 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000758 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000759 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000760 break;
761 case -1:
762 fprintf(output, "Object is a number : -Infinity\n");
763 break;
764 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000765 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000766 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000767 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
768 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000769 } else {
770 fprintf(output, "Object is a number : %0g\n", cur->floatval);
771 }
772 }
Owen Taylor3473f882001-02-23 17:55:21 +0000773 break;
774 case XPATH_STRING:
775 fprintf(output, "Object is a string : ");
776 xmlDebugDumpString(output, cur->stringval);
777 fprintf(output, "\n");
778 break;
779 case XPATH_POINT:
780 fprintf(output, "Object is a point : index %d in node", cur->index);
781 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
782 fprintf(output, "\n");
783 break;
784 case XPATH_RANGE:
785 if ((cur->user2 == NULL) ||
786 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
787 fprintf(output, "Object is a collapsed range :\n");
788 fprintf(output, shift);
789 if (cur->index >= 0)
790 fprintf(output, "index %d in ", cur->index);
791 fprintf(output, "node\n");
792 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
793 depth + 1);
794 } else {
795 fprintf(output, "Object is a range :\n");
796 fprintf(output, shift);
797 fprintf(output, "From ");
798 if (cur->index >= 0)
799 fprintf(output, "index %d in ", cur->index);
800 fprintf(output, "node\n");
801 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
802 depth + 1);
803 fprintf(output, shift);
804 fprintf(output, "To ");
805 if (cur->index2 >= 0)
806 fprintf(output, "index %d in ", cur->index2);
807 fprintf(output, "node\n");
808 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
809 depth + 1);
810 fprintf(output, "\n");
811 }
812 break;
813 case XPATH_LOCATIONSET:
814#if defined(LIBXML_XPTR_ENABLED)
815 fprintf(output, "Object is a Location Set:\n");
816 xmlXPathDebugDumpLocationSet(output,
817 (xmlLocationSetPtr) cur->user, depth);
818#endif
819 break;
820 case XPATH_USERS:
821 fprintf(output, "Object is user defined\n");
822 break;
823 }
824}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000825
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000826static void
827xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000828 xmlXPathStepOpPtr op, int depth) {
829 int i;
830 char shift[100];
831
832 for (i = 0;((i < depth) && (i < 25));i++)
833 shift[2 * i] = shift[2 * i + 1] = ' ';
834 shift[2 * i] = shift[2 * i + 1] = 0;
835
836 fprintf(output, shift);
837 if (op == NULL) {
838 fprintf(output, "Step is NULL\n");
839 return;
840 }
841 switch (op->op) {
842 case XPATH_OP_END:
843 fprintf(output, "END"); break;
844 case XPATH_OP_AND:
845 fprintf(output, "AND"); break;
846 case XPATH_OP_OR:
847 fprintf(output, "OR"); break;
848 case XPATH_OP_EQUAL:
849 if (op->value)
850 fprintf(output, "EQUAL =");
851 else
852 fprintf(output, "EQUAL !=");
853 break;
854 case XPATH_OP_CMP:
855 if (op->value)
856 fprintf(output, "CMP <");
857 else
858 fprintf(output, "CMP >");
859 if (!op->value2)
860 fprintf(output, "=");
861 break;
862 case XPATH_OP_PLUS:
863 if (op->value == 0)
864 fprintf(output, "PLUS -");
865 else if (op->value == 1)
866 fprintf(output, "PLUS +");
867 else if (op->value == 2)
868 fprintf(output, "PLUS unary -");
869 else if (op->value == 3)
870 fprintf(output, "PLUS unary - -");
871 break;
872 case XPATH_OP_MULT:
873 if (op->value == 0)
874 fprintf(output, "MULT *");
875 else if (op->value == 1)
876 fprintf(output, "MULT div");
877 else
878 fprintf(output, "MULT mod");
879 break;
880 case XPATH_OP_UNION:
881 fprintf(output, "UNION"); break;
882 case XPATH_OP_ROOT:
883 fprintf(output, "ROOT"); break;
884 case XPATH_OP_NODE:
885 fprintf(output, "NODE"); break;
886 case XPATH_OP_RESET:
887 fprintf(output, "RESET"); break;
888 case XPATH_OP_SORT:
889 fprintf(output, "SORT"); break;
890 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000891 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
892 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
893 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000894 const xmlChar *prefix = op->value4;
895 const xmlChar *name = op->value5;
896
897 fprintf(output, "COLLECT ");
898 switch (axis) {
899 case AXIS_ANCESTOR:
900 fprintf(output, " 'ancestors' "); break;
901 case AXIS_ANCESTOR_OR_SELF:
902 fprintf(output, " 'ancestors-or-self' "); break;
903 case AXIS_ATTRIBUTE:
904 fprintf(output, " 'attributes' "); break;
905 case AXIS_CHILD:
906 fprintf(output, " 'child' "); break;
907 case AXIS_DESCENDANT:
908 fprintf(output, " 'descendant' "); break;
909 case AXIS_DESCENDANT_OR_SELF:
910 fprintf(output, " 'descendant-or-self' "); break;
911 case AXIS_FOLLOWING:
912 fprintf(output, " 'following' "); break;
913 case AXIS_FOLLOWING_SIBLING:
914 fprintf(output, " 'following-siblings' "); break;
915 case AXIS_NAMESPACE:
916 fprintf(output, " 'namespace' "); break;
917 case AXIS_PARENT:
918 fprintf(output, " 'parent' "); break;
919 case AXIS_PRECEDING:
920 fprintf(output, " 'preceding' "); break;
921 case AXIS_PRECEDING_SIBLING:
922 fprintf(output, " 'preceding-sibling' "); break;
923 case AXIS_SELF:
924 fprintf(output, " 'self' "); break;
925 }
926 switch (test) {
927 case NODE_TEST_NONE:
928 fprintf(output, "'none' "); break;
929 case NODE_TEST_TYPE:
930 fprintf(output, "'type' "); break;
931 case NODE_TEST_PI:
932 fprintf(output, "'PI' "); break;
933 case NODE_TEST_ALL:
934 fprintf(output, "'all' "); break;
935 case NODE_TEST_NS:
936 fprintf(output, "'namespace' "); break;
937 case NODE_TEST_NAME:
938 fprintf(output, "'name' "); break;
939 }
940 switch (type) {
941 case NODE_TYPE_NODE:
942 fprintf(output, "'node' "); break;
943 case NODE_TYPE_COMMENT:
944 fprintf(output, "'comment' "); break;
945 case NODE_TYPE_TEXT:
946 fprintf(output, "'text' "); break;
947 case NODE_TYPE_PI:
948 fprintf(output, "'PI' "); break;
949 }
950 if (prefix != NULL)
951 fprintf(output, "%s:", prefix);
952 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000953 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000954 break;
955
956 }
957 case XPATH_OP_VALUE: {
958 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
959
960 fprintf(output, "ELEM ");
961 xmlXPathDebugDumpObject(output, object, 0);
962 goto finish;
963 }
964 case XPATH_OP_VARIABLE: {
965 const xmlChar *prefix = op->value5;
966 const xmlChar *name = op->value4;
967
968 if (prefix != NULL)
969 fprintf(output, "VARIABLE %s:%s", prefix, name);
970 else
971 fprintf(output, "VARIABLE %s", name);
972 break;
973 }
974 case XPATH_OP_FUNCTION: {
975 int nbargs = op->value;
976 const xmlChar *prefix = op->value5;
977 const xmlChar *name = op->value4;
978
979 if (prefix != NULL)
980 fprintf(output, "FUNCTION %s:%s(%d args)",
981 prefix, name, nbargs);
982 else
983 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
984 break;
985 }
986 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
987 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000988 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000989#ifdef LIBXML_XPTR_ENABLED
990 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
991#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000992 default:
993 fprintf(output, "UNKNOWN %d\n", op->op); return;
994 }
995 fprintf(output, "\n");
996finish:
997 if (op->ch1 >= 0)
998 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
999 if (op->ch2 >= 0)
1000 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1001}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001002
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001003/**
1004 * xmlXPathDebugDumpCompExpr:
1005 * @output: the FILE * for the output
1006 * @comp: the precompiled XPath expression
1007 * @depth: the indentation level.
1008 *
1009 * Dumps the tree of the compiled XPath expression.
1010 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001011void
1012xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1013 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001014 int i;
1015 char shift[100];
1016
1017 for (i = 0;((i < depth) && (i < 25));i++)
1018 shift[2 * i] = shift[2 * i + 1] = ' ';
1019 shift[2 * i] = shift[2 * i + 1] = 0;
1020
1021 fprintf(output, shift);
1022
1023 if (comp == NULL) {
1024 fprintf(output, "Compiled Expression is NULL\n");
1025 return;
1026 }
1027 fprintf(output, "Compiled Expression : %d elements\n",
1028 comp->nbStep);
1029 i = comp->last;
1030 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1031}
Daniel Veillard017b1082001-06-21 11:20:21 +00001032#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001033
1034/************************************************************************
1035 * *
1036 * Parser stacks related functions and macros *
1037 * *
1038 ************************************************************************/
1039
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001040/**
1041 * valuePop:
1042 * @ctxt: an XPath evaluation context
1043 *
1044 * Pops the top XPath object from the value stack
1045 *
1046 * Returns the XPath object just removed
1047 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001048extern xmlXPathObjectPtr
1049valuePop(xmlXPathParserContextPtr ctxt)
1050{
1051 xmlXPathObjectPtr ret;
1052
1053 if (ctxt->valueNr <= 0)
1054 return (0);
1055 ctxt->valueNr--;
1056 if (ctxt->valueNr > 0)
1057 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1058 else
1059 ctxt->value = NULL;
1060 ret = ctxt->valueTab[ctxt->valueNr];
1061 ctxt->valueTab[ctxt->valueNr] = 0;
1062 return (ret);
1063}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001064/**
1065 * valuePush:
1066 * @ctxt: an XPath evaluation context
1067 * @value: the XPath object
1068 *
1069 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001070 *
1071 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001072 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001073extern int
1074valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1075{
1076 if (ctxt->valueNr >= ctxt->valueMax) {
1077 ctxt->valueMax *= 2;
1078 ctxt->valueTab =
1079 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1080 ctxt->valueMax *
1081 sizeof(ctxt->valueTab[0]));
1082 if (ctxt->valueTab == NULL) {
1083 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1084 return (0);
1085 }
1086 }
1087 ctxt->valueTab[ctxt->valueNr] = value;
1088 ctxt->value = value;
1089 return (ctxt->valueNr++);
1090}
Owen Taylor3473f882001-02-23 17:55:21 +00001091
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001092/**
1093 * xmlXPathPopBoolean:
1094 * @ctxt: an XPath parser context
1095 *
1096 * Pops a boolean from the stack, handling conversion if needed.
1097 * Check error with #xmlXPathCheckError.
1098 *
1099 * Returns the boolean
1100 */
1101int
1102xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1103 xmlXPathObjectPtr obj;
1104 int ret;
1105
1106 obj = valuePop(ctxt);
1107 if (obj == NULL) {
1108 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1109 return(0);
1110 }
1111 ret = xmlXPathCastToBoolean(obj);
1112 xmlXPathFreeObject(obj);
1113 return(ret);
1114}
1115
1116/**
1117 * xmlXPathPopNumber:
1118 * @ctxt: an XPath parser context
1119 *
1120 * Pops a number from the stack, handling conversion if needed.
1121 * Check error with #xmlXPathCheckError.
1122 *
1123 * Returns the number
1124 */
1125double
1126xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1127 xmlXPathObjectPtr obj;
1128 double ret;
1129
1130 obj = valuePop(ctxt);
1131 if (obj == NULL) {
1132 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1133 return(0);
1134 }
1135 ret = xmlXPathCastToNumber(obj);
1136 xmlXPathFreeObject(obj);
1137 return(ret);
1138}
1139
1140/**
1141 * xmlXPathPopString:
1142 * @ctxt: an XPath parser context
1143 *
1144 * Pops a string from the stack, handling conversion if needed.
1145 * Check error with #xmlXPathCheckError.
1146 *
1147 * Returns the string
1148 */
1149xmlChar *
1150xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1151 xmlXPathObjectPtr obj;
1152 xmlChar * ret;
1153
1154 obj = valuePop(ctxt);
1155 if (obj == NULL) {
1156 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1157 return(NULL);
1158 }
1159 ret = xmlXPathCastToString(obj);
1160 /* TODO: needs refactoring somewhere else */
1161 if (obj->stringval == ret)
1162 obj->stringval = NULL;
1163 xmlXPathFreeObject(obj);
1164 return(ret);
1165}
1166
1167/**
1168 * xmlXPathPopNodeSet:
1169 * @ctxt: an XPath parser context
1170 *
1171 * Pops a node-set from the stack, handling conversion if needed.
1172 * Check error with #xmlXPathCheckError.
1173 *
1174 * Returns the node-set
1175 */
1176xmlNodeSetPtr
1177xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1178 xmlXPathObjectPtr obj;
1179 xmlNodeSetPtr ret;
1180
1181 if (ctxt->value == NULL) {
1182 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1183 return(NULL);
1184 }
1185 if (!xmlXPathStackIsNodeSet(ctxt)) {
1186 xmlXPathSetTypeError(ctxt);
1187 return(NULL);
1188 }
1189 obj = valuePop(ctxt);
1190 ret = obj->nodesetval;
Daniel Veillard9deb2422003-07-28 20:40:59 +00001191 /* to fix memory leak of not clearing obj->user */
1192 if (obj->boolval && obj->user != NULL)
1193 xmlFreeNodeList((xmlNodePtr) obj->user);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001194 xmlXPathFreeNodeSetList(obj);
1195 return(ret);
1196}
1197
1198/**
1199 * xmlXPathPopExternal:
1200 * @ctxt: an XPath parser context
1201 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001202 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001203 * Check error with #xmlXPathCheckError.
1204 *
1205 * Returns the object
1206 */
1207void *
1208xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1209 xmlXPathObjectPtr obj;
1210 void * ret;
1211
1212 if (ctxt->value == NULL) {
1213 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1214 return(NULL);
1215 }
1216 if (ctxt->value->type != XPATH_USERS) {
1217 xmlXPathSetTypeError(ctxt);
1218 return(NULL);
1219 }
1220 obj = valuePop(ctxt);
1221 ret = obj->user;
1222 xmlXPathFreeObject(obj);
1223 return(ret);
1224}
1225
Owen Taylor3473f882001-02-23 17:55:21 +00001226/*
1227 * Macros for accessing the content. Those should be used only by the parser,
1228 * and not exported.
1229 *
1230 * Dirty macros, i.e. one need to make assumption on the context to use them
1231 *
1232 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1233 * CUR returns the current xmlChar value, i.e. a 8 bit value
1234 * in ISO-Latin or UTF-8.
1235 * This should be used internally by the parser
1236 * only to compare to ASCII values otherwise it would break when
1237 * running with UTF-8 encoding.
1238 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1239 * to compare on ASCII based substring.
1240 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1241 * strings within the parser.
1242 * CURRENT Returns the current char value, with the full decoding of
1243 * UTF-8 if we are using this mode. It returns an int.
1244 * NEXT Skip to the next character, this does the proper decoding
1245 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1246 * It returns the pointer to the current xmlChar.
1247 */
1248
1249#define CUR (*ctxt->cur)
1250#define SKIP(val) ctxt->cur += (val)
1251#define NXT(val) ctxt->cur[(val)]
1252#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001253#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1254
1255#define COPY_BUF(l,b,i,v) \
1256 if (l == 1) b[i++] = (xmlChar) v; \
1257 else i += xmlCopyChar(l,&b[i],v)
1258
1259#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001260
1261#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001262 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001263
1264#define CURRENT (*ctxt->cur)
1265#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1266
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001267
1268#ifndef DBL_DIG
1269#define DBL_DIG 16
1270#endif
1271#ifndef DBL_EPSILON
1272#define DBL_EPSILON 1E-9
1273#endif
1274
1275#define UPPER_DOUBLE 1E9
1276#define LOWER_DOUBLE 1E-5
1277
1278#define INTEGER_DIGITS DBL_DIG
1279#define FRACTION_DIGITS (DBL_DIG + 1)
1280#define EXPONENT_DIGITS (3 + 2)
1281
1282/**
1283 * xmlXPathFormatNumber:
1284 * @number: number to format
1285 * @buffer: output buffer
1286 * @buffersize: size of output buffer
1287 *
1288 * Convert the number into a string representation.
1289 */
1290static void
1291xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1292{
Daniel Veillardcda96922001-08-21 10:56:31 +00001293 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001294 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001295 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001296 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001297 break;
1298 case -1:
1299 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001300 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001301 break;
1302 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001303 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001304 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001305 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001306 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001307 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001308 } else if (number == ((int) number)) {
1309 char work[30];
1310 char *ptr, *cur;
1311 int res, value = (int) number;
1312
1313 ptr = &buffer[0];
1314 if (value < 0) {
1315 *ptr++ = '-';
1316 value = -value;
1317 }
1318 if (value == 0) {
1319 *ptr++ = '0';
1320 } else {
1321 cur = &work[0];
1322 while (value != 0) {
1323 res = value % 10;
1324 value = value / 10;
1325 *cur++ = '0' + res;
1326 }
1327 cur--;
1328 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1329 *ptr++ = *cur--;
1330 }
1331 }
1332 if (ptr - buffer < buffersize) {
1333 *ptr = 0;
1334 } else if (buffersize > 0) {
1335 ptr--;
1336 *ptr = 0;
1337 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001338 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001339 /* 3 is sign, decimal point, and terminating zero */
1340 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1341 int integer_place, fraction_place;
1342 char *ptr;
1343 char *after_fraction;
1344 double absolute_value;
1345 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001346
Bjorn Reese70a9da52001-04-21 16:57:29 +00001347 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001348
Bjorn Reese70a9da52001-04-21 16:57:29 +00001349 /*
1350 * First choose format - scientific or regular floating point.
1351 * In either case, result is in work, and after_fraction points
1352 * just past the fractional part.
1353 */
1354 if ( ((absolute_value > UPPER_DOUBLE) ||
1355 (absolute_value < LOWER_DOUBLE)) &&
1356 (absolute_value != 0.0) ) {
1357 /* Use scientific notation */
1358 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1359 fraction_place = DBL_DIG - 1;
1360 snprintf(work, sizeof(work),"%*.*e",
1361 integer_place, fraction_place, number);
1362 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001363 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001364 else {
1365 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001366 if (absolute_value > 0.0)
1367 integer_place = 1 + (int)log10(absolute_value);
1368 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001369 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001370 fraction_place = (integer_place > 0)
1371 ? DBL_DIG - integer_place
1372 : DBL_DIG;
1373 size = snprintf(work, sizeof(work), "%0.*f",
1374 fraction_place, number);
1375 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001376 }
1377
Bjorn Reese70a9da52001-04-21 16:57:29 +00001378 /* Remove fractional trailing zeroes */
1379 ptr = after_fraction;
1380 while (*(--ptr) == '0')
1381 ;
1382 if (*ptr != '.')
1383 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001384 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001385
1386 /* Finally copy result back to caller */
1387 size = strlen(work) + 1;
1388 if (size > buffersize) {
1389 work[buffersize - 1] = 0;
1390 size = buffersize;
1391 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001392 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001393 }
1394 break;
1395 }
1396}
1397
Owen Taylor3473f882001-02-23 17:55:21 +00001398
1399/************************************************************************
1400 * *
1401 * Routines to handle NodeSets *
1402 * *
1403 ************************************************************************/
1404
1405/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001406 * xmlXPathOrderDocElems:
1407 * @doc: an input document
1408 *
1409 * Call this routine to speed up XPath computation on static documents.
1410 * This stamps all the element nodes with the document order
1411 * Like for line information, the order is kept in the element->content
1412 * field, the value stored is actually - the node number (startting at -1)
1413 * to be able to differenciate from line numbers.
1414 *
1415 * Returns the number of element found in the document or -1 in case
1416 * of error.
1417 */
1418long
1419xmlXPathOrderDocElems(xmlDocPtr doc) {
1420 long count = 0;
1421 xmlNodePtr cur;
1422
1423 if (doc == NULL)
1424 return(-1);
1425 cur = doc->children;
1426 while (cur != NULL) {
1427 if (cur->type == XML_ELEMENT_NODE) {
1428 cur->content = (void *) (-(++count));
1429 if (cur->children != NULL) {
1430 cur = cur->children;
1431 continue;
1432 }
1433 }
1434 if (cur->next != NULL) {
1435 cur = cur->next;
1436 continue;
1437 }
1438 do {
1439 cur = cur->parent;
1440 if (cur == NULL)
1441 break;
1442 if (cur == (xmlNodePtr) doc) {
1443 cur = NULL;
1444 break;
1445 }
1446 if (cur->next != NULL) {
1447 cur = cur->next;
1448 break;
1449 }
1450 } while (cur != NULL);
1451 }
1452 return(count);
1453}
1454
1455/**
Owen Taylor3473f882001-02-23 17:55:21 +00001456 * xmlXPathCmpNodes:
1457 * @node1: the first node
1458 * @node2: the second node
1459 *
1460 * Compare two nodes w.r.t document order
1461 *
1462 * Returns -2 in case of error 1 if first point < second point, 0 if
1463 * that's the same node, -1 otherwise
1464 */
1465int
1466xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1467 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001468 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001469 xmlNodePtr cur, root;
1470
1471 if ((node1 == NULL) || (node2 == NULL))
1472 return(-2);
1473 /*
1474 * a couple of optimizations which will avoid computations in most cases
1475 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001476 if (node1->type == XML_ATTRIBUTE_NODE) {
1477 attr1 = 1;
1478 node1 = node1->parent;
1479 }
1480 if (node2->type == XML_ATTRIBUTE_NODE) {
1481 attr2 = 1;
1482 node2 = node2->parent;
1483 }
1484 if (node1 == node2) {
1485 if (attr1 == attr2)
1486 return(0);
1487 if (attr2 == 1)
1488 return(1);
1489 return(-1);
1490 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001491 if ((node1->type == XML_NAMESPACE_DECL) ||
1492 (node2->type == XML_NAMESPACE_DECL))
1493 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001494 if (node1 == node2->prev)
1495 return(1);
1496 if (node1 == node2->next)
1497 return(-1);
1498
1499 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001500 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001501 */
1502 if ((node1->type == XML_ELEMENT_NODE) &&
1503 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001504 (0 > (long) node1->content) &&
1505 (0 > (long) node2->content) &&
1506 (node1->doc == node2->doc)) {
1507 long l1, l2;
1508
1509 l1 = -((long) node1->content);
1510 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001511 if (l1 < l2)
1512 return(1);
1513 if (l1 > l2)
1514 return(-1);
1515 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001516
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001517 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001518 * compute depth to root
1519 */
1520 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1521 if (cur == node1)
1522 return(1);
1523 depth2++;
1524 }
1525 root = cur;
1526 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1527 if (cur == node2)
1528 return(-1);
1529 depth1++;
1530 }
1531 /*
1532 * Distinct document (or distinct entities :-( ) case.
1533 */
1534 if (root != cur) {
1535 return(-2);
1536 }
1537 /*
1538 * get the nearest common ancestor.
1539 */
1540 while (depth1 > depth2) {
1541 depth1--;
1542 node1 = node1->parent;
1543 }
1544 while (depth2 > depth1) {
1545 depth2--;
1546 node2 = node2->parent;
1547 }
1548 while (node1->parent != node2->parent) {
1549 node1 = node1->parent;
1550 node2 = node2->parent;
1551 /* should not happen but just in case ... */
1552 if ((node1 == NULL) || (node2 == NULL))
1553 return(-2);
1554 }
1555 /*
1556 * Find who's first.
1557 */
1558 if (node1 == node2->next)
1559 return(-1);
1560 for (cur = node1->next;cur != NULL;cur = cur->next)
1561 if (cur == node2)
1562 return(1);
1563 return(-1); /* assume there is no sibling list corruption */
1564}
1565
1566/**
1567 * xmlXPathNodeSetSort:
1568 * @set: the node set
1569 *
1570 * Sort the node set in document order
1571 */
1572void
1573xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001574 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001575 xmlNodePtr tmp;
1576
1577 if (set == NULL)
1578 return;
1579
1580 /* Use Shell's sort to sort the node-set */
1581 len = set->nodeNr;
1582 for (incr = len / 2; incr > 0; incr /= 2) {
1583 for (i = incr; i < len; i++) {
1584 j = i - incr;
1585 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001586 if (xmlXPathCmpNodes(set->nodeTab[j],
1587 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001588 tmp = set->nodeTab[j];
1589 set->nodeTab[j] = set->nodeTab[j + incr];
1590 set->nodeTab[j + incr] = tmp;
1591 j -= incr;
1592 } else
1593 break;
1594 }
1595 }
1596 }
1597}
1598
1599#define XML_NODESET_DEFAULT 10
1600/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001601 * xmlXPathNodeSetDupNs:
1602 * @node: the parent node of the namespace XPath node
1603 * @ns: the libxml namespace declaration node.
1604 *
1605 * Namespace node in libxml don't match the XPath semantic. In a node set
1606 * the namespace nodes are duplicated and the next pointer is set to the
1607 * parent node in the XPath semantic.
1608 *
1609 * Returns the newly created object.
1610 */
1611static xmlNodePtr
1612xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1613 xmlNsPtr cur;
1614
1615 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1616 return(NULL);
1617 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1618 return((xmlNodePtr) ns);
1619
1620 /*
1621 * Allocate a new Namespace and fill the fields.
1622 */
1623 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1624 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001625 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001626 return(NULL);
1627 }
1628 memset(cur, 0, sizeof(xmlNs));
1629 cur->type = XML_NAMESPACE_DECL;
1630 if (ns->href != NULL)
1631 cur->href = xmlStrdup(ns->href);
1632 if (ns->prefix != NULL)
1633 cur->prefix = xmlStrdup(ns->prefix);
1634 cur->next = (xmlNsPtr) node;
1635 return((xmlNodePtr) cur);
1636}
1637
1638/**
1639 * xmlXPathNodeSetFreeNs:
1640 * @ns: the XPath namespace node found in a nodeset.
1641 *
1642 * Namespace node in libxml don't match the XPath semantic. In a node set
1643 * the namespace nodes are duplicated and the next pointer is set to the
1644 * parent node in the XPath semantic. Check if such a node need to be freed
1645 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001646void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001647xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1648 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1649 return;
1650
1651 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1652 if (ns->href != NULL)
1653 xmlFree((xmlChar *)ns->href);
1654 if (ns->prefix != NULL)
1655 xmlFree((xmlChar *)ns->prefix);
1656 xmlFree(ns);
1657 }
1658}
1659
1660/**
Owen Taylor3473f882001-02-23 17:55:21 +00001661 * xmlXPathNodeSetCreate:
1662 * @val: an initial xmlNodePtr, or NULL
1663 *
1664 * Create a new xmlNodeSetPtr of type double and of value @val
1665 *
1666 * Returns the newly created object.
1667 */
1668xmlNodeSetPtr
1669xmlXPathNodeSetCreate(xmlNodePtr val) {
1670 xmlNodeSetPtr ret;
1671
1672 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1673 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001674 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001675 return(NULL);
1676 }
1677 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1678 if (val != NULL) {
1679 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1680 sizeof(xmlNodePtr));
1681 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001682 xmlXPathErrMemory(NULL, "creating nodeset\n");
1683 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001684 return(NULL);
1685 }
1686 memset(ret->nodeTab, 0 ,
1687 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1688 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001689 if (val->type == XML_NAMESPACE_DECL) {
1690 xmlNsPtr ns = (xmlNsPtr) val;
1691
1692 ret->nodeTab[ret->nodeNr++] =
1693 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1694 } else
1695 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001696 }
1697 return(ret);
1698}
1699
1700/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001701 * xmlXPathNodeSetContains:
1702 * @cur: the node-set
1703 * @val: the node
1704 *
1705 * checks whether @cur contains @val
1706 *
1707 * Returns true (1) if @cur contains @val, false (0) otherwise
1708 */
1709int
1710xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1711 int i;
1712
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001713 if (val->type == XML_NAMESPACE_DECL) {
1714 for (i = 0; i < cur->nodeNr; i++) {
1715 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1716 xmlNsPtr ns1, ns2;
1717
1718 ns1 = (xmlNsPtr) val;
1719 ns2 = (xmlNsPtr) cur->nodeTab[i];
1720 if (ns1 == ns2)
1721 return(1);
1722 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1723 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1724 return(1);
1725 }
1726 }
1727 } else {
1728 for (i = 0; i < cur->nodeNr; i++) {
1729 if (cur->nodeTab[i] == val)
1730 return(1);
1731 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001732 }
1733 return(0);
1734}
1735
1736/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001737 * xmlXPathNodeSetAddNs:
1738 * @cur: the initial node set
1739 * @node: the hosting node
1740 * @ns: a the namespace node
1741 *
1742 * add a new namespace node to an existing NodeSet
1743 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001744void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001745xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1746 int i;
1747
1748 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1749 (node->type != XML_ELEMENT_NODE))
1750 return;
1751
1752 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1753 /*
1754 * check against doublons
1755 */
1756 for (i = 0;i < cur->nodeNr;i++) {
1757 if ((cur->nodeTab[i] != NULL) &&
1758 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001759 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001760 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1761 return;
1762 }
1763
1764 /*
1765 * grow the nodeTab if needed
1766 */
1767 if (cur->nodeMax == 0) {
1768 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1769 sizeof(xmlNodePtr));
1770 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001771 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001772 return;
1773 }
1774 memset(cur->nodeTab, 0 ,
1775 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1776 cur->nodeMax = XML_NODESET_DEFAULT;
1777 } else if (cur->nodeNr == cur->nodeMax) {
1778 xmlNodePtr *temp;
1779
1780 cur->nodeMax *= 2;
1781 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1782 sizeof(xmlNodePtr));
1783 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001784 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001785 return;
1786 }
1787 cur->nodeTab = temp;
1788 }
1789 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1790}
1791
1792/**
Owen Taylor3473f882001-02-23 17:55:21 +00001793 * xmlXPathNodeSetAdd:
1794 * @cur: the initial node set
1795 * @val: a new xmlNodePtr
1796 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001797 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001798 */
1799void
1800xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1801 int i;
1802
1803 if (val == NULL) return;
1804
Daniel Veillardef0b4502003-03-24 13:57:34 +00001805#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001806 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1807 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001808#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001809
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001810 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001811 /*
1812 * check against doublons
1813 */
1814 for (i = 0;i < cur->nodeNr;i++)
1815 if (cur->nodeTab[i] == val) return;
1816
1817 /*
1818 * grow the nodeTab if needed
1819 */
1820 if (cur->nodeMax == 0) {
1821 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1822 sizeof(xmlNodePtr));
1823 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001824 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001825 return;
1826 }
1827 memset(cur->nodeTab, 0 ,
1828 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1829 cur->nodeMax = XML_NODESET_DEFAULT;
1830 } else if (cur->nodeNr == cur->nodeMax) {
1831 xmlNodePtr *temp;
1832
1833 cur->nodeMax *= 2;
1834 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1835 sizeof(xmlNodePtr));
1836 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001837 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001838 return;
1839 }
1840 cur->nodeTab = temp;
1841 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001842 if (val->type == XML_NAMESPACE_DECL) {
1843 xmlNsPtr ns = (xmlNsPtr) val;
1844
1845 cur->nodeTab[cur->nodeNr++] =
1846 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1847 } else
1848 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001849}
1850
1851/**
1852 * xmlXPathNodeSetAddUnique:
1853 * @cur: the initial node set
1854 * @val: a new xmlNodePtr
1855 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001856 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001857 * when we are sure the node is not already in the set.
1858 */
1859void
1860xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1861 if (val == NULL) return;
1862
Daniel Veillardef0b4502003-03-24 13:57:34 +00001863#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001864 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1865 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001866#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001867
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001868 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001869 /*
1870 * grow the nodeTab if needed
1871 */
1872 if (cur->nodeMax == 0) {
1873 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1874 sizeof(xmlNodePtr));
1875 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001876 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001877 return;
1878 }
1879 memset(cur->nodeTab, 0 ,
1880 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1881 cur->nodeMax = XML_NODESET_DEFAULT;
1882 } else if (cur->nodeNr == cur->nodeMax) {
1883 xmlNodePtr *temp;
1884
1885 cur->nodeMax *= 2;
1886 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1887 sizeof(xmlNodePtr));
1888 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001889 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001890 return;
1891 }
1892 cur->nodeTab = temp;
1893 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001894 if (val->type == XML_NAMESPACE_DECL) {
1895 xmlNsPtr ns = (xmlNsPtr) val;
1896
1897 cur->nodeTab[cur->nodeNr++] =
1898 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1899 } else
1900 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001901}
1902
1903/**
1904 * xmlXPathNodeSetMerge:
1905 * @val1: the first NodeSet or NULL
1906 * @val2: the second NodeSet
1907 *
1908 * Merges two nodesets, all nodes from @val2 are added to @val1
1909 * if @val1 is NULL, a new set is created and copied from @val2
1910 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001911 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001912 */
1913xmlNodeSetPtr
1914xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001915 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001916
1917 if (val2 == NULL) return(val1);
1918 if (val1 == NULL) {
1919 val1 = xmlXPathNodeSetCreate(NULL);
1920 }
1921
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001922 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001923 initNr = val1->nodeNr;
1924
1925 for (i = 0;i < val2->nodeNr;i++) {
1926 /*
1927 * check against doublons
1928 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001929 skip = 0;
1930 for (j = 0; j < initNr; j++) {
1931 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1932 skip = 1;
1933 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001934 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1935 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1936 xmlNsPtr ns1, ns2;
1937 ns1 = (xmlNsPtr) val1->nodeTab[j];
1938 ns2 = (xmlNsPtr) val2->nodeTab[i];
1939 if ((ns1->next == ns2->next) &&
1940 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1941 skip = 1;
1942 break;
1943 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001944 }
1945 }
1946 if (skip)
1947 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001948
1949 /*
1950 * grow the nodeTab if needed
1951 */
1952 if (val1->nodeMax == 0) {
1953 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1954 sizeof(xmlNodePtr));
1955 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001956 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001957 return(NULL);
1958 }
1959 memset(val1->nodeTab, 0 ,
1960 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1961 val1->nodeMax = XML_NODESET_DEFAULT;
1962 } else if (val1->nodeNr == val1->nodeMax) {
1963 xmlNodePtr *temp;
1964
1965 val1->nodeMax *= 2;
1966 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1967 sizeof(xmlNodePtr));
1968 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001969 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001970 return(NULL);
1971 }
1972 val1->nodeTab = temp;
1973 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001974 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1975 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1976
1977 val1->nodeTab[val1->nodeNr++] =
1978 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1979 } else
1980 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001981 }
1982
1983 return(val1);
1984}
1985
1986/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001987 * xmlXPathNodeSetMergeUnique:
1988 * @val1: the first NodeSet or NULL
1989 * @val2: the second NodeSet
1990 *
1991 * Merges two nodesets, all nodes from @val2 are added to @val1
1992 * if @val1 is NULL, a new set is created and copied from @val2
1993 *
1994 * Returns @val1 once extended or NULL in case of error.
1995 */
1996static xmlNodeSetPtr
1997xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00001998 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00001999
2000 if (val2 == NULL) return(val1);
2001 if (val1 == NULL) {
2002 val1 = xmlXPathNodeSetCreate(NULL);
2003 }
2004
2005 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002006
2007 for (i = 0;i < val2->nodeNr;i++) {
2008 /*
2009 * grow the nodeTab if needed
2010 */
2011 if (val1->nodeMax == 0) {
2012 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2013 sizeof(xmlNodePtr));
2014 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002015 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002016 return(NULL);
2017 }
2018 memset(val1->nodeTab, 0 ,
2019 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2020 val1->nodeMax = XML_NODESET_DEFAULT;
2021 } else if (val1->nodeNr == val1->nodeMax) {
2022 xmlNodePtr *temp;
2023
2024 val1->nodeMax *= 2;
2025 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2026 sizeof(xmlNodePtr));
2027 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002028 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002029 return(NULL);
2030 }
2031 val1->nodeTab = temp;
2032 }
2033 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2034 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2035
2036 val1->nodeTab[val1->nodeNr++] =
2037 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2038 } else
2039 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2040 }
2041
2042 return(val1);
2043}
2044
2045/**
Owen Taylor3473f882001-02-23 17:55:21 +00002046 * xmlXPathNodeSetDel:
2047 * @cur: the initial node set
2048 * @val: an xmlNodePtr
2049 *
2050 * Removes an xmlNodePtr from an existing NodeSet
2051 */
2052void
2053xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2054 int i;
2055
2056 if (cur == NULL) return;
2057 if (val == NULL) return;
2058
2059 /*
2060 * check against doublons
2061 */
2062 for (i = 0;i < cur->nodeNr;i++)
2063 if (cur->nodeTab[i] == val) break;
2064
2065 if (i >= cur->nodeNr) {
2066#ifdef DEBUG
2067 xmlGenericError(xmlGenericErrorContext,
2068 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2069 val->name);
2070#endif
2071 return;
2072 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002073 if ((cur->nodeTab[i] != NULL) &&
2074 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2075 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002076 cur->nodeNr--;
2077 for (;i < cur->nodeNr;i++)
2078 cur->nodeTab[i] = cur->nodeTab[i + 1];
2079 cur->nodeTab[cur->nodeNr] = NULL;
2080}
2081
2082/**
2083 * xmlXPathNodeSetRemove:
2084 * @cur: the initial node set
2085 * @val: the index to remove
2086 *
2087 * Removes an entry from an existing NodeSet list.
2088 */
2089void
2090xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2091 if (cur == NULL) return;
2092 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002093 if ((cur->nodeTab[val] != NULL) &&
2094 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2095 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002096 cur->nodeNr--;
2097 for (;val < cur->nodeNr;val++)
2098 cur->nodeTab[val] = cur->nodeTab[val + 1];
2099 cur->nodeTab[cur->nodeNr] = NULL;
2100}
2101
2102/**
2103 * xmlXPathFreeNodeSet:
2104 * @obj: the xmlNodeSetPtr to free
2105 *
2106 * Free the NodeSet compound (not the actual nodes !).
2107 */
2108void
2109xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2110 if (obj == NULL) return;
2111 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002112 int i;
2113
2114 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2115 for (i = 0;i < obj->nodeNr;i++)
2116 if ((obj->nodeTab[i] != NULL) &&
2117 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2118 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002119 xmlFree(obj->nodeTab);
2120 }
Owen Taylor3473f882001-02-23 17:55:21 +00002121 xmlFree(obj);
2122}
2123
2124/**
2125 * xmlXPathFreeValueTree:
2126 * @obj: the xmlNodeSetPtr to free
2127 *
2128 * Free the NodeSet compound and the actual tree, this is different
2129 * from xmlXPathFreeNodeSet()
2130 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002131static void
Owen Taylor3473f882001-02-23 17:55:21 +00002132xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2133 int i;
2134
2135 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002136
2137 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002138 for (i = 0;i < obj->nodeNr;i++) {
2139 if (obj->nodeTab[i] != NULL) {
2140 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2141 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2142 } else {
2143 xmlFreeNodeList(obj->nodeTab[i]);
2144 }
2145 }
2146 }
Owen Taylor3473f882001-02-23 17:55:21 +00002147 xmlFree(obj->nodeTab);
2148 }
Owen Taylor3473f882001-02-23 17:55:21 +00002149 xmlFree(obj);
2150}
2151
2152#if defined(DEBUG) || defined(DEBUG_STEP)
2153/**
2154 * xmlGenericErrorContextNodeSet:
2155 * @output: a FILE * for the output
2156 * @obj: the xmlNodeSetPtr to free
2157 *
2158 * Quick display of a NodeSet
2159 */
2160void
2161xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2162 int i;
2163
2164 if (output == NULL) output = xmlGenericErrorContext;
2165 if (obj == NULL) {
2166 fprintf(output, "NodeSet == NULL !\n");
2167 return;
2168 }
2169 if (obj->nodeNr == 0) {
2170 fprintf(output, "NodeSet is empty\n");
2171 return;
2172 }
2173 if (obj->nodeTab == NULL) {
2174 fprintf(output, " nodeTab == NULL !\n");
2175 return;
2176 }
2177 for (i = 0; i < obj->nodeNr; i++) {
2178 if (obj->nodeTab[i] == NULL) {
2179 fprintf(output, " NULL !\n");
2180 return;
2181 }
2182 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2183 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2184 fprintf(output, " /");
2185 else if (obj->nodeTab[i]->name == NULL)
2186 fprintf(output, " noname!");
2187 else fprintf(output, " %s", obj->nodeTab[i]->name);
2188 }
2189 fprintf(output, "\n");
2190}
2191#endif
2192
2193/**
2194 * xmlXPathNewNodeSet:
2195 * @val: the NodePtr value
2196 *
2197 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2198 * it with the single Node @val
2199 *
2200 * Returns the newly created object.
2201 */
2202xmlXPathObjectPtr
2203xmlXPathNewNodeSet(xmlNodePtr val) {
2204 xmlXPathObjectPtr ret;
2205
2206 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2207 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002208 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002209 return(NULL);
2210 }
2211 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2212 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002213 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002214 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002215 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002216 return(ret);
2217}
2218
2219/**
2220 * xmlXPathNewValueTree:
2221 * @val: the NodePtr value
2222 *
2223 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2224 * it with the tree root @val
2225 *
2226 * Returns the newly created object.
2227 */
2228xmlXPathObjectPtr
2229xmlXPathNewValueTree(xmlNodePtr val) {
2230 xmlXPathObjectPtr ret;
2231
2232 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2233 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002234 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002235 return(NULL);
2236 }
2237 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2238 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002239 ret->boolval = 1;
2240 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002241 ret->nodesetval = xmlXPathNodeSetCreate(val);
2242 return(ret);
2243}
2244
2245/**
2246 * xmlXPathNewNodeSetList:
2247 * @val: an existing NodeSet
2248 *
2249 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2250 * it with the Nodeset @val
2251 *
2252 * Returns the newly created object.
2253 */
2254xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002255xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2256{
Owen Taylor3473f882001-02-23 17:55:21 +00002257 xmlXPathObjectPtr ret;
2258 int i;
2259
2260 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002261 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002262 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002263 ret = xmlXPathNewNodeSet(NULL);
2264 else {
2265 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2266 for (i = 1; i < val->nodeNr; ++i)
2267 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2268 }
Owen Taylor3473f882001-02-23 17:55:21 +00002269
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002270 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002271}
2272
2273/**
2274 * xmlXPathWrapNodeSet:
2275 * @val: the NodePtr value
2276 *
2277 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2278 *
2279 * Returns the newly created object.
2280 */
2281xmlXPathObjectPtr
2282xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2283 xmlXPathObjectPtr ret;
2284
2285 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2286 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002287 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002288 return(NULL);
2289 }
2290 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2291 ret->type = XPATH_NODESET;
2292 ret->nodesetval = val;
2293 return(ret);
2294}
2295
2296/**
2297 * xmlXPathFreeNodeSetList:
2298 * @obj: an existing NodeSetList object
2299 *
2300 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2301 * the list contrary to xmlXPathFreeObject().
2302 */
2303void
2304xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2305 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002306 xmlFree(obj);
2307}
2308
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002309/**
2310 * xmlXPathDifference:
2311 * @nodes1: a node-set
2312 * @nodes2: a node-set
2313 *
2314 * Implements the EXSLT - Sets difference() function:
2315 * node-set set:difference (node-set, node-set)
2316 *
2317 * Returns the difference between the two node sets, or nodes1 if
2318 * nodes2 is empty
2319 */
2320xmlNodeSetPtr
2321xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2322 xmlNodeSetPtr ret;
2323 int i, l1;
2324 xmlNodePtr cur;
2325
2326 if (xmlXPathNodeSetIsEmpty(nodes2))
2327 return(nodes1);
2328
2329 ret = xmlXPathNodeSetCreate(NULL);
2330 if (xmlXPathNodeSetIsEmpty(nodes1))
2331 return(ret);
2332
2333 l1 = xmlXPathNodeSetGetLength(nodes1);
2334
2335 for (i = 0; i < l1; i++) {
2336 cur = xmlXPathNodeSetItem(nodes1, i);
2337 if (!xmlXPathNodeSetContains(nodes2, cur))
2338 xmlXPathNodeSetAddUnique(ret, cur);
2339 }
2340 return(ret);
2341}
2342
2343/**
2344 * xmlXPathIntersection:
2345 * @nodes1: a node-set
2346 * @nodes2: a node-set
2347 *
2348 * Implements the EXSLT - Sets intersection() function:
2349 * node-set set:intersection (node-set, node-set)
2350 *
2351 * Returns a node set comprising the nodes that are within both the
2352 * node sets passed as arguments
2353 */
2354xmlNodeSetPtr
2355xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2356 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2357 int i, l1;
2358 xmlNodePtr cur;
2359
2360 if (xmlXPathNodeSetIsEmpty(nodes1))
2361 return(ret);
2362 if (xmlXPathNodeSetIsEmpty(nodes2))
2363 return(ret);
2364
2365 l1 = xmlXPathNodeSetGetLength(nodes1);
2366
2367 for (i = 0; i < l1; i++) {
2368 cur = xmlXPathNodeSetItem(nodes1, i);
2369 if (xmlXPathNodeSetContains(nodes2, cur))
2370 xmlXPathNodeSetAddUnique(ret, cur);
2371 }
2372 return(ret);
2373}
2374
2375/**
2376 * xmlXPathDistinctSorted:
2377 * @nodes: a node-set, sorted by document order
2378 *
2379 * Implements the EXSLT - Sets distinct() function:
2380 * node-set set:distinct (node-set)
2381 *
2382 * Returns a subset of the nodes contained in @nodes, or @nodes if
2383 * it is empty
2384 */
2385xmlNodeSetPtr
2386xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2387 xmlNodeSetPtr ret;
2388 xmlHashTablePtr hash;
2389 int i, l;
2390 xmlChar * strval;
2391 xmlNodePtr cur;
2392
2393 if (xmlXPathNodeSetIsEmpty(nodes))
2394 return(nodes);
2395
2396 ret = xmlXPathNodeSetCreate(NULL);
2397 l = xmlXPathNodeSetGetLength(nodes);
2398 hash = xmlHashCreate (l);
2399 for (i = 0; i < l; i++) {
2400 cur = xmlXPathNodeSetItem(nodes, i);
2401 strval = xmlXPathCastNodeToString(cur);
2402 if (xmlHashLookup(hash, strval) == NULL) {
2403 xmlHashAddEntry(hash, strval, strval);
2404 xmlXPathNodeSetAddUnique(ret, cur);
2405 } else {
2406 xmlFree(strval);
2407 }
2408 }
2409 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2410 return(ret);
2411}
2412
2413/**
2414 * xmlXPathDistinct:
2415 * @nodes: a node-set
2416 *
2417 * Implements the EXSLT - Sets distinct() function:
2418 * node-set set:distinct (node-set)
2419 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2420 * is called with the sorted node-set
2421 *
2422 * Returns a subset of the nodes contained in @nodes, or @nodes if
2423 * it is empty
2424 */
2425xmlNodeSetPtr
2426xmlXPathDistinct (xmlNodeSetPtr nodes) {
2427 if (xmlXPathNodeSetIsEmpty(nodes))
2428 return(nodes);
2429
2430 xmlXPathNodeSetSort(nodes);
2431 return(xmlXPathDistinctSorted(nodes));
2432}
2433
2434/**
2435 * xmlXPathHasSameNodes:
2436 * @nodes1: a node-set
2437 * @nodes2: a node-set
2438 *
2439 * Implements the EXSLT - Sets has-same-nodes function:
2440 * boolean set:has-same-node(node-set, node-set)
2441 *
2442 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2443 * otherwise
2444 */
2445int
2446xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2447 int i, l;
2448 xmlNodePtr cur;
2449
2450 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2451 xmlXPathNodeSetIsEmpty(nodes2))
2452 return(0);
2453
2454 l = xmlXPathNodeSetGetLength(nodes1);
2455 for (i = 0; i < l; i++) {
2456 cur = xmlXPathNodeSetItem(nodes1, i);
2457 if (xmlXPathNodeSetContains(nodes2, cur))
2458 return(1);
2459 }
2460 return(0);
2461}
2462
2463/**
2464 * xmlXPathNodeLeadingSorted:
2465 * @nodes: a node-set, sorted by document order
2466 * @node: a node
2467 *
2468 * Implements the EXSLT - Sets leading() function:
2469 * node-set set:leading (node-set, node-set)
2470 *
2471 * Returns the nodes in @nodes that precede @node in document order,
2472 * @nodes if @node is NULL or an empty node-set if @nodes
2473 * doesn't contain @node
2474 */
2475xmlNodeSetPtr
2476xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2477 int i, l;
2478 xmlNodePtr cur;
2479 xmlNodeSetPtr ret;
2480
2481 if (node == NULL)
2482 return(nodes);
2483
2484 ret = xmlXPathNodeSetCreate(NULL);
2485 if (xmlXPathNodeSetIsEmpty(nodes) ||
2486 (!xmlXPathNodeSetContains(nodes, node)))
2487 return(ret);
2488
2489 l = xmlXPathNodeSetGetLength(nodes);
2490 for (i = 0; i < l; i++) {
2491 cur = xmlXPathNodeSetItem(nodes, i);
2492 if (cur == node)
2493 break;
2494 xmlXPathNodeSetAddUnique(ret, cur);
2495 }
2496 return(ret);
2497}
2498
2499/**
2500 * xmlXPathNodeLeading:
2501 * @nodes: a node-set
2502 * @node: a node
2503 *
2504 * Implements the EXSLT - Sets leading() function:
2505 * node-set set:leading (node-set, node-set)
2506 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2507 * is called.
2508 *
2509 * Returns the nodes in @nodes that precede @node in document order,
2510 * @nodes if @node is NULL or an empty node-set if @nodes
2511 * doesn't contain @node
2512 */
2513xmlNodeSetPtr
2514xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2515 xmlXPathNodeSetSort(nodes);
2516 return(xmlXPathNodeLeadingSorted(nodes, node));
2517}
2518
2519/**
2520 * xmlXPathLeadingSorted:
2521 * @nodes1: a node-set, sorted by document order
2522 * @nodes2: a node-set, sorted by document order
2523 *
2524 * Implements the EXSLT - Sets leading() function:
2525 * node-set set:leading (node-set, node-set)
2526 *
2527 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2528 * in document order, @nodes1 if @nodes2 is NULL or empty or
2529 * an empty node-set if @nodes1 doesn't contain @nodes2
2530 */
2531xmlNodeSetPtr
2532xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2533 if (xmlXPathNodeSetIsEmpty(nodes2))
2534 return(nodes1);
2535 return(xmlXPathNodeLeadingSorted(nodes1,
2536 xmlXPathNodeSetItem(nodes2, 1)));
2537}
2538
2539/**
2540 * xmlXPathLeading:
2541 * @nodes1: a node-set
2542 * @nodes2: a node-set
2543 *
2544 * Implements the EXSLT - Sets leading() function:
2545 * node-set set:leading (node-set, node-set)
2546 * @nodes1 and @nodes2 are sorted by document order, then
2547 * #exslSetsLeadingSorted is called.
2548 *
2549 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2550 * in document order, @nodes1 if @nodes2 is NULL or empty or
2551 * an empty node-set if @nodes1 doesn't contain @nodes2
2552 */
2553xmlNodeSetPtr
2554xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2555 if (xmlXPathNodeSetIsEmpty(nodes2))
2556 return(nodes1);
2557 if (xmlXPathNodeSetIsEmpty(nodes1))
2558 return(xmlXPathNodeSetCreate(NULL));
2559 xmlXPathNodeSetSort(nodes1);
2560 xmlXPathNodeSetSort(nodes2);
2561 return(xmlXPathNodeLeadingSorted(nodes1,
2562 xmlXPathNodeSetItem(nodes2, 1)));
2563}
2564
2565/**
2566 * xmlXPathNodeTrailingSorted:
2567 * @nodes: a node-set, sorted by document order
2568 * @node: a node
2569 *
2570 * Implements the EXSLT - Sets trailing() function:
2571 * node-set set:trailing (node-set, node-set)
2572 *
2573 * Returns the nodes in @nodes that follow @node in document order,
2574 * @nodes if @node is NULL or an empty node-set if @nodes
2575 * doesn't contain @node
2576 */
2577xmlNodeSetPtr
2578xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2579 int i, l;
2580 xmlNodePtr cur;
2581 xmlNodeSetPtr ret;
2582
2583 if (node == NULL)
2584 return(nodes);
2585
2586 ret = xmlXPathNodeSetCreate(NULL);
2587 if (xmlXPathNodeSetIsEmpty(nodes) ||
2588 (!xmlXPathNodeSetContains(nodes, node)))
2589 return(ret);
2590
2591 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002592 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002593 cur = xmlXPathNodeSetItem(nodes, i);
2594 if (cur == node)
2595 break;
2596 xmlXPathNodeSetAddUnique(ret, cur);
2597 }
2598 return(ret);
2599}
2600
2601/**
2602 * xmlXPathNodeTrailing:
2603 * @nodes: a node-set
2604 * @node: a node
2605 *
2606 * Implements the EXSLT - Sets trailing() function:
2607 * node-set set:trailing (node-set, node-set)
2608 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2609 * is called.
2610 *
2611 * Returns the nodes in @nodes that follow @node in document order,
2612 * @nodes if @node is NULL or an empty node-set if @nodes
2613 * doesn't contain @node
2614 */
2615xmlNodeSetPtr
2616xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2617 xmlXPathNodeSetSort(nodes);
2618 return(xmlXPathNodeTrailingSorted(nodes, node));
2619}
2620
2621/**
2622 * xmlXPathTrailingSorted:
2623 * @nodes1: a node-set, sorted by document order
2624 * @nodes2: a node-set, sorted by document order
2625 *
2626 * Implements the EXSLT - Sets trailing() function:
2627 * node-set set:trailing (node-set, node-set)
2628 *
2629 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2630 * in document order, @nodes1 if @nodes2 is NULL or empty or
2631 * an empty node-set if @nodes1 doesn't contain @nodes2
2632 */
2633xmlNodeSetPtr
2634xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2635 if (xmlXPathNodeSetIsEmpty(nodes2))
2636 return(nodes1);
2637 return(xmlXPathNodeTrailingSorted(nodes1,
2638 xmlXPathNodeSetItem(nodes2, 0)));
2639}
2640
2641/**
2642 * xmlXPathTrailing:
2643 * @nodes1: a node-set
2644 * @nodes2: a node-set
2645 *
2646 * Implements the EXSLT - Sets trailing() function:
2647 * node-set set:trailing (node-set, node-set)
2648 * @nodes1 and @nodes2 are sorted by document order, then
2649 * #xmlXPathTrailingSorted is called.
2650 *
2651 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2652 * in document order, @nodes1 if @nodes2 is NULL or empty or
2653 * an empty node-set if @nodes1 doesn't contain @nodes2
2654 */
2655xmlNodeSetPtr
2656xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2657 if (xmlXPathNodeSetIsEmpty(nodes2))
2658 return(nodes1);
2659 if (xmlXPathNodeSetIsEmpty(nodes1))
2660 return(xmlXPathNodeSetCreate(NULL));
2661 xmlXPathNodeSetSort(nodes1);
2662 xmlXPathNodeSetSort(nodes2);
2663 return(xmlXPathNodeTrailingSorted(nodes1,
2664 xmlXPathNodeSetItem(nodes2, 0)));
2665}
2666
Owen Taylor3473f882001-02-23 17:55:21 +00002667/************************************************************************
2668 * *
2669 * Routines to handle extra functions *
2670 * *
2671 ************************************************************************/
2672
2673/**
2674 * xmlXPathRegisterFunc:
2675 * @ctxt: the XPath context
2676 * @name: the function name
2677 * @f: the function implementation or NULL
2678 *
2679 * Register a new function. If @f is NULL it unregisters the function
2680 *
2681 * Returns 0 in case of success, -1 in case of error
2682 */
2683int
2684xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2685 xmlXPathFunction f) {
2686 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2687}
2688
2689/**
2690 * xmlXPathRegisterFuncNS:
2691 * @ctxt: the XPath context
2692 * @name: the function name
2693 * @ns_uri: the function namespace URI
2694 * @f: the function implementation or NULL
2695 *
2696 * Register a new function. If @f is NULL it unregisters the function
2697 *
2698 * Returns 0 in case of success, -1 in case of error
2699 */
2700int
2701xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2702 const xmlChar *ns_uri, xmlXPathFunction f) {
2703 if (ctxt == NULL)
2704 return(-1);
2705 if (name == NULL)
2706 return(-1);
2707
2708 if (ctxt->funcHash == NULL)
2709 ctxt->funcHash = xmlHashCreate(0);
2710 if (ctxt->funcHash == NULL)
2711 return(-1);
2712 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2713}
2714
2715/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002716 * xmlXPathRegisterFuncLookup:
2717 * @ctxt: the XPath context
2718 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002719 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002720 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002721 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002722 */
2723void
2724xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2725 xmlXPathFuncLookupFunc f,
2726 void *funcCtxt) {
2727 if (ctxt == NULL)
2728 return;
2729 ctxt->funcLookupFunc = (void *) f;
2730 ctxt->funcLookupData = funcCtxt;
2731}
2732
2733/**
Owen Taylor3473f882001-02-23 17:55:21 +00002734 * xmlXPathFunctionLookup:
2735 * @ctxt: the XPath context
2736 * @name: the function name
2737 *
2738 * Search in the Function array of the context for the given
2739 * function.
2740 *
2741 * Returns the xmlXPathFunction or NULL if not found
2742 */
2743xmlXPathFunction
2744xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002745 if (ctxt == NULL)
2746 return (NULL);
2747
2748 if (ctxt->funcLookupFunc != NULL) {
2749 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002750 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002751
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002752 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002753 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002754 if (ret != NULL)
2755 return(ret);
2756 }
Owen Taylor3473f882001-02-23 17:55:21 +00002757 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2758}
2759
2760/**
2761 * xmlXPathFunctionLookupNS:
2762 * @ctxt: the XPath context
2763 * @name: the function name
2764 * @ns_uri: the function namespace URI
2765 *
2766 * Search in the Function array of the context for the given
2767 * function.
2768 *
2769 * Returns the xmlXPathFunction or NULL if not found
2770 */
2771xmlXPathFunction
2772xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2773 const xmlChar *ns_uri) {
2774 if (ctxt == NULL)
2775 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002776 if (name == NULL)
2777 return(NULL);
2778
Thomas Broyerba4ad322001-07-26 16:55:21 +00002779 if (ctxt->funcLookupFunc != NULL) {
2780 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002781 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002782
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002783 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002784 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002785 if (ret != NULL)
2786 return(ret);
2787 }
2788
2789 if (ctxt->funcHash == NULL)
2790 return(NULL);
2791
Owen Taylor3473f882001-02-23 17:55:21 +00002792 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2793}
2794
2795/**
2796 * xmlXPathRegisteredFuncsCleanup:
2797 * @ctxt: the XPath context
2798 *
2799 * Cleanup the XPath context data associated to registered functions
2800 */
2801void
2802xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2803 if (ctxt == NULL)
2804 return;
2805
2806 xmlHashFree(ctxt->funcHash, NULL);
2807 ctxt->funcHash = NULL;
2808}
2809
2810/************************************************************************
2811 * *
2812 * Routines to handle Variable *
2813 * *
2814 ************************************************************************/
2815
2816/**
2817 * xmlXPathRegisterVariable:
2818 * @ctxt: the XPath context
2819 * @name: the variable name
2820 * @value: the variable value or NULL
2821 *
2822 * Register a new variable value. If @value is NULL it unregisters
2823 * the variable
2824 *
2825 * Returns 0 in case of success, -1 in case of error
2826 */
2827int
2828xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2829 xmlXPathObjectPtr value) {
2830 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2831}
2832
2833/**
2834 * xmlXPathRegisterVariableNS:
2835 * @ctxt: the XPath context
2836 * @name: the variable name
2837 * @ns_uri: the variable namespace URI
2838 * @value: the variable value or NULL
2839 *
2840 * Register a new variable value. If @value is NULL it unregisters
2841 * the variable
2842 *
2843 * Returns 0 in case of success, -1 in case of error
2844 */
2845int
2846xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2847 const xmlChar *ns_uri,
2848 xmlXPathObjectPtr value) {
2849 if (ctxt == NULL)
2850 return(-1);
2851 if (name == NULL)
2852 return(-1);
2853
2854 if (ctxt->varHash == NULL)
2855 ctxt->varHash = xmlHashCreate(0);
2856 if (ctxt->varHash == NULL)
2857 return(-1);
2858 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2859 (void *) value,
2860 (xmlHashDeallocator)xmlXPathFreeObject));
2861}
2862
2863/**
2864 * xmlXPathRegisterVariableLookup:
2865 * @ctxt: the XPath context
2866 * @f: the lookup function
2867 * @data: the lookup data
2868 *
2869 * register an external mechanism to do variable lookup
2870 */
2871void
2872xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2873 xmlXPathVariableLookupFunc f, void *data) {
2874 if (ctxt == NULL)
2875 return;
2876 ctxt->varLookupFunc = (void *) f;
2877 ctxt->varLookupData = data;
2878}
2879
2880/**
2881 * xmlXPathVariableLookup:
2882 * @ctxt: the XPath context
2883 * @name: the variable name
2884 *
2885 * Search in the Variable array of the context for the given
2886 * variable value.
2887 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002888 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002889 */
2890xmlXPathObjectPtr
2891xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2892 if (ctxt == NULL)
2893 return(NULL);
2894
2895 if (ctxt->varLookupFunc != NULL) {
2896 xmlXPathObjectPtr ret;
2897
2898 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2899 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002900 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002901 }
2902 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2903}
2904
2905/**
2906 * xmlXPathVariableLookupNS:
2907 * @ctxt: the XPath context
2908 * @name: the variable name
2909 * @ns_uri: the variable namespace URI
2910 *
2911 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002912 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002913 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002914 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002915 */
2916xmlXPathObjectPtr
2917xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2918 const xmlChar *ns_uri) {
2919 if (ctxt == NULL)
2920 return(NULL);
2921
2922 if (ctxt->varLookupFunc != NULL) {
2923 xmlXPathObjectPtr ret;
2924
2925 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2926 (ctxt->varLookupData, name, ns_uri);
2927 if (ret != NULL) return(ret);
2928 }
2929
2930 if (ctxt->varHash == NULL)
2931 return(NULL);
2932 if (name == NULL)
2933 return(NULL);
2934
Daniel Veillard8c357d52001-07-03 23:43:33 +00002935 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2936 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002937}
2938
2939/**
2940 * xmlXPathRegisteredVariablesCleanup:
2941 * @ctxt: the XPath context
2942 *
2943 * Cleanup the XPath context data associated to registered variables
2944 */
2945void
2946xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2947 if (ctxt == NULL)
2948 return;
2949
Daniel Veillard76d66f42001-05-16 21:05:17 +00002950 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002951 ctxt->varHash = NULL;
2952}
2953
2954/**
2955 * xmlXPathRegisterNs:
2956 * @ctxt: the XPath context
2957 * @prefix: the namespace prefix
2958 * @ns_uri: the namespace name
2959 *
2960 * Register a new namespace. If @ns_uri is NULL it unregisters
2961 * the namespace
2962 *
2963 * Returns 0 in case of success, -1 in case of error
2964 */
2965int
2966xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2967 const xmlChar *ns_uri) {
2968 if (ctxt == NULL)
2969 return(-1);
2970 if (prefix == NULL)
2971 return(-1);
2972
2973 if (ctxt->nsHash == NULL)
2974 ctxt->nsHash = xmlHashCreate(10);
2975 if (ctxt->nsHash == NULL)
2976 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00002977 if (ns_uri == NULL)
2978 return(xmlHashRemoveEntry(ctxt->nsHash, ns_uri,
2979 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00002980 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002981 (xmlHashDeallocator)xmlFree));
2982}
2983
2984/**
2985 * xmlXPathNsLookup:
2986 * @ctxt: the XPath context
2987 * @prefix: the namespace prefix value
2988 *
2989 * Search in the namespace declaration array of the context for the given
2990 * namespace name associated to the given prefix
2991 *
2992 * Returns the value or NULL if not found
2993 */
2994const xmlChar *
2995xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2996 if (ctxt == NULL)
2997 return(NULL);
2998 if (prefix == NULL)
2999 return(NULL);
3000
3001#ifdef XML_XML_NAMESPACE
3002 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3003 return(XML_XML_NAMESPACE);
3004#endif
3005
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003006 if (ctxt->namespaces != NULL) {
3007 int i;
3008
3009 for (i = 0;i < ctxt->nsNr;i++) {
3010 if ((ctxt->namespaces[i] != NULL) &&
3011 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3012 return(ctxt->namespaces[i]->href);
3013 }
3014 }
Owen Taylor3473f882001-02-23 17:55:21 +00003015
3016 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3017}
3018
3019/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003020 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003021 * @ctxt: the XPath context
3022 *
3023 * Cleanup the XPath context data associated to registered variables
3024 */
3025void
3026xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3027 if (ctxt == NULL)
3028 return;
3029
Daniel Veillard42766c02002-08-22 20:52:17 +00003030 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003031 ctxt->nsHash = NULL;
3032}
3033
3034/************************************************************************
3035 * *
3036 * Routines to handle Values *
3037 * *
3038 ************************************************************************/
3039
3040/* Allocations are terrible, one need to optimize all this !!! */
3041
3042/**
3043 * xmlXPathNewFloat:
3044 * @val: the double value
3045 *
3046 * Create a new xmlXPathObjectPtr of type double and of value @val
3047 *
3048 * Returns the newly created object.
3049 */
3050xmlXPathObjectPtr
3051xmlXPathNewFloat(double val) {
3052 xmlXPathObjectPtr ret;
3053
3054 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3055 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003056 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003057 return(NULL);
3058 }
3059 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3060 ret->type = XPATH_NUMBER;
3061 ret->floatval = val;
3062 return(ret);
3063}
3064
3065/**
3066 * xmlXPathNewBoolean:
3067 * @val: the boolean value
3068 *
3069 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3070 *
3071 * Returns the newly created object.
3072 */
3073xmlXPathObjectPtr
3074xmlXPathNewBoolean(int val) {
3075 xmlXPathObjectPtr ret;
3076
3077 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3078 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003079 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003080 return(NULL);
3081 }
3082 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3083 ret->type = XPATH_BOOLEAN;
3084 ret->boolval = (val != 0);
3085 return(ret);
3086}
3087
3088/**
3089 * xmlXPathNewString:
3090 * @val: the xmlChar * value
3091 *
3092 * Create a new xmlXPathObjectPtr of type string and of value @val
3093 *
3094 * Returns the newly created object.
3095 */
3096xmlXPathObjectPtr
3097xmlXPathNewString(const xmlChar *val) {
3098 xmlXPathObjectPtr ret;
3099
3100 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3101 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003102 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003103 return(NULL);
3104 }
3105 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3106 ret->type = XPATH_STRING;
3107 if (val != NULL)
3108 ret->stringval = xmlStrdup(val);
3109 else
3110 ret->stringval = xmlStrdup((const xmlChar *)"");
3111 return(ret);
3112}
3113
3114/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003115 * xmlXPathWrapString:
3116 * @val: the xmlChar * value
3117 *
3118 * Wraps the @val string into an XPath object.
3119 *
3120 * Returns the newly created object.
3121 */
3122xmlXPathObjectPtr
3123xmlXPathWrapString (xmlChar *val) {
3124 xmlXPathObjectPtr ret;
3125
3126 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3127 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003128 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003129 return(NULL);
3130 }
3131 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3132 ret->type = XPATH_STRING;
3133 ret->stringval = val;
3134 return(ret);
3135}
3136
3137/**
Owen Taylor3473f882001-02-23 17:55:21 +00003138 * xmlXPathNewCString:
3139 * @val: the char * value
3140 *
3141 * Create a new xmlXPathObjectPtr of type string and of value @val
3142 *
3143 * Returns the newly created object.
3144 */
3145xmlXPathObjectPtr
3146xmlXPathNewCString(const char *val) {
3147 xmlXPathObjectPtr ret;
3148
3149 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3150 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003151 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003152 return(NULL);
3153 }
3154 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3155 ret->type = XPATH_STRING;
3156 ret->stringval = xmlStrdup(BAD_CAST val);
3157 return(ret);
3158}
3159
3160/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003161 * xmlXPathWrapCString:
3162 * @val: the char * value
3163 *
3164 * Wraps a string into an XPath object.
3165 *
3166 * Returns the newly created object.
3167 */
3168xmlXPathObjectPtr
3169xmlXPathWrapCString (char * val) {
3170 return(xmlXPathWrapString((xmlChar *)(val)));
3171}
3172
3173/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003174 * xmlXPathWrapExternal:
3175 * @val: the user data
3176 *
3177 * Wraps the @val data into an XPath object.
3178 *
3179 * Returns the newly created object.
3180 */
3181xmlXPathObjectPtr
3182xmlXPathWrapExternal (void *val) {
3183 xmlXPathObjectPtr ret;
3184
3185 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3186 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003187 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003188 return(NULL);
3189 }
3190 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3191 ret->type = XPATH_USERS;
3192 ret->user = val;
3193 return(ret);
3194}
3195
3196/**
Owen Taylor3473f882001-02-23 17:55:21 +00003197 * xmlXPathObjectCopy:
3198 * @val: the original object
3199 *
3200 * allocate a new copy of a given object
3201 *
3202 * Returns the newly created object.
3203 */
3204xmlXPathObjectPtr
3205xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3206 xmlXPathObjectPtr ret;
3207
3208 if (val == NULL)
3209 return(NULL);
3210
3211 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3212 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003213 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003214 return(NULL);
3215 }
3216 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3217 switch (val->type) {
3218 case XPATH_BOOLEAN:
3219 case XPATH_NUMBER:
3220 case XPATH_POINT:
3221 case XPATH_RANGE:
3222 break;
3223 case XPATH_STRING:
3224 ret->stringval = xmlStrdup(val->stringval);
3225 break;
3226 case XPATH_XSLT_TREE:
3227 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003228 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003229 xmlNodePtr cur, tmp;
3230 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003231
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003232 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003233 top = xmlNewDoc(NULL);
3234 top->name = (char *)
3235 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003236 ret->user = top;
3237 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003238 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003239 cur = val->nodesetval->nodeTab[0]->children;
3240 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003241 tmp = xmlDocCopyNode(cur, top, 1);
3242 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003243 cur = cur->next;
3244 }
3245 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003246 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003247 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003248 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003249 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003250 break;
3251 case XPATH_NODESET:
3252 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003253 /* Do not deallocate the copied tree value */
3254 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003255 break;
3256 case XPATH_LOCATIONSET:
3257#ifdef LIBXML_XPTR_ENABLED
3258 {
3259 xmlLocationSetPtr loc = val->user;
3260 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3261 break;
3262 }
3263#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003264 case XPATH_USERS:
3265 ret->user = val->user;
3266 break;
3267 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003268 xmlGenericError(xmlGenericErrorContext,
3269 "xmlXPathObjectCopy: unsupported type %d\n",
3270 val->type);
3271 break;
3272 }
3273 return(ret);
3274}
3275
3276/**
3277 * xmlXPathFreeObject:
3278 * @obj: the object to free
3279 *
3280 * Free up an xmlXPathObjectPtr object.
3281 */
3282void
3283xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3284 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003285 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003286 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003287 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003288 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003289 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003290 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003291 xmlXPathFreeValueTree(obj->nodesetval);
3292 } else {
3293 if (obj->nodesetval != NULL)
3294 xmlXPathFreeNodeSet(obj->nodesetval);
3295 }
Owen Taylor3473f882001-02-23 17:55:21 +00003296#ifdef LIBXML_XPTR_ENABLED
3297 } else if (obj->type == XPATH_LOCATIONSET) {
3298 if (obj->user != NULL)
3299 xmlXPtrFreeLocationSet(obj->user);
3300#endif
3301 } else if (obj->type == XPATH_STRING) {
3302 if (obj->stringval != NULL)
3303 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003304 }
3305
Owen Taylor3473f882001-02-23 17:55:21 +00003306 xmlFree(obj);
3307}
3308
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003309
3310/************************************************************************
3311 * *
3312 * Type Casting Routines *
3313 * *
3314 ************************************************************************/
3315
3316/**
3317 * xmlXPathCastBooleanToString:
3318 * @val: a boolean
3319 *
3320 * Converts a boolean to its string value.
3321 *
3322 * Returns a newly allocated string.
3323 */
3324xmlChar *
3325xmlXPathCastBooleanToString (int val) {
3326 xmlChar *ret;
3327 if (val)
3328 ret = xmlStrdup((const xmlChar *) "true");
3329 else
3330 ret = xmlStrdup((const xmlChar *) "false");
3331 return(ret);
3332}
3333
3334/**
3335 * xmlXPathCastNumberToString:
3336 * @val: a number
3337 *
3338 * Converts a number to its string value.
3339 *
3340 * Returns a newly allocated string.
3341 */
3342xmlChar *
3343xmlXPathCastNumberToString (double val) {
3344 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003345 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003346 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003347 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003348 break;
3349 case -1:
3350 ret = xmlStrdup((const xmlChar *) "-Infinity");
3351 break;
3352 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003353 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003354 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003355 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3356 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003357 } else {
3358 /* could be improved */
3359 char buf[100];
3360 xmlXPathFormatNumber(val, buf, 100);
3361 ret = xmlStrdup((const xmlChar *) buf);
3362 }
3363 }
3364 return(ret);
3365}
3366
3367/**
3368 * xmlXPathCastNodeToString:
3369 * @node: a node
3370 *
3371 * Converts a node to its string value.
3372 *
3373 * Returns a newly allocated string.
3374 */
3375xmlChar *
3376xmlXPathCastNodeToString (xmlNodePtr node) {
3377 return(xmlNodeGetContent(node));
3378}
3379
3380/**
3381 * xmlXPathCastNodeSetToString:
3382 * @ns: a node-set
3383 *
3384 * Converts a node-set to its string value.
3385 *
3386 * Returns a newly allocated string.
3387 */
3388xmlChar *
3389xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3390 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3391 return(xmlStrdup((const xmlChar *) ""));
3392
3393 xmlXPathNodeSetSort(ns);
3394 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3395}
3396
3397/**
3398 * xmlXPathCastToString:
3399 * @val: an XPath object
3400 *
3401 * Converts an existing object to its string() equivalent
3402 *
3403 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003404 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003405 * string object).
3406 */
3407xmlChar *
3408xmlXPathCastToString(xmlXPathObjectPtr val) {
3409 xmlChar *ret = NULL;
3410
3411 if (val == NULL)
3412 return(xmlStrdup((const xmlChar *) ""));
3413 switch (val->type) {
3414 case XPATH_UNDEFINED:
3415#ifdef DEBUG_EXPR
3416 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3417#endif
3418 ret = xmlStrdup((const xmlChar *) "");
3419 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003420 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003421 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003422 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3423 break;
3424 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003425 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003426 case XPATH_BOOLEAN:
3427 ret = xmlXPathCastBooleanToString(val->boolval);
3428 break;
3429 case XPATH_NUMBER: {
3430 ret = xmlXPathCastNumberToString(val->floatval);
3431 break;
3432 }
3433 case XPATH_USERS:
3434 case XPATH_POINT:
3435 case XPATH_RANGE:
3436 case XPATH_LOCATIONSET:
3437 TODO
3438 ret = xmlStrdup((const xmlChar *) "");
3439 break;
3440 }
3441 return(ret);
3442}
3443
3444/**
3445 * xmlXPathConvertString:
3446 * @val: an XPath object
3447 *
3448 * Converts an existing object to its string() equivalent
3449 *
3450 * Returns the new object, the old one is freed (or the operation
3451 * is done directly on @val)
3452 */
3453xmlXPathObjectPtr
3454xmlXPathConvertString(xmlXPathObjectPtr val) {
3455 xmlChar *res = NULL;
3456
3457 if (val == NULL)
3458 return(xmlXPathNewCString(""));
3459
3460 switch (val->type) {
3461 case XPATH_UNDEFINED:
3462#ifdef DEBUG_EXPR
3463 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3464#endif
3465 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003466 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003467 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003468 res = xmlXPathCastNodeSetToString(val->nodesetval);
3469 break;
3470 case XPATH_STRING:
3471 return(val);
3472 case XPATH_BOOLEAN:
3473 res = xmlXPathCastBooleanToString(val->boolval);
3474 break;
3475 case XPATH_NUMBER:
3476 res = xmlXPathCastNumberToString(val->floatval);
3477 break;
3478 case XPATH_USERS:
3479 case XPATH_POINT:
3480 case XPATH_RANGE:
3481 case XPATH_LOCATIONSET:
3482 TODO;
3483 break;
3484 }
3485 xmlXPathFreeObject(val);
3486 if (res == NULL)
3487 return(xmlXPathNewCString(""));
3488 return(xmlXPathWrapString(res));
3489}
3490
3491/**
3492 * xmlXPathCastBooleanToNumber:
3493 * @val: a boolean
3494 *
3495 * Converts a boolean to its number value
3496 *
3497 * Returns the number value
3498 */
3499double
3500xmlXPathCastBooleanToNumber(int val) {
3501 if (val)
3502 return(1.0);
3503 return(0.0);
3504}
3505
3506/**
3507 * xmlXPathCastStringToNumber:
3508 * @val: a string
3509 *
3510 * Converts a string to its number value
3511 *
3512 * Returns the number value
3513 */
3514double
3515xmlXPathCastStringToNumber(const xmlChar * val) {
3516 return(xmlXPathStringEvalNumber(val));
3517}
3518
3519/**
3520 * xmlXPathCastNodeToNumber:
3521 * @node: a node
3522 *
3523 * Converts a node to its number value
3524 *
3525 * Returns the number value
3526 */
3527double
3528xmlXPathCastNodeToNumber (xmlNodePtr node) {
3529 xmlChar *strval;
3530 double ret;
3531
3532 if (node == NULL)
3533 return(xmlXPathNAN);
3534 strval = xmlXPathCastNodeToString(node);
3535 if (strval == NULL)
3536 return(xmlXPathNAN);
3537 ret = xmlXPathCastStringToNumber(strval);
3538 xmlFree(strval);
3539
3540 return(ret);
3541}
3542
3543/**
3544 * xmlXPathCastNodeSetToNumber:
3545 * @ns: a node-set
3546 *
3547 * Converts a node-set to its number value
3548 *
3549 * Returns the number value
3550 */
3551double
3552xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3553 xmlChar *str;
3554 double ret;
3555
3556 if (ns == NULL)
3557 return(xmlXPathNAN);
3558 str = xmlXPathCastNodeSetToString(ns);
3559 ret = xmlXPathCastStringToNumber(str);
3560 xmlFree(str);
3561 return(ret);
3562}
3563
3564/**
3565 * xmlXPathCastToNumber:
3566 * @val: an XPath object
3567 *
3568 * Converts an XPath object to its number value
3569 *
3570 * Returns the number value
3571 */
3572double
3573xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3574 double ret = 0.0;
3575
3576 if (val == NULL)
3577 return(xmlXPathNAN);
3578 switch (val->type) {
3579 case XPATH_UNDEFINED:
3580#ifdef DEGUB_EXPR
3581 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3582#endif
3583 ret = xmlXPathNAN;
3584 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003585 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003586 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003587 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3588 break;
3589 case XPATH_STRING:
3590 ret = xmlXPathCastStringToNumber(val->stringval);
3591 break;
3592 case XPATH_NUMBER:
3593 ret = val->floatval;
3594 break;
3595 case XPATH_BOOLEAN:
3596 ret = xmlXPathCastBooleanToNumber(val->boolval);
3597 break;
3598 case XPATH_USERS:
3599 case XPATH_POINT:
3600 case XPATH_RANGE:
3601 case XPATH_LOCATIONSET:
3602 TODO;
3603 ret = xmlXPathNAN;
3604 break;
3605 }
3606 return(ret);
3607}
3608
3609/**
3610 * xmlXPathConvertNumber:
3611 * @val: an XPath object
3612 *
3613 * Converts an existing object to its number() equivalent
3614 *
3615 * Returns the new object, the old one is freed (or the operation
3616 * is done directly on @val)
3617 */
3618xmlXPathObjectPtr
3619xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3620 xmlXPathObjectPtr ret;
3621
3622 if (val == NULL)
3623 return(xmlXPathNewFloat(0.0));
3624 if (val->type == XPATH_NUMBER)
3625 return(val);
3626 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3627 xmlXPathFreeObject(val);
3628 return(ret);
3629}
3630
3631/**
3632 * xmlXPathCastNumberToBoolean:
3633 * @val: a number
3634 *
3635 * Converts a number to its boolean value
3636 *
3637 * Returns the boolean value
3638 */
3639int
3640xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003641 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003642 return(0);
3643 return(1);
3644}
3645
3646/**
3647 * xmlXPathCastStringToBoolean:
3648 * @val: a string
3649 *
3650 * Converts a string to its boolean value
3651 *
3652 * Returns the boolean value
3653 */
3654int
3655xmlXPathCastStringToBoolean (const xmlChar *val) {
3656 if ((val == NULL) || (xmlStrlen(val) == 0))
3657 return(0);
3658 return(1);
3659}
3660
3661/**
3662 * xmlXPathCastNodeSetToBoolean:
3663 * @ns: a node-set
3664 *
3665 * Converts a node-set to its boolean value
3666 *
3667 * Returns the boolean value
3668 */
3669int
3670xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3671 if ((ns == NULL) || (ns->nodeNr == 0))
3672 return(0);
3673 return(1);
3674}
3675
3676/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003677 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003678 * @val: an XPath object
3679 *
3680 * Converts an XPath object to its boolean value
3681 *
3682 * Returns the boolean value
3683 */
3684int
3685xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3686 int ret = 0;
3687
3688 if (val == NULL)
3689 return(0);
3690 switch (val->type) {
3691 case XPATH_UNDEFINED:
3692#ifdef DEBUG_EXPR
3693 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3694#endif
3695 ret = 0;
3696 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003697 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003698 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003699 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3700 break;
3701 case XPATH_STRING:
3702 ret = xmlXPathCastStringToBoolean(val->stringval);
3703 break;
3704 case XPATH_NUMBER:
3705 ret = xmlXPathCastNumberToBoolean(val->floatval);
3706 break;
3707 case XPATH_BOOLEAN:
3708 ret = val->boolval;
3709 break;
3710 case XPATH_USERS:
3711 case XPATH_POINT:
3712 case XPATH_RANGE:
3713 case XPATH_LOCATIONSET:
3714 TODO;
3715 ret = 0;
3716 break;
3717 }
3718 return(ret);
3719}
3720
3721
3722/**
3723 * xmlXPathConvertBoolean:
3724 * @val: an XPath object
3725 *
3726 * Converts an existing object to its boolean() equivalent
3727 *
3728 * Returns the new object, the old one is freed (or the operation
3729 * is done directly on @val)
3730 */
3731xmlXPathObjectPtr
3732xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3733 xmlXPathObjectPtr ret;
3734
3735 if (val == NULL)
3736 return(xmlXPathNewBoolean(0));
3737 if (val->type == XPATH_BOOLEAN)
3738 return(val);
3739 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3740 xmlXPathFreeObject(val);
3741 return(ret);
3742}
3743
Owen Taylor3473f882001-02-23 17:55:21 +00003744/************************************************************************
3745 * *
3746 * Routines to handle XPath contexts *
3747 * *
3748 ************************************************************************/
3749
3750/**
3751 * xmlXPathNewContext:
3752 * @doc: the XML document
3753 *
3754 * Create a new xmlXPathContext
3755 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003756 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003757 */
3758xmlXPathContextPtr
3759xmlXPathNewContext(xmlDocPtr doc) {
3760 xmlXPathContextPtr ret;
3761
3762 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3763 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003764 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003765 return(NULL);
3766 }
3767 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3768 ret->doc = doc;
3769 ret->node = NULL;
3770
3771 ret->varHash = NULL;
3772
3773 ret->nb_types = 0;
3774 ret->max_types = 0;
3775 ret->types = NULL;
3776
3777 ret->funcHash = xmlHashCreate(0);
3778
3779 ret->nb_axis = 0;
3780 ret->max_axis = 0;
3781 ret->axis = NULL;
3782
3783 ret->nsHash = NULL;
3784 ret->user = NULL;
3785
3786 ret->contextSize = -1;
3787 ret->proximityPosition = -1;
3788
3789 xmlXPathRegisterAllFunctions(ret);
3790
3791 return(ret);
3792}
3793
3794/**
3795 * xmlXPathFreeContext:
3796 * @ctxt: the context to free
3797 *
3798 * Free up an xmlXPathContext
3799 */
3800void
3801xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3802 xmlXPathRegisteredNsCleanup(ctxt);
3803 xmlXPathRegisteredFuncsCleanup(ctxt);
3804 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003805 xmlFree(ctxt);
3806}
3807
3808/************************************************************************
3809 * *
3810 * Routines to handle XPath parser contexts *
3811 * *
3812 ************************************************************************/
3813
3814#define CHECK_CTXT(ctxt) \
3815 if (ctxt == NULL) { \
3816 xmlGenericError(xmlGenericErrorContext, \
3817 "%s:%d Internal error: ctxt == NULL\n", \
3818 __FILE__, __LINE__); \
3819 } \
3820
3821
3822#define CHECK_CONTEXT(ctxt) \
3823 if (ctxt == NULL) { \
3824 xmlGenericError(xmlGenericErrorContext, \
3825 "%s:%d Internal error: no context\n", \
3826 __FILE__, __LINE__); \
3827 } \
3828 else if (ctxt->doc == NULL) { \
3829 xmlGenericError(xmlGenericErrorContext, \
3830 "%s:%d Internal error: no document\n", \
3831 __FILE__, __LINE__); \
3832 } \
3833 else if (ctxt->doc->children == NULL) { \
3834 xmlGenericError(xmlGenericErrorContext, \
3835 "%s:%d Internal error: document without root\n", \
3836 __FILE__, __LINE__); \
3837 } \
3838
3839
3840/**
3841 * xmlXPathNewParserContext:
3842 * @str: the XPath expression
3843 * @ctxt: the XPath context
3844 *
3845 * Create a new xmlXPathParserContext
3846 *
3847 * Returns the xmlXPathParserContext just allocated.
3848 */
3849xmlXPathParserContextPtr
3850xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3851 xmlXPathParserContextPtr ret;
3852
3853 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3854 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003855 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003856 return(NULL);
3857 }
3858 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3859 ret->cur = ret->base = str;
3860 ret->context = ctxt;
3861
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003862 ret->comp = xmlXPathNewCompExpr();
3863 if (ret->comp == NULL) {
3864 xmlFree(ret->valueTab);
3865 xmlFree(ret);
3866 return(NULL);
3867 }
3868
3869 return(ret);
3870}
3871
3872/**
3873 * xmlXPathCompParserContext:
3874 * @comp: the XPath compiled expression
3875 * @ctxt: the XPath context
3876 *
3877 * Create a new xmlXPathParserContext when processing a compiled expression
3878 *
3879 * Returns the xmlXPathParserContext just allocated.
3880 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003881static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003882xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3883 xmlXPathParserContextPtr ret;
3884
3885 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3886 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003887 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003888 return(NULL);
3889 }
3890 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3891
Owen Taylor3473f882001-02-23 17:55:21 +00003892 /* Allocate the value stack */
3893 ret->valueTab = (xmlXPathObjectPtr *)
3894 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003895 if (ret->valueTab == NULL) {
3896 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003897 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003898 return(NULL);
3899 }
Owen Taylor3473f882001-02-23 17:55:21 +00003900 ret->valueNr = 0;
3901 ret->valueMax = 10;
3902 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003903
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003904 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003905 ret->comp = comp;
3906
Owen Taylor3473f882001-02-23 17:55:21 +00003907 return(ret);
3908}
3909
3910/**
3911 * xmlXPathFreeParserContext:
3912 * @ctxt: the context to free
3913 *
3914 * Free up an xmlXPathParserContext
3915 */
3916void
3917xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3918 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003919 xmlFree(ctxt->valueTab);
3920 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003921 if (ctxt->comp)
3922 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003923 xmlFree(ctxt);
3924}
3925
3926/************************************************************************
3927 * *
3928 * The implicit core function library *
3929 * *
3930 ************************************************************************/
3931
Owen Taylor3473f882001-02-23 17:55:21 +00003932/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003933 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003934 * @node: a node pointer
3935 *
3936 * Function computing the beginning of the string value of the node,
3937 * used to speed up comparisons
3938 *
3939 * Returns an int usable as a hash
3940 */
3941static unsigned int
3942xmlXPathNodeValHash(xmlNodePtr node) {
3943 int len = 2;
3944 const xmlChar * string = NULL;
3945 xmlNodePtr tmp = NULL;
3946 unsigned int ret = 0;
3947
3948 if (node == NULL)
3949 return(0);
3950
Daniel Veillard9adc0462003-03-24 18:39:54 +00003951 if (node->type == XML_DOCUMENT_NODE) {
3952 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3953 if (tmp == NULL)
3954 node = node->children;
3955 else
3956 node = tmp;
3957
3958 if (node == NULL)
3959 return(0);
3960 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003961
3962 switch (node->type) {
3963 case XML_COMMENT_NODE:
3964 case XML_PI_NODE:
3965 case XML_CDATA_SECTION_NODE:
3966 case XML_TEXT_NODE:
3967 string = node->content;
3968 if (string == NULL)
3969 return(0);
3970 if (string[0] == 0)
3971 return(0);
3972 return(((unsigned int) string[0]) +
3973 (((unsigned int) string[1]) << 8));
3974 case XML_NAMESPACE_DECL:
3975 string = ((xmlNsPtr)node)->href;
3976 if (string == NULL)
3977 return(0);
3978 if (string[0] == 0)
3979 return(0);
3980 return(((unsigned int) string[0]) +
3981 (((unsigned int) string[1]) << 8));
3982 case XML_ATTRIBUTE_NODE:
3983 tmp = ((xmlAttrPtr) node)->children;
3984 break;
3985 case XML_ELEMENT_NODE:
3986 tmp = node->children;
3987 break;
3988 default:
3989 return(0);
3990 }
3991 while (tmp != NULL) {
3992 switch (tmp->type) {
3993 case XML_COMMENT_NODE:
3994 case XML_PI_NODE:
3995 case XML_CDATA_SECTION_NODE:
3996 case XML_TEXT_NODE:
3997 string = tmp->content;
3998 break;
3999 case XML_NAMESPACE_DECL:
4000 string = ((xmlNsPtr)tmp)->href;
4001 break;
4002 default:
4003 break;
4004 }
4005 if ((string != NULL) && (string[0] != 0)) {
4006 if (string[0] == 0)
4007 return(0);
4008 if (len == 1) {
4009 return(ret + (((unsigned int) string[0]) << 8));
4010 }
4011 if (string[1] == 0) {
4012 len = 1;
4013 ret = (unsigned int) string[0];
4014 } else {
4015 return(((unsigned int) string[0]) +
4016 (((unsigned int) string[1]) << 8));
4017 }
4018 }
4019 /*
4020 * Skip to next node
4021 */
4022 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4023 if (tmp->children->type != XML_ENTITY_DECL) {
4024 tmp = tmp->children;
4025 continue;
4026 }
4027 }
4028 if (tmp == node)
4029 break;
4030
4031 if (tmp->next != NULL) {
4032 tmp = tmp->next;
4033 continue;
4034 }
4035
4036 do {
4037 tmp = tmp->parent;
4038 if (tmp == NULL)
4039 break;
4040 if (tmp == node) {
4041 tmp = NULL;
4042 break;
4043 }
4044 if (tmp->next != NULL) {
4045 tmp = tmp->next;
4046 break;
4047 }
4048 } while (tmp != NULL);
4049 }
4050 return(ret);
4051}
4052
4053/**
4054 * xmlXPathStringHash:
4055 * @string: a string
4056 *
4057 * Function computing the beginning of the string value of the node,
4058 * used to speed up comparisons
4059 *
4060 * Returns an int usable as a hash
4061 */
4062static unsigned int
4063xmlXPathStringHash(const xmlChar * string) {
4064 if (string == NULL)
4065 return((unsigned int) 0);
4066 if (string[0] == 0)
4067 return(0);
4068 return(((unsigned int) string[0]) +
4069 (((unsigned int) string[1]) << 8));
4070}
4071
4072/**
Owen Taylor3473f882001-02-23 17:55:21 +00004073 * xmlXPathCompareNodeSetFloat:
4074 * @ctxt: the XPath Parser context
4075 * @inf: less than (1) or greater than (0)
4076 * @strict: is the comparison strict
4077 * @arg: the node set
4078 * @f: the value
4079 *
4080 * Implement the compare operation between a nodeset and a number
4081 * @ns < @val (1, 1, ...
4082 * @ns <= @val (1, 0, ...
4083 * @ns > @val (0, 1, ...
4084 * @ns >= @val (0, 0, ...
4085 *
4086 * If one object to be compared is a node-set and the other is a number,
4087 * then the comparison will be true if and only if there is a node in the
4088 * node-set such that the result of performing the comparison on the number
4089 * to be compared and on the result of converting the string-value of that
4090 * node to a number using the number function is true.
4091 *
4092 * Returns 0 or 1 depending on the results of the test.
4093 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004094static int
Owen Taylor3473f882001-02-23 17:55:21 +00004095xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4096 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4097 int i, ret = 0;
4098 xmlNodeSetPtr ns;
4099 xmlChar *str2;
4100
4101 if ((f == NULL) || (arg == NULL) ||
4102 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4103 xmlXPathFreeObject(arg);
4104 xmlXPathFreeObject(f);
4105 return(0);
4106 }
4107 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004108 if (ns != NULL) {
4109 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004110 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004111 if (str2 != NULL) {
4112 valuePush(ctxt,
4113 xmlXPathNewString(str2));
4114 xmlFree(str2);
4115 xmlXPathNumberFunction(ctxt, 1);
4116 valuePush(ctxt, xmlXPathObjectCopy(f));
4117 ret = xmlXPathCompareValues(ctxt, inf, strict);
4118 if (ret)
4119 break;
4120 }
4121 }
Owen Taylor3473f882001-02-23 17:55:21 +00004122 }
4123 xmlXPathFreeObject(arg);
4124 xmlXPathFreeObject(f);
4125 return(ret);
4126}
4127
4128/**
4129 * xmlXPathCompareNodeSetString:
4130 * @ctxt: the XPath Parser context
4131 * @inf: less than (1) or greater than (0)
4132 * @strict: is the comparison strict
4133 * @arg: the node set
4134 * @s: the value
4135 *
4136 * Implement the compare operation between a nodeset and a string
4137 * @ns < @val (1, 1, ...
4138 * @ns <= @val (1, 0, ...
4139 * @ns > @val (0, 1, ...
4140 * @ns >= @val (0, 0, ...
4141 *
4142 * If one object to be compared is a node-set and the other is a string,
4143 * then the comparison will be true if and only if there is a node in
4144 * the node-set such that the result of performing the comparison on the
4145 * string-value of the node and the other string is true.
4146 *
4147 * Returns 0 or 1 depending on the results of the test.
4148 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004149static int
Owen Taylor3473f882001-02-23 17:55:21 +00004150xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4151 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4152 int i, ret = 0;
4153 xmlNodeSetPtr ns;
4154 xmlChar *str2;
4155
4156 if ((s == NULL) || (arg == NULL) ||
4157 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4158 xmlXPathFreeObject(arg);
4159 xmlXPathFreeObject(s);
4160 return(0);
4161 }
4162 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004163 if (ns != NULL) {
4164 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004165 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004166 if (str2 != NULL) {
4167 valuePush(ctxt,
4168 xmlXPathNewString(str2));
4169 xmlFree(str2);
4170 valuePush(ctxt, xmlXPathObjectCopy(s));
4171 ret = xmlXPathCompareValues(ctxt, inf, strict);
4172 if (ret)
4173 break;
4174 }
4175 }
Owen Taylor3473f882001-02-23 17:55:21 +00004176 }
4177 xmlXPathFreeObject(arg);
4178 xmlXPathFreeObject(s);
4179 return(ret);
4180}
4181
4182/**
4183 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004184 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004185 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004186 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004187 * @arg2: the second node set object
4188 *
4189 * Implement the compare operation on nodesets:
4190 *
4191 * If both objects to be compared are node-sets, then the comparison
4192 * will be true if and only if there is a node in the first node-set
4193 * and a node in the second node-set such that the result of performing
4194 * the comparison on the string-values of the two nodes is true.
4195 * ....
4196 * When neither object to be compared is a node-set and the operator
4197 * is <=, <, >= or >, then the objects are compared by converting both
4198 * objects to numbers and comparing the numbers according to IEEE 754.
4199 * ....
4200 * The number function converts its argument to a number as follows:
4201 * - a string that consists of optional whitespace followed by an
4202 * optional minus sign followed by a Number followed by whitespace
4203 * is converted to the IEEE 754 number that is nearest (according
4204 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4205 * represented by the string; any other string is converted to NaN
4206 *
4207 * Conclusion all nodes need to be converted first to their string value
4208 * and then the comparison must be done when possible
4209 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004210static int
4211xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004212 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4213 int i, j, init = 0;
4214 double val1;
4215 double *values2;
4216 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004217 xmlNodeSetPtr ns1;
4218 xmlNodeSetPtr ns2;
4219
4220 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004221 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4222 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004223 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004224 }
Owen Taylor3473f882001-02-23 17:55:21 +00004225 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004226 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4227 xmlXPathFreeObject(arg1);
4228 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004229 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004230 }
Owen Taylor3473f882001-02-23 17:55:21 +00004231
4232 ns1 = arg1->nodesetval;
4233 ns2 = arg2->nodesetval;
4234
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004235 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004236 xmlXPathFreeObject(arg1);
4237 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004238 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004239 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004240 if ((ns2 == NULL) || (ns2->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 }
Owen Taylor3473f882001-02-23 17:55:21 +00004245
4246 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4247 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004248 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004249 xmlXPathFreeObject(arg1);
4250 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004251 return(0);
4252 }
4253 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004254 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004255 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004256 continue;
4257 for (j = 0;j < ns2->nodeNr;j++) {
4258 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004259 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004260 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004261 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004262 continue;
4263 if (inf && strict)
4264 ret = (val1 < values2[j]);
4265 else if (inf && !strict)
4266 ret = (val1 <= values2[j]);
4267 else if (!inf && strict)
4268 ret = (val1 > values2[j]);
4269 else if (!inf && !strict)
4270 ret = (val1 >= values2[j]);
4271 if (ret)
4272 break;
4273 }
4274 if (ret)
4275 break;
4276 init = 1;
4277 }
4278 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004279 xmlXPathFreeObject(arg1);
4280 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004281 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004282}
4283
4284/**
4285 * xmlXPathCompareNodeSetValue:
4286 * @ctxt: the XPath Parser context
4287 * @inf: less than (1) or greater than (0)
4288 * @strict: is the comparison strict
4289 * @arg: the node set
4290 * @val: the value
4291 *
4292 * Implement the compare operation between a nodeset and a value
4293 * @ns < @val (1, 1, ...
4294 * @ns <= @val (1, 0, ...
4295 * @ns > @val (0, 1, ...
4296 * @ns >= @val (0, 0, ...
4297 *
4298 * If one object to be compared is a node-set and the other is a boolean,
4299 * then the comparison will be true if and only if the result of performing
4300 * the comparison on the boolean and on the result of converting
4301 * the node-set to a boolean using the boolean function is true.
4302 *
4303 * Returns 0 or 1 depending on the results of the test.
4304 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004305static int
Owen Taylor3473f882001-02-23 17:55:21 +00004306xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4307 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4308 if ((val == NULL) || (arg == NULL) ||
4309 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4310 return(0);
4311
4312 switch(val->type) {
4313 case XPATH_NUMBER:
4314 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4315 case XPATH_NODESET:
4316 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004317 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004318 case XPATH_STRING:
4319 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4320 case XPATH_BOOLEAN:
4321 valuePush(ctxt, arg);
4322 xmlXPathBooleanFunction(ctxt, 1);
4323 valuePush(ctxt, val);
4324 return(xmlXPathCompareValues(ctxt, inf, strict));
4325 default:
4326 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004327 }
4328 return(0);
4329}
4330
4331/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004332 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004333 * @arg: the nodeset object argument
4334 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004335 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004336 *
4337 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4338 * If one object to be compared is a node-set and the other is a string,
4339 * then the comparison will be true if and only if there is a node in
4340 * the node-set such that the result of performing the comparison on the
4341 * string-value of the node and the other string is true.
4342 *
4343 * Returns 0 or 1 depending on the results of the test.
4344 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004345static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004346xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004347{
Owen Taylor3473f882001-02-23 17:55:21 +00004348 int i;
4349 xmlNodeSetPtr ns;
4350 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004351 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004352
4353 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004354 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4355 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004356 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004357 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004358 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004359 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004360 if (ns->nodeNr <= 0) {
4361 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004362 return(neq ^ 1);
4363 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004364 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004365 for (i = 0; i < ns->nodeNr; i++) {
4366 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4367 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4368 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4369 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004370 if (neq)
4371 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004372 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004373 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4374 if (neq)
4375 continue;
4376 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004377 } else if (neq) {
4378 if (str2 != NULL)
4379 xmlFree(str2);
4380 return (1);
4381 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004382 if (str2 != NULL)
4383 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004384 } else if (neq)
4385 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004386 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004387 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004388}
4389
4390/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004391 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004392 * @arg: the nodeset object argument
4393 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004394 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004395 *
4396 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4397 * If one object to be compared is a node-set and the other is a number,
4398 * then the comparison will be true if and only if there is a node in
4399 * the node-set such that the result of performing the comparison on the
4400 * number to be compared and on the result of converting the string-value
4401 * of that node to a number using the number function is true.
4402 *
4403 * Returns 0 or 1 depending on the results of the test.
4404 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004405static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004406xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4407 xmlXPathObjectPtr arg, double f, int neq) {
4408 int i, ret=0;
4409 xmlNodeSetPtr ns;
4410 xmlChar *str2;
4411 xmlXPathObjectPtr val;
4412 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004413
4414 if ((arg == NULL) ||
4415 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4416 return(0);
4417
William M. Brack0c022ad2002-07-12 00:56:01 +00004418 ns = arg->nodesetval;
4419 if (ns != NULL) {
4420 for (i=0;i<ns->nodeNr;i++) {
4421 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4422 if (str2 != NULL) {
4423 valuePush(ctxt, xmlXPathNewString(str2));
4424 xmlFree(str2);
4425 xmlXPathNumberFunction(ctxt, 1);
4426 val = valuePop(ctxt);
4427 v = val->floatval;
4428 xmlXPathFreeObject(val);
4429 if (!xmlXPathIsNaN(v)) {
4430 if ((!neq) && (v==f)) {
4431 ret = 1;
4432 break;
4433 } else if ((neq) && (v!=f)) {
4434 ret = 1;
4435 break;
4436 }
4437 }
4438 }
4439 }
4440 }
4441
4442 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004443}
4444
4445
4446/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004447 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004448 * @arg1: first nodeset object argument
4449 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004450 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004451 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004452 * Implement the equal / not equal operation on XPath nodesets:
4453 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004454 * If both objects to be compared are node-sets, then the comparison
4455 * will be true if and only if there is a node in the first node-set and
4456 * a node in the second node-set such that the result of performing the
4457 * comparison on the string-values of the two nodes is true.
4458 *
4459 * (needless to say, this is a costly operation)
4460 *
4461 * Returns 0 or 1 depending on the results of the test.
4462 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004463static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004464xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004465 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004466 unsigned int *hashs1;
4467 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004468 xmlChar **values1;
4469 xmlChar **values2;
4470 int ret = 0;
4471 xmlNodeSetPtr ns1;
4472 xmlNodeSetPtr ns2;
4473
4474 if ((arg1 == NULL) ||
4475 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4476 return(0);
4477 if ((arg2 == NULL) ||
4478 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4479 return(0);
4480
4481 ns1 = arg1->nodesetval;
4482 ns2 = arg2->nodesetval;
4483
Daniel Veillard911f49a2001-04-07 15:39:35 +00004484 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004485 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004486 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004487 return(0);
4488
4489 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004490 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004491 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004492 if (neq == 0)
4493 for (i = 0;i < ns1->nodeNr;i++)
4494 for (j = 0;j < ns2->nodeNr;j++)
4495 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4496 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004497
4498 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004499 if (values1 == NULL) {
4500 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004501 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004502 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004503 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4504 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004505 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004506 xmlFree(values1);
4507 return(0);
4508 }
Owen Taylor3473f882001-02-23 17:55:21 +00004509 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4510 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4511 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004512 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004513 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004514 xmlFree(values1);
4515 return(0);
4516 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004517 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4518 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004519 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004520 xmlFree(hashs1);
4521 xmlFree(values1);
4522 xmlFree(values2);
4523 return(0);
4524 }
Owen Taylor3473f882001-02-23 17:55:21 +00004525 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4526 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004527 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004528 for (j = 0;j < ns2->nodeNr;j++) {
4529 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004530 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004531 if (hashs1[i] != hashs2[j]) {
4532 if (neq) {
4533 ret = 1;
4534 break;
4535 }
4536 }
4537 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004538 if (values1[i] == NULL)
4539 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4540 if (values2[j] == NULL)
4541 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004542 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004543 if (ret)
4544 break;
4545 }
Owen Taylor3473f882001-02-23 17:55:21 +00004546 }
4547 if (ret)
4548 break;
4549 }
4550 for (i = 0;i < ns1->nodeNr;i++)
4551 if (values1[i] != NULL)
4552 xmlFree(values1[i]);
4553 for (j = 0;j < ns2->nodeNr;j++)
4554 if (values2[j] != NULL)
4555 xmlFree(values2[j]);
4556 xmlFree(values1);
4557 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004558 xmlFree(hashs1);
4559 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004560 return(ret);
4561}
4562
William M. Brack0c022ad2002-07-12 00:56:01 +00004563static int
4564xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4565 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004566 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004567 /*
4568 *At this point we are assured neither arg1 nor arg2
4569 *is a nodeset, so we can just pick the appropriate routine.
4570 */
Owen Taylor3473f882001-02-23 17:55:21 +00004571 switch (arg1->type) {
4572 case XPATH_UNDEFINED:
4573#ifdef DEBUG_EXPR
4574 xmlGenericError(xmlGenericErrorContext,
4575 "Equal: undefined\n");
4576#endif
4577 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004578 case XPATH_BOOLEAN:
4579 switch (arg2->type) {
4580 case XPATH_UNDEFINED:
4581#ifdef DEBUG_EXPR
4582 xmlGenericError(xmlGenericErrorContext,
4583 "Equal: undefined\n");
4584#endif
4585 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004586 case XPATH_BOOLEAN:
4587#ifdef DEBUG_EXPR
4588 xmlGenericError(xmlGenericErrorContext,
4589 "Equal: %d boolean %d \n",
4590 arg1->boolval, arg2->boolval);
4591#endif
4592 ret = (arg1->boolval == arg2->boolval);
4593 break;
4594 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004595 ret = (arg1->boolval ==
4596 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004597 break;
4598 case XPATH_STRING:
4599 if ((arg2->stringval == NULL) ||
4600 (arg2->stringval[0] == 0)) ret = 0;
4601 else
4602 ret = 1;
4603 ret = (arg1->boolval == ret);
4604 break;
4605 case XPATH_USERS:
4606 case XPATH_POINT:
4607 case XPATH_RANGE:
4608 case XPATH_LOCATIONSET:
4609 TODO
4610 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004611 case XPATH_NODESET:
4612 case XPATH_XSLT_TREE:
4613 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004614 }
4615 break;
4616 case XPATH_NUMBER:
4617 switch (arg2->type) {
4618 case XPATH_UNDEFINED:
4619#ifdef DEBUG_EXPR
4620 xmlGenericError(xmlGenericErrorContext,
4621 "Equal: undefined\n");
4622#endif
4623 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004624 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004625 ret = (arg2->boolval==
4626 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004627 break;
4628 case XPATH_STRING:
4629 valuePush(ctxt, arg2);
4630 xmlXPathNumberFunction(ctxt, 1);
4631 arg2 = valuePop(ctxt);
4632 /* no break on purpose */
4633 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004634 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004635 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4636 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004637 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4638 if (xmlXPathIsInf(arg2->floatval) == 1)
4639 ret = 1;
4640 else
4641 ret = 0;
4642 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4643 if (xmlXPathIsInf(arg2->floatval) == -1)
4644 ret = 1;
4645 else
4646 ret = 0;
4647 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4648 if (xmlXPathIsInf(arg1->floatval) == 1)
4649 ret = 1;
4650 else
4651 ret = 0;
4652 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4653 if (xmlXPathIsInf(arg1->floatval) == -1)
4654 ret = 1;
4655 else
4656 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004657 } else {
4658 ret = (arg1->floatval == arg2->floatval);
4659 }
Owen Taylor3473f882001-02-23 17:55:21 +00004660 break;
4661 case XPATH_USERS:
4662 case XPATH_POINT:
4663 case XPATH_RANGE:
4664 case XPATH_LOCATIONSET:
4665 TODO
4666 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004667 case XPATH_NODESET:
4668 case XPATH_XSLT_TREE:
4669 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004670 }
4671 break;
4672 case XPATH_STRING:
4673 switch (arg2->type) {
4674 case XPATH_UNDEFINED:
4675#ifdef DEBUG_EXPR
4676 xmlGenericError(xmlGenericErrorContext,
4677 "Equal: undefined\n");
4678#endif
4679 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004680 case XPATH_BOOLEAN:
4681 if ((arg1->stringval == NULL) ||
4682 (arg1->stringval[0] == 0)) ret = 0;
4683 else
4684 ret = 1;
4685 ret = (arg2->boolval == ret);
4686 break;
4687 case XPATH_STRING:
4688 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4689 break;
4690 case XPATH_NUMBER:
4691 valuePush(ctxt, arg1);
4692 xmlXPathNumberFunction(ctxt, 1);
4693 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004694 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004695 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4696 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004697 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4698 if (xmlXPathIsInf(arg2->floatval) == 1)
4699 ret = 1;
4700 else
4701 ret = 0;
4702 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4703 if (xmlXPathIsInf(arg2->floatval) == -1)
4704 ret = 1;
4705 else
4706 ret = 0;
4707 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4708 if (xmlXPathIsInf(arg1->floatval) == 1)
4709 ret = 1;
4710 else
4711 ret = 0;
4712 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4713 if (xmlXPathIsInf(arg1->floatval) == -1)
4714 ret = 1;
4715 else
4716 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004717 } else {
4718 ret = (arg1->floatval == arg2->floatval);
4719 }
Owen Taylor3473f882001-02-23 17:55:21 +00004720 break;
4721 case XPATH_USERS:
4722 case XPATH_POINT:
4723 case XPATH_RANGE:
4724 case XPATH_LOCATIONSET:
4725 TODO
4726 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004727 case XPATH_NODESET:
4728 case XPATH_XSLT_TREE:
4729 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004730 }
4731 break;
4732 case XPATH_USERS:
4733 case XPATH_POINT:
4734 case XPATH_RANGE:
4735 case XPATH_LOCATIONSET:
4736 TODO
4737 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004738 case XPATH_NODESET:
4739 case XPATH_XSLT_TREE:
4740 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004741 }
4742 xmlXPathFreeObject(arg1);
4743 xmlXPathFreeObject(arg2);
4744 return(ret);
4745}
4746
William M. Brack0c022ad2002-07-12 00:56:01 +00004747/**
4748 * xmlXPathEqualValues:
4749 * @ctxt: the XPath Parser context
4750 *
4751 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4752 *
4753 * Returns 0 or 1 depending on the results of the test.
4754 */
4755int
4756xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4757 xmlXPathObjectPtr arg1, arg2, argtmp;
4758 int ret = 0;
4759
4760 arg2 = valuePop(ctxt);
4761 arg1 = valuePop(ctxt);
4762 if ((arg1 == NULL) || (arg2 == NULL)) {
4763 if (arg1 != NULL)
4764 xmlXPathFreeObject(arg1);
4765 else
4766 xmlXPathFreeObject(arg2);
4767 XP_ERROR0(XPATH_INVALID_OPERAND);
4768 }
4769
4770 if (arg1 == arg2) {
4771#ifdef DEBUG_EXPR
4772 xmlGenericError(xmlGenericErrorContext,
4773 "Equal: by pointer\n");
4774#endif
4775 return(1);
4776 }
4777
4778 /*
4779 *If either argument is a nodeset, it's a 'special case'
4780 */
4781 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4782 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4783 /*
4784 *Hack it to assure arg1 is the nodeset
4785 */
4786 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4787 argtmp = arg2;
4788 arg2 = arg1;
4789 arg1 = argtmp;
4790 }
4791 switch (arg2->type) {
4792 case XPATH_UNDEFINED:
4793#ifdef DEBUG_EXPR
4794 xmlGenericError(xmlGenericErrorContext,
4795 "Equal: undefined\n");
4796#endif
4797 break;
4798 case XPATH_NODESET:
4799 case XPATH_XSLT_TREE:
4800 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4801 break;
4802 case XPATH_BOOLEAN:
4803 if ((arg1->nodesetval == NULL) ||
4804 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4805 else
4806 ret = 1;
4807 ret = (ret == arg2->boolval);
4808 break;
4809 case XPATH_NUMBER:
4810 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4811 break;
4812 case XPATH_STRING:
4813 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4814 break;
4815 case XPATH_USERS:
4816 case XPATH_POINT:
4817 case XPATH_RANGE:
4818 case XPATH_LOCATIONSET:
4819 TODO
4820 break;
4821 }
4822 xmlXPathFreeObject(arg1);
4823 xmlXPathFreeObject(arg2);
4824 return(ret);
4825 }
4826
4827 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4828}
4829
4830/**
4831 * xmlXPathNotEqualValues:
4832 * @ctxt: the XPath Parser context
4833 *
4834 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4835 *
4836 * Returns 0 or 1 depending on the results of the test.
4837 */
4838int
4839xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4840 xmlXPathObjectPtr arg1, arg2, argtmp;
4841 int ret = 0;
4842
4843 arg2 = valuePop(ctxt);
4844 arg1 = valuePop(ctxt);
4845 if ((arg1 == NULL) || (arg2 == NULL)) {
4846 if (arg1 != NULL)
4847 xmlXPathFreeObject(arg1);
4848 else
4849 xmlXPathFreeObject(arg2);
4850 XP_ERROR0(XPATH_INVALID_OPERAND);
4851 }
4852
4853 if (arg1 == arg2) {
4854#ifdef DEBUG_EXPR
4855 xmlGenericError(xmlGenericErrorContext,
4856 "NotEqual: by pointer\n");
4857#endif
4858 return(0);
4859 }
4860
4861 /*
4862 *If either argument is a nodeset, it's a 'special case'
4863 */
4864 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4865 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4866 /*
4867 *Hack it to assure arg1 is the nodeset
4868 */
4869 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4870 argtmp = arg2;
4871 arg2 = arg1;
4872 arg1 = argtmp;
4873 }
4874 switch (arg2->type) {
4875 case XPATH_UNDEFINED:
4876#ifdef DEBUG_EXPR
4877 xmlGenericError(xmlGenericErrorContext,
4878 "NotEqual: undefined\n");
4879#endif
4880 break;
4881 case XPATH_NODESET:
4882 case XPATH_XSLT_TREE:
4883 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4884 break;
4885 case XPATH_BOOLEAN:
4886 if ((arg1->nodesetval == NULL) ||
4887 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4888 else
4889 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004890 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004891 break;
4892 case XPATH_NUMBER:
4893 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4894 break;
4895 case XPATH_STRING:
4896 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4897 break;
4898 case XPATH_USERS:
4899 case XPATH_POINT:
4900 case XPATH_RANGE:
4901 case XPATH_LOCATIONSET:
4902 TODO
4903 break;
4904 }
4905 xmlXPathFreeObject(arg1);
4906 xmlXPathFreeObject(arg2);
4907 return(ret);
4908 }
4909
4910 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4911}
Owen Taylor3473f882001-02-23 17:55:21 +00004912
4913/**
4914 * xmlXPathCompareValues:
4915 * @ctxt: the XPath Parser context
4916 * @inf: less than (1) or greater than (0)
4917 * @strict: is the comparison strict
4918 *
4919 * Implement the compare operation on XPath objects:
4920 * @arg1 < @arg2 (1, 1, ...
4921 * @arg1 <= @arg2 (1, 0, ...
4922 * @arg1 > @arg2 (0, 1, ...
4923 * @arg1 >= @arg2 (0, 0, ...
4924 *
4925 * When neither object to be compared is a node-set and the operator is
4926 * <=, <, >=, >, then the objects are compared by converted both objects
4927 * to numbers and comparing the numbers according to IEEE 754. The <
4928 * comparison will be true if and only if the first number is less than the
4929 * second number. The <= comparison will be true if and only if the first
4930 * number is less than or equal to the second number. The > comparison
4931 * will be true if and only if the first number is greater than the second
4932 * number. The >= comparison will be true if and only if the first number
4933 * is greater than or equal to the second number.
4934 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004935 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004936 */
4937int
4938xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004939 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004940 xmlXPathObjectPtr arg1, arg2;
4941
William M. Brack0c022ad2002-07-12 00:56:01 +00004942 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004943 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004944 if ((arg1 == NULL) || (arg2 == NULL)) {
4945 if (arg1 != NULL)
4946 xmlXPathFreeObject(arg1);
4947 else
4948 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004949 XP_ERROR0(XPATH_INVALID_OPERAND);
4950 }
4951
William M. Brack0c022ad2002-07-12 00:56:01 +00004952 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4953 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4954 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4955 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004956 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004957 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004958 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004959 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4960 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004961 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004962 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4963 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004964 }
4965 }
4966 return(ret);
4967 }
4968
4969 if (arg1->type != XPATH_NUMBER) {
4970 valuePush(ctxt, arg1);
4971 xmlXPathNumberFunction(ctxt, 1);
4972 arg1 = valuePop(ctxt);
4973 }
4974 if (arg1->type != XPATH_NUMBER) {
4975 xmlXPathFreeObject(arg1);
4976 xmlXPathFreeObject(arg2);
4977 XP_ERROR0(XPATH_INVALID_OPERAND);
4978 }
4979 if (arg2->type != XPATH_NUMBER) {
4980 valuePush(ctxt, arg2);
4981 xmlXPathNumberFunction(ctxt, 1);
4982 arg2 = valuePop(ctxt);
4983 }
4984 if (arg2->type != XPATH_NUMBER) {
4985 xmlXPathFreeObject(arg1);
4986 xmlXPathFreeObject(arg2);
4987 XP_ERROR0(XPATH_INVALID_OPERAND);
4988 }
4989 /*
4990 * Add tests for infinity and nan
4991 * => feedback on 3.4 for Inf and NaN
4992 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004993 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004994 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004995 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004996 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004997 arg1i=xmlXPathIsInf(arg1->floatval);
4998 arg2i=xmlXPathIsInf(arg2->floatval);
4999 if (inf && strict) {
5000 if ((arg1i == -1 && arg2i != -1) ||
5001 (arg2i == 1 && arg1i != 1)) {
5002 ret = 1;
5003 } else if (arg1i == 0 && arg2i == 0) {
5004 ret = (arg1->floatval < arg2->floatval);
5005 } else {
5006 ret = 0;
5007 }
5008 }
5009 else if (inf && !strict) {
5010 if (arg1i == -1 || arg2i == 1) {
5011 ret = 1;
5012 } else if (arg1i == 0 && arg2i == 0) {
5013 ret = (arg1->floatval <= arg2->floatval);
5014 } else {
5015 ret = 0;
5016 }
5017 }
5018 else if (!inf && strict) {
5019 if ((arg1i == 1 && arg2i != 1) ||
5020 (arg2i == -1 && arg1i != -1)) {
5021 ret = 1;
5022 } else if (arg1i == 0 && arg2i == 0) {
5023 ret = (arg1->floatval > arg2->floatval);
5024 } else {
5025 ret = 0;
5026 }
5027 }
5028 else if (!inf && !strict) {
5029 if (arg1i == 1 || arg2i == -1) {
5030 ret = 1;
5031 } else if (arg1i == 0 && arg2i == 0) {
5032 ret = (arg1->floatval >= arg2->floatval);
5033 } else {
5034 ret = 0;
5035 }
5036 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005037 }
Owen Taylor3473f882001-02-23 17:55:21 +00005038 xmlXPathFreeObject(arg1);
5039 xmlXPathFreeObject(arg2);
5040 return(ret);
5041}
5042
5043/**
5044 * xmlXPathValueFlipSign:
5045 * @ctxt: the XPath Parser context
5046 *
5047 * Implement the unary - operation on an XPath object
5048 * The numeric operators convert their operands to numbers as if
5049 * by calling the number function.
5050 */
5051void
5052xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005053 CAST_TO_NUMBER;
5054 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005055 if (xmlXPathIsNaN(ctxt->value->floatval))
5056 ctxt->value->floatval=xmlXPathNAN;
5057 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5058 ctxt->value->floatval=xmlXPathNINF;
5059 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5060 ctxt->value->floatval=xmlXPathPINF;
5061 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005062 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5063 ctxt->value->floatval = xmlXPathNZERO;
5064 else
5065 ctxt->value->floatval = 0;
5066 }
5067 else
5068 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005069}
5070
5071/**
5072 * xmlXPathAddValues:
5073 * @ctxt: the XPath Parser context
5074 *
5075 * Implement the add operation on XPath objects:
5076 * The numeric operators convert their operands to numbers as if
5077 * by calling the number function.
5078 */
5079void
5080xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5081 xmlXPathObjectPtr arg;
5082 double val;
5083
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005084 arg = valuePop(ctxt);
5085 if (arg == NULL)
5086 XP_ERROR(XPATH_INVALID_OPERAND);
5087 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005088 xmlXPathFreeObject(arg);
5089
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005090 CAST_TO_NUMBER;
5091 CHECK_TYPE(XPATH_NUMBER);
5092 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005093}
5094
5095/**
5096 * xmlXPathSubValues:
5097 * @ctxt: the XPath Parser context
5098 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005099 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005100 * The numeric operators convert their operands to numbers as if
5101 * by calling the number function.
5102 */
5103void
5104xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5105 xmlXPathObjectPtr arg;
5106 double val;
5107
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005108 arg = valuePop(ctxt);
5109 if (arg == NULL)
5110 XP_ERROR(XPATH_INVALID_OPERAND);
5111 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005112 xmlXPathFreeObject(arg);
5113
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005114 CAST_TO_NUMBER;
5115 CHECK_TYPE(XPATH_NUMBER);
5116 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005117}
5118
5119/**
5120 * xmlXPathMultValues:
5121 * @ctxt: the XPath Parser context
5122 *
5123 * Implement the multiply operation on XPath objects:
5124 * The numeric operators convert their operands to numbers as if
5125 * by calling the number function.
5126 */
5127void
5128xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5129 xmlXPathObjectPtr arg;
5130 double val;
5131
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005132 arg = valuePop(ctxt);
5133 if (arg == NULL)
5134 XP_ERROR(XPATH_INVALID_OPERAND);
5135 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005136 xmlXPathFreeObject(arg);
5137
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005138 CAST_TO_NUMBER;
5139 CHECK_TYPE(XPATH_NUMBER);
5140 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005141}
5142
5143/**
5144 * xmlXPathDivValues:
5145 * @ctxt: the XPath Parser context
5146 *
5147 * Implement the div operation on XPath objects @arg1 / @arg2:
5148 * The numeric operators convert their operands to numbers as if
5149 * by calling the number function.
5150 */
5151void
5152xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5153 xmlXPathObjectPtr arg;
5154 double val;
5155
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005156 arg = valuePop(ctxt);
5157 if (arg == NULL)
5158 XP_ERROR(XPATH_INVALID_OPERAND);
5159 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005160 xmlXPathFreeObject(arg);
5161
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005162 CAST_TO_NUMBER;
5163 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005164 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5165 ctxt->value->floatval = xmlXPathNAN;
5166 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005167 if (ctxt->value->floatval == 0)
5168 ctxt->value->floatval = xmlXPathNAN;
5169 else if (ctxt->value->floatval > 0)
5170 ctxt->value->floatval = xmlXPathNINF;
5171 else if (ctxt->value->floatval < 0)
5172 ctxt->value->floatval = xmlXPathPINF;
5173 }
5174 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005175 if (ctxt->value->floatval == 0)
5176 ctxt->value->floatval = xmlXPathNAN;
5177 else if (ctxt->value->floatval > 0)
5178 ctxt->value->floatval = xmlXPathPINF;
5179 else if (ctxt->value->floatval < 0)
5180 ctxt->value->floatval = xmlXPathNINF;
5181 } else
5182 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005183}
5184
5185/**
5186 * xmlXPathModValues:
5187 * @ctxt: the XPath Parser context
5188 *
5189 * Implement the mod operation on XPath objects: @arg1 / @arg2
5190 * The numeric operators convert their operands to numbers as if
5191 * by calling the number function.
5192 */
5193void
5194xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5195 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005196 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005197
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005198 arg = valuePop(ctxt);
5199 if (arg == NULL)
5200 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005201 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005202 xmlXPathFreeObject(arg);
5203
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005204 CAST_TO_NUMBER;
5205 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005206 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005207 if (arg2 == 0)
5208 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005209 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005210 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005211 }
Owen Taylor3473f882001-02-23 17:55:21 +00005212}
5213
5214/************************************************************************
5215 * *
5216 * The traversal functions *
5217 * *
5218 ************************************************************************/
5219
Owen Taylor3473f882001-02-23 17:55:21 +00005220/*
5221 * A traversal function enumerates nodes along an axis.
5222 * Initially it must be called with NULL, and it indicates
5223 * termination on the axis by returning NULL.
5224 */
5225typedef xmlNodePtr (*xmlXPathTraversalFunction)
5226 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5227
5228/**
5229 * xmlXPathNextSelf:
5230 * @ctxt: the XPath Parser context
5231 * @cur: the current node in the traversal
5232 *
5233 * Traversal function for the "self" direction
5234 * The self axis contains just the context node itself
5235 *
5236 * Returns the next element following that axis
5237 */
5238xmlNodePtr
5239xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5240 if (cur == NULL)
5241 return(ctxt->context->node);
5242 return(NULL);
5243}
5244
5245/**
5246 * xmlXPathNextChild:
5247 * @ctxt: the XPath Parser context
5248 * @cur: the current node in the traversal
5249 *
5250 * Traversal function for the "child" direction
5251 * The child axis contains the children of the context node in document order.
5252 *
5253 * Returns the next element following that axis
5254 */
5255xmlNodePtr
5256xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5257 if (cur == NULL) {
5258 if (ctxt->context->node == NULL) return(NULL);
5259 switch (ctxt->context->node->type) {
5260 case XML_ELEMENT_NODE:
5261 case XML_TEXT_NODE:
5262 case XML_CDATA_SECTION_NODE:
5263 case XML_ENTITY_REF_NODE:
5264 case XML_ENTITY_NODE:
5265 case XML_PI_NODE:
5266 case XML_COMMENT_NODE:
5267 case XML_NOTATION_NODE:
5268 case XML_DTD_NODE:
5269 return(ctxt->context->node->children);
5270 case XML_DOCUMENT_NODE:
5271 case XML_DOCUMENT_TYPE_NODE:
5272 case XML_DOCUMENT_FRAG_NODE:
5273 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005274#ifdef LIBXML_DOCB_ENABLED
5275 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005276#endif
5277 return(((xmlDocPtr) ctxt->context->node)->children);
5278 case XML_ELEMENT_DECL:
5279 case XML_ATTRIBUTE_DECL:
5280 case XML_ENTITY_DECL:
5281 case XML_ATTRIBUTE_NODE:
5282 case XML_NAMESPACE_DECL:
5283 case XML_XINCLUDE_START:
5284 case XML_XINCLUDE_END:
5285 return(NULL);
5286 }
5287 return(NULL);
5288 }
5289 if ((cur->type == XML_DOCUMENT_NODE) ||
5290 (cur->type == XML_HTML_DOCUMENT_NODE))
5291 return(NULL);
5292 return(cur->next);
5293}
5294
5295/**
5296 * xmlXPathNextDescendant:
5297 * @ctxt: the XPath Parser context
5298 * @cur: the current node in the traversal
5299 *
5300 * Traversal function for the "descendant" direction
5301 * the descendant axis contains the descendants of the context node in document
5302 * order; a descendant is a child or a child of a child and so on.
5303 *
5304 * Returns the next element following that axis
5305 */
5306xmlNodePtr
5307xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5308 if (cur == NULL) {
5309 if (ctxt->context->node == NULL)
5310 return(NULL);
5311 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5312 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5313 return(NULL);
5314
5315 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5316 return(ctxt->context->doc->children);
5317 return(ctxt->context->node->children);
5318 }
5319
Daniel Veillard567e1b42001-08-01 15:53:47 +00005320 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005321 /*
5322 * Do not descend on entities declarations
5323 */
5324 if (cur->children->type != XML_ENTITY_DECL) {
5325 cur = cur->children;
5326 /*
5327 * Skip DTDs
5328 */
5329 if (cur->type != XML_DTD_NODE)
5330 return(cur);
5331 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005332 }
5333
5334 if (cur == ctxt->context->node) return(NULL);
5335
Daniel Veillard68e9e742002-11-16 15:35:11 +00005336 while (cur->next != NULL) {
5337 cur = cur->next;
5338 if ((cur->type != XML_ENTITY_DECL) &&
5339 (cur->type != XML_DTD_NODE))
5340 return(cur);
5341 }
Owen Taylor3473f882001-02-23 17:55:21 +00005342
5343 do {
5344 cur = cur->parent;
5345 if (cur == NULL) return(NULL);
5346 if (cur == ctxt->context->node) return(NULL);
5347 if (cur->next != NULL) {
5348 cur = cur->next;
5349 return(cur);
5350 }
5351 } while (cur != NULL);
5352 return(cur);
5353}
5354
5355/**
5356 * xmlXPathNextDescendantOrSelf:
5357 * @ctxt: the XPath Parser context
5358 * @cur: the current node in the traversal
5359 *
5360 * Traversal function for the "descendant-or-self" direction
5361 * the descendant-or-self axis contains the context node and the descendants
5362 * of the context node in document order; thus the context node is the first
5363 * node on the axis, and the first child of the context node is the second node
5364 * on the axis
5365 *
5366 * Returns the next element following that axis
5367 */
5368xmlNodePtr
5369xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5370 if (cur == NULL) {
5371 if (ctxt->context->node == NULL)
5372 return(NULL);
5373 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5374 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5375 return(NULL);
5376 return(ctxt->context->node);
5377 }
5378
5379 return(xmlXPathNextDescendant(ctxt, cur));
5380}
5381
5382/**
5383 * xmlXPathNextParent:
5384 * @ctxt: the XPath Parser context
5385 * @cur: the current node in the traversal
5386 *
5387 * Traversal function for the "parent" direction
5388 * The parent axis contains the parent of the context node, if there is one.
5389 *
5390 * Returns the next element following that axis
5391 */
5392xmlNodePtr
5393xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5394 /*
5395 * the parent of an attribute or namespace node is the element
5396 * to which the attribute or namespace node is attached
5397 * Namespace handling !!!
5398 */
5399 if (cur == NULL) {
5400 if (ctxt->context->node == NULL) return(NULL);
5401 switch (ctxt->context->node->type) {
5402 case XML_ELEMENT_NODE:
5403 case XML_TEXT_NODE:
5404 case XML_CDATA_SECTION_NODE:
5405 case XML_ENTITY_REF_NODE:
5406 case XML_ENTITY_NODE:
5407 case XML_PI_NODE:
5408 case XML_COMMENT_NODE:
5409 case XML_NOTATION_NODE:
5410 case XML_DTD_NODE:
5411 case XML_ELEMENT_DECL:
5412 case XML_ATTRIBUTE_DECL:
5413 case XML_XINCLUDE_START:
5414 case XML_XINCLUDE_END:
5415 case XML_ENTITY_DECL:
5416 if (ctxt->context->node->parent == NULL)
5417 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005418 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005419 ((ctxt->context->node->parent->name[0] == ' ') ||
5420 (xmlStrEqual(ctxt->context->node->parent->name,
5421 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005422 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005423 return(ctxt->context->node->parent);
5424 case XML_ATTRIBUTE_NODE: {
5425 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5426
5427 return(att->parent);
5428 }
5429 case XML_DOCUMENT_NODE:
5430 case XML_DOCUMENT_TYPE_NODE:
5431 case XML_DOCUMENT_FRAG_NODE:
5432 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005433#ifdef LIBXML_DOCB_ENABLED
5434 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005435#endif
5436 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005437 case XML_NAMESPACE_DECL: {
5438 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5439
5440 if ((ns->next != NULL) &&
5441 (ns->next->type != XML_NAMESPACE_DECL))
5442 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005443 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005444 }
Owen Taylor3473f882001-02-23 17:55:21 +00005445 }
5446 }
5447 return(NULL);
5448}
5449
5450/**
5451 * xmlXPathNextAncestor:
5452 * @ctxt: the XPath Parser context
5453 * @cur: the current node in the traversal
5454 *
5455 * Traversal function for the "ancestor" direction
5456 * the ancestor axis contains the ancestors of the context node; the ancestors
5457 * of the context node consist of the parent of context node and the parent's
5458 * parent and so on; the nodes are ordered in reverse document order; thus the
5459 * parent is the first node on the axis, and the parent's parent is the second
5460 * node on the axis
5461 *
5462 * Returns the next element following that axis
5463 */
5464xmlNodePtr
5465xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5466 /*
5467 * the parent of an attribute or namespace node is the element
5468 * to which the attribute or namespace node is attached
5469 * !!!!!!!!!!!!!
5470 */
5471 if (cur == NULL) {
5472 if (ctxt->context->node == NULL) return(NULL);
5473 switch (ctxt->context->node->type) {
5474 case XML_ELEMENT_NODE:
5475 case XML_TEXT_NODE:
5476 case XML_CDATA_SECTION_NODE:
5477 case XML_ENTITY_REF_NODE:
5478 case XML_ENTITY_NODE:
5479 case XML_PI_NODE:
5480 case XML_COMMENT_NODE:
5481 case XML_DTD_NODE:
5482 case XML_ELEMENT_DECL:
5483 case XML_ATTRIBUTE_DECL:
5484 case XML_ENTITY_DECL:
5485 case XML_NOTATION_NODE:
5486 case XML_XINCLUDE_START:
5487 case XML_XINCLUDE_END:
5488 if (ctxt->context->node->parent == NULL)
5489 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005490 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005491 ((ctxt->context->node->parent->name[0] == ' ') ||
5492 (xmlStrEqual(ctxt->context->node->parent->name,
5493 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005494 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005495 return(ctxt->context->node->parent);
5496 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005497 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005498
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005499 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005500 }
5501 case XML_DOCUMENT_NODE:
5502 case XML_DOCUMENT_TYPE_NODE:
5503 case XML_DOCUMENT_FRAG_NODE:
5504 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005505#ifdef LIBXML_DOCB_ENABLED
5506 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005507#endif
5508 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005509 case XML_NAMESPACE_DECL: {
5510 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5511
5512 if ((ns->next != NULL) &&
5513 (ns->next->type != XML_NAMESPACE_DECL))
5514 return((xmlNodePtr) ns->next);
5515 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005516 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005517 }
Owen Taylor3473f882001-02-23 17:55:21 +00005518 }
5519 return(NULL);
5520 }
5521 if (cur == ctxt->context->doc->children)
5522 return((xmlNodePtr) ctxt->context->doc);
5523 if (cur == (xmlNodePtr) ctxt->context->doc)
5524 return(NULL);
5525 switch (cur->type) {
5526 case XML_ELEMENT_NODE:
5527 case XML_TEXT_NODE:
5528 case XML_CDATA_SECTION_NODE:
5529 case XML_ENTITY_REF_NODE:
5530 case XML_ENTITY_NODE:
5531 case XML_PI_NODE:
5532 case XML_COMMENT_NODE:
5533 case XML_NOTATION_NODE:
5534 case XML_DTD_NODE:
5535 case XML_ELEMENT_DECL:
5536 case XML_ATTRIBUTE_DECL:
5537 case XML_ENTITY_DECL:
5538 case XML_XINCLUDE_START:
5539 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005540 if (cur->parent == NULL)
5541 return(NULL);
5542 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005543 ((cur->parent->name[0] == ' ') ||
5544 (xmlStrEqual(cur->parent->name,
5545 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005546 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005547 return(cur->parent);
5548 case XML_ATTRIBUTE_NODE: {
5549 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5550
5551 return(att->parent);
5552 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005553 case XML_NAMESPACE_DECL: {
5554 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5555
5556 if ((ns->next != NULL) &&
5557 (ns->next->type != XML_NAMESPACE_DECL))
5558 return((xmlNodePtr) ns->next);
5559 /* Bad, how did that namespace ended-up there ? */
5560 return(NULL);
5561 }
Owen Taylor3473f882001-02-23 17:55:21 +00005562 case XML_DOCUMENT_NODE:
5563 case XML_DOCUMENT_TYPE_NODE:
5564 case XML_DOCUMENT_FRAG_NODE:
5565 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005566#ifdef LIBXML_DOCB_ENABLED
5567 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005568#endif
5569 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005570 }
5571 return(NULL);
5572}
5573
5574/**
5575 * xmlXPathNextAncestorOrSelf:
5576 * @ctxt: the XPath Parser context
5577 * @cur: the current node in the traversal
5578 *
5579 * Traversal function for the "ancestor-or-self" direction
5580 * he ancestor-or-self axis contains the context node and ancestors of
5581 * the context node in reverse document order; thus the context node is
5582 * the first node on the axis, and the context node's parent the second;
5583 * parent here is defined the same as with the parent axis.
5584 *
5585 * Returns the next element following that axis
5586 */
5587xmlNodePtr
5588xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5589 if (cur == NULL)
5590 return(ctxt->context->node);
5591 return(xmlXPathNextAncestor(ctxt, cur));
5592}
5593
5594/**
5595 * xmlXPathNextFollowingSibling:
5596 * @ctxt: the XPath Parser context
5597 * @cur: the current node in the traversal
5598 *
5599 * Traversal function for the "following-sibling" direction
5600 * The following-sibling axis contains the following siblings of the context
5601 * node in document order.
5602 *
5603 * Returns the next element following that axis
5604 */
5605xmlNodePtr
5606xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5607 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5608 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5609 return(NULL);
5610 if (cur == (xmlNodePtr) ctxt->context->doc)
5611 return(NULL);
5612 if (cur == NULL)
5613 return(ctxt->context->node->next);
5614 return(cur->next);
5615}
5616
5617/**
5618 * xmlXPathNextPrecedingSibling:
5619 * @ctxt: the XPath Parser context
5620 * @cur: the current node in the traversal
5621 *
5622 * Traversal function for the "preceding-sibling" direction
5623 * The preceding-sibling axis contains the preceding siblings of the context
5624 * node in reverse document order; the first preceding sibling is first on the
5625 * axis; the sibling preceding that node is the second on the axis and so on.
5626 *
5627 * Returns the next element following that axis
5628 */
5629xmlNodePtr
5630xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5631 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5632 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5633 return(NULL);
5634 if (cur == (xmlNodePtr) ctxt->context->doc)
5635 return(NULL);
5636 if (cur == NULL)
5637 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005638 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5639 cur = cur->prev;
5640 if (cur == NULL)
5641 return(ctxt->context->node->prev);
5642 }
Owen Taylor3473f882001-02-23 17:55:21 +00005643 return(cur->prev);
5644}
5645
5646/**
5647 * xmlXPathNextFollowing:
5648 * @ctxt: the XPath Parser context
5649 * @cur: the current node in the traversal
5650 *
5651 * Traversal function for the "following" direction
5652 * The following axis contains all nodes in the same document as the context
5653 * node that are after the context node in document order, excluding any
5654 * descendants and excluding attribute nodes and namespace nodes; the nodes
5655 * are ordered in document order
5656 *
5657 * Returns the next element following that axis
5658 */
5659xmlNodePtr
5660xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5661 if (cur != NULL && cur->children != NULL)
5662 return cur->children ;
5663 if (cur == NULL) cur = ctxt->context->node;
5664 if (cur == NULL) return(NULL) ; /* ERROR */
5665 if (cur->next != NULL) return(cur->next) ;
5666 do {
5667 cur = cur->parent;
5668 if (cur == NULL) return(NULL);
5669 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5670 if (cur->next != NULL) return(cur->next);
5671 } while (cur != NULL);
5672 return(cur);
5673}
5674
5675/*
5676 * xmlXPathIsAncestor:
5677 * @ancestor: the ancestor node
5678 * @node: the current node
5679 *
5680 * Check that @ancestor is a @node's ancestor
5681 *
5682 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5683 */
5684static int
5685xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5686 if ((ancestor == NULL) || (node == NULL)) return(0);
5687 /* nodes need to be in the same document */
5688 if (ancestor->doc != node->doc) return(0);
5689 /* avoid searching if ancestor or node is the root node */
5690 if (ancestor == (xmlNodePtr) node->doc) return(1);
5691 if (node == (xmlNodePtr) ancestor->doc) return(0);
5692 while (node->parent != NULL) {
5693 if (node->parent == ancestor)
5694 return(1);
5695 node = node->parent;
5696 }
5697 return(0);
5698}
5699
5700/**
5701 * xmlXPathNextPreceding:
5702 * @ctxt: the XPath Parser context
5703 * @cur: the current node in the traversal
5704 *
5705 * Traversal function for the "preceding" direction
5706 * the preceding axis contains all nodes in the same document as the context
5707 * node that are before the context node in document order, excluding any
5708 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5709 * ordered in reverse document order
5710 *
5711 * Returns the next element following that axis
5712 */
5713xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005714xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5715{
Owen Taylor3473f882001-02-23 17:55:21 +00005716 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005717 cur = ctxt->context->node;
5718 if (cur == NULL)
5719 return (NULL);
5720 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5721 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005722 do {
5723 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005724 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5725 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005726 }
5727
5728 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005729 if (cur == NULL)
5730 return (NULL);
5731 if (cur == ctxt->context->doc->children)
5732 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005733 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005734 return (cur);
5735}
5736
5737/**
5738 * xmlXPathNextPrecedingInternal:
5739 * @ctxt: the XPath Parser context
5740 * @cur: the current node in the traversal
5741 *
5742 * Traversal function for the "preceding" direction
5743 * the preceding axis contains all nodes in the same document as the context
5744 * node that are before the context node in document order, excluding any
5745 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5746 * ordered in reverse document order
5747 * This is a faster implementation but internal only since it requires a
5748 * state kept in the parser context: ctxt->ancestor.
5749 *
5750 * Returns the next element following that axis
5751 */
5752static xmlNodePtr
5753xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5754 xmlNodePtr cur)
5755{
5756 if (cur == NULL) {
5757 cur = ctxt->context->node;
5758 if (cur == NULL)
5759 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005760 if (cur->type == XML_NAMESPACE_DECL)
5761 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005762 ctxt->ancestor = cur->parent;
5763 }
5764 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5765 cur = cur->prev;
5766 while (cur->prev == NULL) {
5767 cur = cur->parent;
5768 if (cur == NULL)
5769 return (NULL);
5770 if (cur == ctxt->context->doc->children)
5771 return (NULL);
5772 if (cur != ctxt->ancestor)
5773 return (cur);
5774 ctxt->ancestor = cur->parent;
5775 }
5776 cur = cur->prev;
5777 while (cur->last != NULL)
5778 cur = cur->last;
5779 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005780}
5781
5782/**
5783 * xmlXPathNextNamespace:
5784 * @ctxt: the XPath Parser context
5785 * @cur: the current attribute in the traversal
5786 *
5787 * Traversal function for the "namespace" direction
5788 * the namespace axis contains the namespace nodes of the context node;
5789 * the order of nodes on this axis is implementation-defined; the axis will
5790 * be empty unless the context node is an element
5791 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005792 * We keep the XML namespace node at the end of the list.
5793 *
Owen Taylor3473f882001-02-23 17:55:21 +00005794 * Returns the next element following that axis
5795 */
5796xmlNodePtr
5797xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5798 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005799 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005800 if (ctxt->context->tmpNsList != NULL)
5801 xmlFree(ctxt->context->tmpNsList);
5802 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005803 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005804 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005805 if (ctxt->context->tmpNsList != NULL) {
5806 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5807 ctxt->context->tmpNsNr++;
5808 }
5809 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005810 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005811 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005812 if (ctxt->context->tmpNsNr > 0) {
5813 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5814 } else {
5815 if (ctxt->context->tmpNsList != NULL)
5816 xmlFree(ctxt->context->tmpNsList);
5817 ctxt->context->tmpNsList = NULL;
5818 return(NULL);
5819 }
Owen Taylor3473f882001-02-23 17:55:21 +00005820}
5821
5822/**
5823 * xmlXPathNextAttribute:
5824 * @ctxt: the XPath Parser context
5825 * @cur: the current attribute in the traversal
5826 *
5827 * Traversal function for the "attribute" direction
5828 * TODO: support DTD inherited default attributes
5829 *
5830 * Returns the next element following that axis
5831 */
5832xmlNodePtr
5833xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005834 if (ctxt->context->node == NULL)
5835 return(NULL);
5836 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5837 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005838 if (cur == NULL) {
5839 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5840 return(NULL);
5841 return((xmlNodePtr)ctxt->context->node->properties);
5842 }
5843 return((xmlNodePtr)cur->next);
5844}
5845
5846/************************************************************************
5847 * *
5848 * NodeTest Functions *
5849 * *
5850 ************************************************************************/
5851
Owen Taylor3473f882001-02-23 17:55:21 +00005852#define IS_FUNCTION 200
5853
Owen Taylor3473f882001-02-23 17:55:21 +00005854
5855/************************************************************************
5856 * *
5857 * Implicit tree core function library *
5858 * *
5859 ************************************************************************/
5860
5861/**
5862 * xmlXPathRoot:
5863 * @ctxt: the XPath Parser context
5864 *
5865 * Initialize the context to the root of the document
5866 */
5867void
5868xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5869 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5870 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5871}
5872
5873/************************************************************************
5874 * *
5875 * The explicit core function library *
5876 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5877 * *
5878 ************************************************************************/
5879
5880
5881/**
5882 * xmlXPathLastFunction:
5883 * @ctxt: the XPath Parser context
5884 * @nargs: the number of arguments
5885 *
5886 * Implement the last() XPath function
5887 * number last()
5888 * The last function returns the number of nodes in the context node list.
5889 */
5890void
5891xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5892 CHECK_ARITY(0);
5893 if (ctxt->context->contextSize >= 0) {
5894 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5895#ifdef DEBUG_EXPR
5896 xmlGenericError(xmlGenericErrorContext,
5897 "last() : %d\n", ctxt->context->contextSize);
5898#endif
5899 } else {
5900 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5901 }
5902}
5903
5904/**
5905 * xmlXPathPositionFunction:
5906 * @ctxt: the XPath Parser context
5907 * @nargs: the number of arguments
5908 *
5909 * Implement the position() XPath function
5910 * number position()
5911 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005912 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005913 * will be equal to last().
5914 */
5915void
5916xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5917 CHECK_ARITY(0);
5918 if (ctxt->context->proximityPosition >= 0) {
5919 valuePush(ctxt,
5920 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5921#ifdef DEBUG_EXPR
5922 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5923 ctxt->context->proximityPosition);
5924#endif
5925 } else {
5926 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5927 }
5928}
5929
5930/**
5931 * xmlXPathCountFunction:
5932 * @ctxt: the XPath Parser context
5933 * @nargs: the number of arguments
5934 *
5935 * Implement the count() XPath function
5936 * number count(node-set)
5937 */
5938void
5939xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5940 xmlXPathObjectPtr cur;
5941
5942 CHECK_ARITY(1);
5943 if ((ctxt->value == NULL) ||
5944 ((ctxt->value->type != XPATH_NODESET) &&
5945 (ctxt->value->type != XPATH_XSLT_TREE)))
5946 XP_ERROR(XPATH_INVALID_TYPE);
5947 cur = valuePop(ctxt);
5948
Daniel Veillard911f49a2001-04-07 15:39:35 +00005949 if ((cur == NULL) || (cur->nodesetval == NULL))
5950 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005951 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005952 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005953 } else {
5954 if ((cur->nodesetval->nodeNr != 1) ||
5955 (cur->nodesetval->nodeTab == NULL)) {
5956 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5957 } else {
5958 xmlNodePtr tmp;
5959 int i = 0;
5960
5961 tmp = cur->nodesetval->nodeTab[0];
5962 if (tmp != NULL) {
5963 tmp = tmp->children;
5964 while (tmp != NULL) {
5965 tmp = tmp->next;
5966 i++;
5967 }
5968 }
5969 valuePush(ctxt, xmlXPathNewFloat((double) i));
5970 }
5971 }
Owen Taylor3473f882001-02-23 17:55:21 +00005972 xmlXPathFreeObject(cur);
5973}
5974
5975/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005976 * xmlXPathGetElementsByIds:
5977 * @doc: the document
5978 * @ids: a whitespace separated list of IDs
5979 *
5980 * Selects elements by their unique ID.
5981 *
5982 * Returns a node-set of selected elements.
5983 */
5984static xmlNodeSetPtr
5985xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5986 xmlNodeSetPtr ret;
5987 const xmlChar *cur = ids;
5988 xmlChar *ID;
5989 xmlAttrPtr attr;
5990 xmlNodePtr elem = NULL;
5991
Daniel Veillard7a985a12003-07-06 17:57:42 +00005992 if (ids == NULL) return(NULL);
5993
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005994 ret = xmlXPathNodeSetCreate(NULL);
5995
William M. Brack76e95df2003-10-18 16:20:14 +00005996 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005997 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00005998 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00005999 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006000
6001 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006002 if (ID != NULL) {
6003 if (xmlValidateNCName(ID, 1) == 0) {
6004 attr = xmlGetID(doc, ID);
6005 if (attr != NULL) {
6006 if (attr->type == XML_ATTRIBUTE_NODE)
6007 elem = attr->parent;
6008 else if (attr->type == XML_ELEMENT_NODE)
6009 elem = (xmlNodePtr) attr;
6010 else
6011 elem = NULL;
6012 if (elem != NULL)
6013 xmlXPathNodeSetAdd(ret, elem);
6014 }
6015 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006016 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006017 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006018
William M. Brack76e95df2003-10-18 16:20:14 +00006019 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006020 ids = cur;
6021 }
6022 return(ret);
6023}
6024
6025/**
Owen Taylor3473f882001-02-23 17:55:21 +00006026 * xmlXPathIdFunction:
6027 * @ctxt: the XPath Parser context
6028 * @nargs: the number of arguments
6029 *
6030 * Implement the id() XPath function
6031 * node-set id(object)
6032 * The id function selects elements by their unique ID
6033 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6034 * then the result is the union of the result of applying id to the
6035 * string value of each of the nodes in the argument node-set. When the
6036 * argument to id is of any other type, the argument is converted to a
6037 * string as if by a call to the string function; the string is split
6038 * into a whitespace-separated list of tokens (whitespace is any sequence
6039 * of characters matching the production S); the result is a node-set
6040 * containing the elements in the same document as the context node that
6041 * have a unique ID equal to any of the tokens in the list.
6042 */
6043void
6044xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006045 xmlChar *tokens;
6046 xmlNodeSetPtr ret;
6047 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006048
6049 CHECK_ARITY(1);
6050 obj = valuePop(ctxt);
6051 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006052 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006053 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006054 int i;
6055
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006056 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006057
Daniel Veillard911f49a2001-04-07 15:39:35 +00006058 if (obj->nodesetval != NULL) {
6059 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006060 tokens =
6061 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6062 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6063 ret = xmlXPathNodeSetMerge(ret, ns);
6064 xmlXPathFreeNodeSet(ns);
6065 if (tokens != NULL)
6066 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006067 }
Owen Taylor3473f882001-02-23 17:55:21 +00006068 }
6069
6070 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006071 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006072 return;
6073 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006074 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006075
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006076 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6077 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006078
Owen Taylor3473f882001-02-23 17:55:21 +00006079 xmlXPathFreeObject(obj);
6080 return;
6081}
6082
6083/**
6084 * xmlXPathLocalNameFunction:
6085 * @ctxt: the XPath Parser context
6086 * @nargs: the number of arguments
6087 *
6088 * Implement the local-name() XPath function
6089 * string local-name(node-set?)
6090 * The local-name function returns a string containing the local part
6091 * of the name of the node in the argument node-set that is first in
6092 * document order. If the node-set is empty or the first node has no
6093 * name, an empty string is returned. If the argument is omitted it
6094 * defaults to the context node.
6095 */
6096void
6097xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6098 xmlXPathObjectPtr cur;
6099
6100 if (nargs == 0) {
6101 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6102 nargs = 1;
6103 }
6104
6105 CHECK_ARITY(1);
6106 if ((ctxt->value == NULL) ||
6107 ((ctxt->value->type != XPATH_NODESET) &&
6108 (ctxt->value->type != XPATH_XSLT_TREE)))
6109 XP_ERROR(XPATH_INVALID_TYPE);
6110 cur = valuePop(ctxt);
6111
Daniel Veillard911f49a2001-04-07 15:39:35 +00006112 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006113 valuePush(ctxt, xmlXPathNewCString(""));
6114 } else {
6115 int i = 0; /* Should be first in document order !!!!! */
6116 switch (cur->nodesetval->nodeTab[i]->type) {
6117 case XML_ELEMENT_NODE:
6118 case XML_ATTRIBUTE_NODE:
6119 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006120 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6121 valuePush(ctxt, xmlXPathNewCString(""));
6122 else
6123 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006124 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6125 break;
6126 case XML_NAMESPACE_DECL:
6127 valuePush(ctxt, xmlXPathNewString(
6128 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6129 break;
6130 default:
6131 valuePush(ctxt, xmlXPathNewCString(""));
6132 }
6133 }
6134 xmlXPathFreeObject(cur);
6135}
6136
6137/**
6138 * xmlXPathNamespaceURIFunction:
6139 * @ctxt: the XPath Parser context
6140 * @nargs: the number of arguments
6141 *
6142 * Implement the namespace-uri() XPath function
6143 * string namespace-uri(node-set?)
6144 * The namespace-uri function returns a string containing the
6145 * namespace URI of the expanded name of the node in the argument
6146 * node-set that is first in document order. If the node-set is empty,
6147 * the first node has no name, or the expanded name has no namespace
6148 * URI, an empty string is returned. If the argument is omitted it
6149 * defaults to the context node.
6150 */
6151void
6152xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6153 xmlXPathObjectPtr cur;
6154
6155 if (nargs == 0) {
6156 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6157 nargs = 1;
6158 }
6159 CHECK_ARITY(1);
6160 if ((ctxt->value == NULL) ||
6161 ((ctxt->value->type != XPATH_NODESET) &&
6162 (ctxt->value->type != XPATH_XSLT_TREE)))
6163 XP_ERROR(XPATH_INVALID_TYPE);
6164 cur = valuePop(ctxt);
6165
Daniel Veillard911f49a2001-04-07 15:39:35 +00006166 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006167 valuePush(ctxt, xmlXPathNewCString(""));
6168 } else {
6169 int i = 0; /* Should be first in document order !!!!! */
6170 switch (cur->nodesetval->nodeTab[i]->type) {
6171 case XML_ELEMENT_NODE:
6172 case XML_ATTRIBUTE_NODE:
6173 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6174 valuePush(ctxt, xmlXPathNewCString(""));
6175 else
6176 valuePush(ctxt, xmlXPathNewString(
6177 cur->nodesetval->nodeTab[i]->ns->href));
6178 break;
6179 default:
6180 valuePush(ctxt, xmlXPathNewCString(""));
6181 }
6182 }
6183 xmlXPathFreeObject(cur);
6184}
6185
6186/**
6187 * xmlXPathNameFunction:
6188 * @ctxt: the XPath Parser context
6189 * @nargs: the number of arguments
6190 *
6191 * Implement the name() XPath function
6192 * string name(node-set?)
6193 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006194 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006195 * order. The QName must represent the name with respect to the namespace
6196 * declarations in effect on the node whose name is being represented.
6197 * Typically, this will be the form in which the name occurred in the XML
6198 * source. This need not be the case if there are namespace declarations
6199 * in effect on the node that associate multiple prefixes with the same
6200 * namespace. However, an implementation may include information about
6201 * the original prefix in its representation of nodes; in this case, an
6202 * implementation can ensure that the returned string is always the same
6203 * as the QName used in the XML source. If the argument it omitted it
6204 * defaults to the context node.
6205 * Libxml keep the original prefix so the "real qualified name" used is
6206 * returned.
6207 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006208static void
Daniel Veillard04383752001-07-08 14:27:15 +00006209xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6210{
Owen Taylor3473f882001-02-23 17:55:21 +00006211 xmlXPathObjectPtr cur;
6212
6213 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006214 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6215 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006216 }
6217
6218 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006219 if ((ctxt->value == NULL) ||
6220 ((ctxt->value->type != XPATH_NODESET) &&
6221 (ctxt->value->type != XPATH_XSLT_TREE)))
6222 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006223 cur = valuePop(ctxt);
6224
Daniel Veillard911f49a2001-04-07 15:39:35 +00006225 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006226 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006227 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006228 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006229
Daniel Veillard04383752001-07-08 14:27:15 +00006230 switch (cur->nodesetval->nodeTab[i]->type) {
6231 case XML_ELEMENT_NODE:
6232 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006233 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6234 valuePush(ctxt, xmlXPathNewCString(""));
6235 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6236 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006237 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006238 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006239
Daniel Veillard652d8a92003-02-04 19:28:49 +00006240 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006241 xmlChar *fullname;
6242
6243 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6244 cur->nodesetval->nodeTab[i]->ns->prefix,
6245 NULL, 0);
6246 if (fullname == cur->nodesetval->nodeTab[i]->name)
6247 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6248 if (fullname == NULL) {
6249 XP_ERROR(XPATH_MEMORY_ERROR);
6250 }
6251 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006252 }
6253 break;
6254 default:
6255 valuePush(ctxt,
6256 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6257 xmlXPathLocalNameFunction(ctxt, 1);
6258 }
Owen Taylor3473f882001-02-23 17:55:21 +00006259 }
6260 xmlXPathFreeObject(cur);
6261}
6262
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006263
6264/**
Owen Taylor3473f882001-02-23 17:55:21 +00006265 * xmlXPathStringFunction:
6266 * @ctxt: the XPath Parser context
6267 * @nargs: the number of arguments
6268 *
6269 * Implement the string() XPath function
6270 * string string(object?)
6271 * he string function converts an object to a string as follows:
6272 * - A node-set is converted to a string by returning the value of
6273 * the node in the node-set that is first in document order.
6274 * If the node-set is empty, an empty string is returned.
6275 * - A number is converted to a string as follows
6276 * + NaN is converted to the string NaN
6277 * + positive zero is converted to the string 0
6278 * + negative zero is converted to the string 0
6279 * + positive infinity is converted to the string Infinity
6280 * + negative infinity is converted to the string -Infinity
6281 * + if the number is an integer, the number is represented in
6282 * decimal form as a Number with no decimal point and no leading
6283 * zeros, preceded by a minus sign (-) if the number is negative
6284 * + otherwise, the number is represented in decimal form as a
6285 * Number including a decimal point with at least one digit
6286 * before the decimal point and at least one digit after the
6287 * decimal point, preceded by a minus sign (-) if the number
6288 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006289 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006290 * before the decimal point; beyond the one required digit
6291 * after the decimal point there must be as many, but only as
6292 * many, more digits as are needed to uniquely distinguish the
6293 * number from all other IEEE 754 numeric values.
6294 * - The boolean false value is converted to the string false.
6295 * The boolean true value is converted to the string true.
6296 *
6297 * If the argument is omitted, it defaults to a node-set with the
6298 * context node as its only member.
6299 */
6300void
6301xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6302 xmlXPathObjectPtr cur;
6303
6304 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006305 valuePush(ctxt,
6306 xmlXPathWrapString(
6307 xmlXPathCastNodeToString(ctxt->context->node)));
6308 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006309 }
6310
6311 CHECK_ARITY(1);
6312 cur = valuePop(ctxt);
6313 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006314 cur = xmlXPathConvertString(cur);
6315 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006316}
6317
6318/**
6319 * xmlXPathStringLengthFunction:
6320 * @ctxt: the XPath Parser context
6321 * @nargs: the number of arguments
6322 *
6323 * Implement the string-length() XPath function
6324 * number string-length(string?)
6325 * The string-length returns the number of characters in the string
6326 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6327 * the context node converted to a string, in other words the value
6328 * of the context node.
6329 */
6330void
6331xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6332 xmlXPathObjectPtr cur;
6333
6334 if (nargs == 0) {
6335 if (ctxt->context->node == NULL) {
6336 valuePush(ctxt, xmlXPathNewFloat(0));
6337 } else {
6338 xmlChar *content;
6339
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006340 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006341 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006342 xmlFree(content);
6343 }
6344 return;
6345 }
6346 CHECK_ARITY(1);
6347 CAST_TO_STRING;
6348 CHECK_TYPE(XPATH_STRING);
6349 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006350 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006351 xmlXPathFreeObject(cur);
6352}
6353
6354/**
6355 * xmlXPathConcatFunction:
6356 * @ctxt: the XPath Parser context
6357 * @nargs: the number of arguments
6358 *
6359 * Implement the concat() XPath function
6360 * string concat(string, string, string*)
6361 * The concat function returns the concatenation of its arguments.
6362 */
6363void
6364xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6365 xmlXPathObjectPtr cur, newobj;
6366 xmlChar *tmp;
6367
6368 if (nargs < 2) {
6369 CHECK_ARITY(2);
6370 }
6371
6372 CAST_TO_STRING;
6373 cur = valuePop(ctxt);
6374 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6375 xmlXPathFreeObject(cur);
6376 return;
6377 }
6378 nargs--;
6379
6380 while (nargs > 0) {
6381 CAST_TO_STRING;
6382 newobj = valuePop(ctxt);
6383 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6384 xmlXPathFreeObject(newobj);
6385 xmlXPathFreeObject(cur);
6386 XP_ERROR(XPATH_INVALID_TYPE);
6387 }
6388 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6389 newobj->stringval = cur->stringval;
6390 cur->stringval = tmp;
6391
6392 xmlXPathFreeObject(newobj);
6393 nargs--;
6394 }
6395 valuePush(ctxt, cur);
6396}
6397
6398/**
6399 * xmlXPathContainsFunction:
6400 * @ctxt: the XPath Parser context
6401 * @nargs: the number of arguments
6402 *
6403 * Implement the contains() XPath function
6404 * boolean contains(string, string)
6405 * The contains function returns true if the first argument string
6406 * contains the second argument string, and otherwise returns false.
6407 */
6408void
6409xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6410 xmlXPathObjectPtr hay, needle;
6411
6412 CHECK_ARITY(2);
6413 CAST_TO_STRING;
6414 CHECK_TYPE(XPATH_STRING);
6415 needle = valuePop(ctxt);
6416 CAST_TO_STRING;
6417 hay = valuePop(ctxt);
6418 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6419 xmlXPathFreeObject(hay);
6420 xmlXPathFreeObject(needle);
6421 XP_ERROR(XPATH_INVALID_TYPE);
6422 }
6423 if (xmlStrstr(hay->stringval, needle->stringval))
6424 valuePush(ctxt, xmlXPathNewBoolean(1));
6425 else
6426 valuePush(ctxt, xmlXPathNewBoolean(0));
6427 xmlXPathFreeObject(hay);
6428 xmlXPathFreeObject(needle);
6429}
6430
6431/**
6432 * xmlXPathStartsWithFunction:
6433 * @ctxt: the XPath Parser context
6434 * @nargs: the number of arguments
6435 *
6436 * Implement the starts-with() XPath function
6437 * boolean starts-with(string, string)
6438 * The starts-with function returns true if the first argument string
6439 * starts with the second argument string, and otherwise returns false.
6440 */
6441void
6442xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6443 xmlXPathObjectPtr hay, needle;
6444 int n;
6445
6446 CHECK_ARITY(2);
6447 CAST_TO_STRING;
6448 CHECK_TYPE(XPATH_STRING);
6449 needle = valuePop(ctxt);
6450 CAST_TO_STRING;
6451 hay = valuePop(ctxt);
6452 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6453 xmlXPathFreeObject(hay);
6454 xmlXPathFreeObject(needle);
6455 XP_ERROR(XPATH_INVALID_TYPE);
6456 }
6457 n = xmlStrlen(needle->stringval);
6458 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6459 valuePush(ctxt, xmlXPathNewBoolean(0));
6460 else
6461 valuePush(ctxt, xmlXPathNewBoolean(1));
6462 xmlXPathFreeObject(hay);
6463 xmlXPathFreeObject(needle);
6464}
6465
6466/**
6467 * xmlXPathSubstringFunction:
6468 * @ctxt: the XPath Parser context
6469 * @nargs: the number of arguments
6470 *
6471 * Implement the substring() XPath function
6472 * string substring(string, number, number?)
6473 * The substring function returns the substring of the first argument
6474 * starting at the position specified in the second argument with
6475 * length specified in the third argument. For example,
6476 * substring("12345",2,3) returns "234". If the third argument is not
6477 * specified, it returns the substring starting at the position specified
6478 * in the second argument and continuing to the end of the string. For
6479 * example, substring("12345",2) returns "2345". More precisely, each
6480 * character in the string (see [3.6 Strings]) is considered to have a
6481 * numeric position: the position of the first character is 1, the position
6482 * of the second character is 2 and so on. The returned substring contains
6483 * those characters for which the position of the character is greater than
6484 * or equal to the second argument and, if the third argument is specified,
6485 * less than the sum of the second and third arguments; the comparisons
6486 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6487 * - substring("12345", 1.5, 2.6) returns "234"
6488 * - substring("12345", 0, 3) returns "12"
6489 * - substring("12345", 0 div 0, 3) returns ""
6490 * - substring("12345", 1, 0 div 0) returns ""
6491 * - substring("12345", -42, 1 div 0) returns "12345"
6492 * - substring("12345", -1 div 0, 1 div 0) returns ""
6493 */
6494void
6495xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6496 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006497 double le=0, in;
6498 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006499 xmlChar *ret;
6500
Owen Taylor3473f882001-02-23 17:55:21 +00006501 if (nargs < 2) {
6502 CHECK_ARITY(2);
6503 }
6504 if (nargs > 3) {
6505 CHECK_ARITY(3);
6506 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006507 /*
6508 * take care of possible last (position) argument
6509 */
Owen Taylor3473f882001-02-23 17:55:21 +00006510 if (nargs == 3) {
6511 CAST_TO_NUMBER;
6512 CHECK_TYPE(XPATH_NUMBER);
6513 len = valuePop(ctxt);
6514 le = len->floatval;
6515 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006516 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006517
Owen Taylor3473f882001-02-23 17:55:21 +00006518 CAST_TO_NUMBER;
6519 CHECK_TYPE(XPATH_NUMBER);
6520 start = valuePop(ctxt);
6521 in = start->floatval;
6522 xmlXPathFreeObject(start);
6523 CAST_TO_STRING;
6524 CHECK_TYPE(XPATH_STRING);
6525 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006526 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006527
Daniel Veillard97ac1312001-05-30 19:14:17 +00006528 /*
6529 * If last pos not present, calculate last position
6530 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006531 if (nargs != 3) {
6532 le = (double)m;
6533 if (in < 1.0)
6534 in = 1.0;
6535 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006536
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006537 /* Need to check for the special cases where either
6538 * the index is NaN, the length is NaN, or both
6539 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006540 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006541 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006542 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006543 * To meet the requirements of the spec, the arguments
6544 * must be converted to integer format before
6545 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006546 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006547 * First we go to integer form, rounding up
6548 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006549 */
6550 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006551 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006552
Daniel Veillard9e412302002-06-10 15:59:44 +00006553 if (xmlXPathIsInf(le) == 1) {
6554 l = m;
6555 if (i < 1)
6556 i = 1;
6557 }
6558 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6559 l = 0;
6560 else {
6561 l = (int) le;
6562 if (((double)l)+0.5 <= le) l++;
6563 }
6564
6565 /* Now we normalize inidices */
6566 i -= 1;
6567 l += i;
6568 if (i < 0)
6569 i = 0;
6570 if (l > m)
6571 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006572
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006573 /* number of chars to copy */
6574 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006575
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006576 ret = xmlUTF8Strsub(str->stringval, i, l);
6577 }
6578 else {
6579 ret = NULL;
6580 }
6581
Owen Taylor3473f882001-02-23 17:55:21 +00006582 if (ret == NULL)
6583 valuePush(ctxt, xmlXPathNewCString(""));
6584 else {
6585 valuePush(ctxt, xmlXPathNewString(ret));
6586 xmlFree(ret);
6587 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006588
Owen Taylor3473f882001-02-23 17:55:21 +00006589 xmlXPathFreeObject(str);
6590}
6591
6592/**
6593 * xmlXPathSubstringBeforeFunction:
6594 * @ctxt: the XPath Parser context
6595 * @nargs: the number of arguments
6596 *
6597 * Implement the substring-before() XPath function
6598 * string substring-before(string, string)
6599 * The substring-before function returns the substring of the first
6600 * argument string that precedes the first occurrence of the second
6601 * argument string in the first argument string, or the empty string
6602 * if the first argument string does not contain the second argument
6603 * string. For example, substring-before("1999/04/01","/") returns 1999.
6604 */
6605void
6606xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6607 xmlXPathObjectPtr str;
6608 xmlXPathObjectPtr find;
6609 xmlBufferPtr target;
6610 const xmlChar *point;
6611 int offset;
6612
6613 CHECK_ARITY(2);
6614 CAST_TO_STRING;
6615 find = valuePop(ctxt);
6616 CAST_TO_STRING;
6617 str = valuePop(ctxt);
6618
6619 target = xmlBufferCreate();
6620 if (target) {
6621 point = xmlStrstr(str->stringval, find->stringval);
6622 if (point) {
6623 offset = (int)(point - str->stringval);
6624 xmlBufferAdd(target, str->stringval, offset);
6625 }
6626 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6627 xmlBufferFree(target);
6628 }
6629
6630 xmlXPathFreeObject(str);
6631 xmlXPathFreeObject(find);
6632}
6633
6634/**
6635 * xmlXPathSubstringAfterFunction:
6636 * @ctxt: the XPath Parser context
6637 * @nargs: the number of arguments
6638 *
6639 * Implement the substring-after() XPath function
6640 * string substring-after(string, string)
6641 * The substring-after function returns the substring of the first
6642 * argument string that follows the first occurrence of the second
6643 * argument string in the first argument string, or the empty stringi
6644 * if the first argument string does not contain the second argument
6645 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6646 * and substring-after("1999/04/01","19") returns 99/04/01.
6647 */
6648void
6649xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6650 xmlXPathObjectPtr str;
6651 xmlXPathObjectPtr find;
6652 xmlBufferPtr target;
6653 const xmlChar *point;
6654 int offset;
6655
6656 CHECK_ARITY(2);
6657 CAST_TO_STRING;
6658 find = valuePop(ctxt);
6659 CAST_TO_STRING;
6660 str = valuePop(ctxt);
6661
6662 target = xmlBufferCreate();
6663 if (target) {
6664 point = xmlStrstr(str->stringval, find->stringval);
6665 if (point) {
6666 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6667 xmlBufferAdd(target, &str->stringval[offset],
6668 xmlStrlen(str->stringval) - offset);
6669 }
6670 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6671 xmlBufferFree(target);
6672 }
6673
6674 xmlXPathFreeObject(str);
6675 xmlXPathFreeObject(find);
6676}
6677
6678/**
6679 * xmlXPathNormalizeFunction:
6680 * @ctxt: the XPath Parser context
6681 * @nargs: the number of arguments
6682 *
6683 * Implement the normalize-space() XPath function
6684 * string normalize-space(string?)
6685 * The normalize-space function returns the argument string with white
6686 * space normalized by stripping leading and trailing whitespace
6687 * and replacing sequences of whitespace characters by a single
6688 * space. Whitespace characters are the same allowed by the S production
6689 * in XML. If the argument is omitted, it defaults to the context
6690 * node converted to a string, in other words the value of the context node.
6691 */
6692void
6693xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6694 xmlXPathObjectPtr obj = NULL;
6695 xmlChar *source = NULL;
6696 xmlBufferPtr target;
6697 xmlChar blank;
6698
6699 if (nargs == 0) {
6700 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006701 valuePush(ctxt,
6702 xmlXPathWrapString(
6703 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006704 nargs = 1;
6705 }
6706
6707 CHECK_ARITY(1);
6708 CAST_TO_STRING;
6709 CHECK_TYPE(XPATH_STRING);
6710 obj = valuePop(ctxt);
6711 source = obj->stringval;
6712
6713 target = xmlBufferCreate();
6714 if (target && source) {
6715
6716 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006717 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006718 source++;
6719
6720 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6721 blank = 0;
6722 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006723 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006724 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006725 } else {
6726 if (blank) {
6727 xmlBufferAdd(target, &blank, 1);
6728 blank = 0;
6729 }
6730 xmlBufferAdd(target, source, 1);
6731 }
6732 source++;
6733 }
6734
6735 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6736 xmlBufferFree(target);
6737 }
6738 xmlXPathFreeObject(obj);
6739}
6740
6741/**
6742 * xmlXPathTranslateFunction:
6743 * @ctxt: the XPath Parser context
6744 * @nargs: the number of arguments
6745 *
6746 * Implement the translate() XPath function
6747 * string translate(string, string, string)
6748 * The translate function returns the first argument string with
6749 * occurrences of characters in the second argument string replaced
6750 * by the character at the corresponding position in the third argument
6751 * string. For example, translate("bar","abc","ABC") returns the string
6752 * BAr. If there is a character in the second argument string with no
6753 * character at a corresponding position in the third argument string
6754 * (because the second argument string is longer than the third argument
6755 * string), then occurrences of that character in the first argument
6756 * string are removed. For example, translate("--aaa--","abc-","ABC")
6757 * returns "AAA". If a character occurs more than once in second
6758 * argument string, then the first occurrence determines the replacement
6759 * character. If the third argument string is longer than the second
6760 * argument string, then excess characters are ignored.
6761 */
6762void
6763xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006764 xmlXPathObjectPtr str;
6765 xmlXPathObjectPtr from;
6766 xmlXPathObjectPtr to;
6767 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006768 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006769 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006770 xmlChar *point;
6771 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006772
Daniel Veillarde043ee12001-04-16 14:08:07 +00006773 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006774
Daniel Veillarde043ee12001-04-16 14:08:07 +00006775 CAST_TO_STRING;
6776 to = valuePop(ctxt);
6777 CAST_TO_STRING;
6778 from = valuePop(ctxt);
6779 CAST_TO_STRING;
6780 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006781
Daniel Veillarde043ee12001-04-16 14:08:07 +00006782 target = xmlBufferCreate();
6783 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006784 max = xmlUTF8Strlen(to->stringval);
6785 for (cptr = str->stringval; (ch=*cptr); ) {
6786 offset = xmlUTF8Strloc(from->stringval, cptr);
6787 if (offset >= 0) {
6788 if (offset < max) {
6789 point = xmlUTF8Strpos(to->stringval, offset);
6790 if (point)
6791 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6792 }
6793 } else
6794 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6795
6796 /* Step to next character in input */
6797 cptr++;
6798 if ( ch & 0x80 ) {
6799 /* if not simple ascii, verify proper format */
6800 if ( (ch & 0xc0) != 0xc0 ) {
6801 xmlGenericError(xmlGenericErrorContext,
6802 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6803 break;
6804 }
6805 /* then skip over remaining bytes for this char */
6806 while ( (ch <<= 1) & 0x80 )
6807 if ( (*cptr++ & 0xc0) != 0x80 ) {
6808 xmlGenericError(xmlGenericErrorContext,
6809 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6810 break;
6811 }
6812 if (ch & 0x80) /* must have had error encountered */
6813 break;
6814 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006815 }
Owen Taylor3473f882001-02-23 17:55:21 +00006816 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006817 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6818 xmlBufferFree(target);
6819 xmlXPathFreeObject(str);
6820 xmlXPathFreeObject(from);
6821 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006822}
6823
6824/**
6825 * xmlXPathBooleanFunction:
6826 * @ctxt: the XPath Parser context
6827 * @nargs: the number of arguments
6828 *
6829 * Implement the boolean() XPath function
6830 * boolean boolean(object)
6831 * he boolean function converts its argument to a boolean as follows:
6832 * - a number is true if and only if it is neither positive or
6833 * negative zero nor NaN
6834 * - a node-set is true if and only if it is non-empty
6835 * - a string is true if and only if its length is non-zero
6836 */
6837void
6838xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6839 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006840
6841 CHECK_ARITY(1);
6842 cur = valuePop(ctxt);
6843 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006844 cur = xmlXPathConvertBoolean(cur);
6845 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006846}
6847
6848/**
6849 * xmlXPathNotFunction:
6850 * @ctxt: the XPath Parser context
6851 * @nargs: the number of arguments
6852 *
6853 * Implement the not() XPath function
6854 * boolean not(boolean)
6855 * The not function returns true if its argument is false,
6856 * and false otherwise.
6857 */
6858void
6859xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6860 CHECK_ARITY(1);
6861 CAST_TO_BOOLEAN;
6862 CHECK_TYPE(XPATH_BOOLEAN);
6863 ctxt->value->boolval = ! ctxt->value->boolval;
6864}
6865
6866/**
6867 * xmlXPathTrueFunction:
6868 * @ctxt: the XPath Parser context
6869 * @nargs: the number of arguments
6870 *
6871 * Implement the true() XPath function
6872 * boolean true()
6873 */
6874void
6875xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6876 CHECK_ARITY(0);
6877 valuePush(ctxt, xmlXPathNewBoolean(1));
6878}
6879
6880/**
6881 * xmlXPathFalseFunction:
6882 * @ctxt: the XPath Parser context
6883 * @nargs: the number of arguments
6884 *
6885 * Implement the false() XPath function
6886 * boolean false()
6887 */
6888void
6889xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6890 CHECK_ARITY(0);
6891 valuePush(ctxt, xmlXPathNewBoolean(0));
6892}
6893
6894/**
6895 * xmlXPathLangFunction:
6896 * @ctxt: the XPath Parser context
6897 * @nargs: the number of arguments
6898 *
6899 * Implement the lang() XPath function
6900 * boolean lang(string)
6901 * The lang function returns true or false depending on whether the
6902 * language of the context node as specified by xml:lang attributes
6903 * is the same as or is a sublanguage of the language specified by
6904 * the argument string. The language of the context node is determined
6905 * by the value of the xml:lang attribute on the context node, or, if
6906 * the context node has no xml:lang attribute, by the value of the
6907 * xml:lang attribute on the nearest ancestor of the context node that
6908 * has an xml:lang attribute. If there is no such attribute, then lang
6909 * returns false. If there is such an attribute, then lang returns
6910 * true if the attribute value is equal to the argument ignoring case,
6911 * or if there is some suffix starting with - such that the attribute
6912 * value is equal to the argument ignoring that suffix of the attribute
6913 * value and ignoring case.
6914 */
6915void
6916xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6917 xmlXPathObjectPtr val;
6918 const xmlChar *theLang;
6919 const xmlChar *lang;
6920 int ret = 0;
6921 int i;
6922
6923 CHECK_ARITY(1);
6924 CAST_TO_STRING;
6925 CHECK_TYPE(XPATH_STRING);
6926 val = valuePop(ctxt);
6927 lang = val->stringval;
6928 theLang = xmlNodeGetLang(ctxt->context->node);
6929 if ((theLang != NULL) && (lang != NULL)) {
6930 for (i = 0;lang[i] != 0;i++)
6931 if (toupper(lang[i]) != toupper(theLang[i]))
6932 goto not_equal;
6933 ret = 1;
6934 }
6935not_equal:
6936 xmlXPathFreeObject(val);
6937 valuePush(ctxt, xmlXPathNewBoolean(ret));
6938}
6939
6940/**
6941 * xmlXPathNumberFunction:
6942 * @ctxt: the XPath Parser context
6943 * @nargs: the number of arguments
6944 *
6945 * Implement the number() XPath function
6946 * number number(object?)
6947 */
6948void
6949xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6950 xmlXPathObjectPtr cur;
6951 double res;
6952
6953 if (nargs == 0) {
6954 if (ctxt->context->node == NULL) {
6955 valuePush(ctxt, xmlXPathNewFloat(0.0));
6956 } else {
6957 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6958
6959 res = xmlXPathStringEvalNumber(content);
6960 valuePush(ctxt, xmlXPathNewFloat(res));
6961 xmlFree(content);
6962 }
6963 return;
6964 }
6965
6966 CHECK_ARITY(1);
6967 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006968 cur = xmlXPathConvertNumber(cur);
6969 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006970}
6971
6972/**
6973 * xmlXPathSumFunction:
6974 * @ctxt: the XPath Parser context
6975 * @nargs: the number of arguments
6976 *
6977 * Implement the sum() XPath function
6978 * number sum(node-set)
6979 * The sum function returns the sum of the values of the nodes in
6980 * the argument node-set.
6981 */
6982void
6983xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6984 xmlXPathObjectPtr cur;
6985 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006986 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006987
6988 CHECK_ARITY(1);
6989 if ((ctxt->value == NULL) ||
6990 ((ctxt->value->type != XPATH_NODESET) &&
6991 (ctxt->value->type != XPATH_XSLT_TREE)))
6992 XP_ERROR(XPATH_INVALID_TYPE);
6993 cur = valuePop(ctxt);
6994
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006995 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006996 valuePush(ctxt, xmlXPathNewFloat(0.0));
6997 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006998 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6999 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007000 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007001 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007002 }
7003 xmlXPathFreeObject(cur);
7004}
7005
7006/**
7007 * xmlXPathFloorFunction:
7008 * @ctxt: the XPath Parser context
7009 * @nargs: the number of arguments
7010 *
7011 * Implement the floor() XPath function
7012 * number floor(number)
7013 * The floor function returns the largest (closest to positive infinity)
7014 * number that is not greater than the argument and that is an integer.
7015 */
7016void
7017xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007018 double f;
7019
Owen Taylor3473f882001-02-23 17:55:21 +00007020 CHECK_ARITY(1);
7021 CAST_TO_NUMBER;
7022 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007023
7024 f = (double)((int) ctxt->value->floatval);
7025 if (f != ctxt->value->floatval) {
7026 if (ctxt->value->floatval > 0)
7027 ctxt->value->floatval = f;
7028 else
7029 ctxt->value->floatval = f - 1;
7030 }
Owen Taylor3473f882001-02-23 17:55:21 +00007031}
7032
7033/**
7034 * xmlXPathCeilingFunction:
7035 * @ctxt: the XPath Parser context
7036 * @nargs: the number of arguments
7037 *
7038 * Implement the ceiling() XPath function
7039 * number ceiling(number)
7040 * The ceiling function returns the smallest (closest to negative infinity)
7041 * number that is not less than the argument and that is an integer.
7042 */
7043void
7044xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7045 double f;
7046
7047 CHECK_ARITY(1);
7048 CAST_TO_NUMBER;
7049 CHECK_TYPE(XPATH_NUMBER);
7050
7051#if 0
7052 ctxt->value->floatval = ceil(ctxt->value->floatval);
7053#else
7054 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007055 if (f != ctxt->value->floatval) {
7056 if (ctxt->value->floatval > 0)
7057 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007058 else {
7059 if (ctxt->value->floatval < 0 && f == 0)
7060 ctxt->value->floatval = xmlXPathNZERO;
7061 else
7062 ctxt->value->floatval = f;
7063 }
7064
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007065 }
Owen Taylor3473f882001-02-23 17:55:21 +00007066#endif
7067}
7068
7069/**
7070 * xmlXPathRoundFunction:
7071 * @ctxt: the XPath Parser context
7072 * @nargs: the number of arguments
7073 *
7074 * Implement the round() XPath function
7075 * number round(number)
7076 * The round function returns the number that is closest to the
7077 * argument and that is an integer. If there are two such numbers,
7078 * then the one that is even is returned.
7079 */
7080void
7081xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7082 double f;
7083
7084 CHECK_ARITY(1);
7085 CAST_TO_NUMBER;
7086 CHECK_TYPE(XPATH_NUMBER);
7087
Daniel Veillardcda96922001-08-21 10:56:31 +00007088 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7089 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7090 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007091 (ctxt->value->floatval == 0.0))
7092 return;
7093
Owen Taylor3473f882001-02-23 17:55:21 +00007094 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007095 if (ctxt->value->floatval < 0) {
7096 if (ctxt->value->floatval < f - 0.5)
7097 ctxt->value->floatval = f - 1;
7098 else
7099 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007100 if (ctxt->value->floatval == 0)
7101 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007102 } else {
7103 if (ctxt->value->floatval < f + 0.5)
7104 ctxt->value->floatval = f;
7105 else
7106 ctxt->value->floatval = f + 1;
7107 }
Owen Taylor3473f882001-02-23 17:55:21 +00007108}
7109
7110/************************************************************************
7111 * *
7112 * The Parser *
7113 * *
7114 ************************************************************************/
7115
7116/*
7117 * a couple of forward declarations since we use a recursive call based
7118 * implementation.
7119 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007120static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007121static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007122static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007123static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007124static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7125 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007126
7127/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007128 * xmlXPathCurrentChar:
7129 * @ctxt: the XPath parser context
7130 * @cur: pointer to the beginning of the char
7131 * @len: pointer to the length of the char read
7132 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007133 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007134 * bytes in the input buffer.
7135 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007136 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007137 */
7138
7139static int
7140xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7141 unsigned char c;
7142 unsigned int val;
7143 const xmlChar *cur;
7144
7145 if (ctxt == NULL)
7146 return(0);
7147 cur = ctxt->cur;
7148
7149 /*
7150 * We are supposed to handle UTF8, check it's valid
7151 * From rfc2044: encoding of the Unicode values on UTF-8:
7152 *
7153 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7154 * 0000 0000-0000 007F 0xxxxxxx
7155 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7156 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7157 *
7158 * Check for the 0x110000 limit too
7159 */
7160 c = *cur;
7161 if (c & 0x80) {
7162 if ((cur[1] & 0xc0) != 0x80)
7163 goto encoding_error;
7164 if ((c & 0xe0) == 0xe0) {
7165
7166 if ((cur[2] & 0xc0) != 0x80)
7167 goto encoding_error;
7168 if ((c & 0xf0) == 0xf0) {
7169 if (((c & 0xf8) != 0xf0) ||
7170 ((cur[3] & 0xc0) != 0x80))
7171 goto encoding_error;
7172 /* 4-byte code */
7173 *len = 4;
7174 val = (cur[0] & 0x7) << 18;
7175 val |= (cur[1] & 0x3f) << 12;
7176 val |= (cur[2] & 0x3f) << 6;
7177 val |= cur[3] & 0x3f;
7178 } else {
7179 /* 3-byte code */
7180 *len = 3;
7181 val = (cur[0] & 0xf) << 12;
7182 val |= (cur[1] & 0x3f) << 6;
7183 val |= cur[2] & 0x3f;
7184 }
7185 } else {
7186 /* 2-byte code */
7187 *len = 2;
7188 val = (cur[0] & 0x1f) << 6;
7189 val |= cur[1] & 0x3f;
7190 }
7191 if (!IS_CHAR(val)) {
7192 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7193 }
7194 return(val);
7195 } else {
7196 /* 1-byte code */
7197 *len = 1;
7198 return((int) *cur);
7199 }
7200encoding_error:
7201 /*
7202 * If we detect an UTF8 error that probably mean that the
7203 * input encoding didn't get properly advertized in the
7204 * declaration header. Report the error and switch the encoding
7205 * to ISO-Latin-1 (if you don't like this policy, just declare the
7206 * encoding !)
7207 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007208 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007209 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007210}
7211
7212/**
Owen Taylor3473f882001-02-23 17:55:21 +00007213 * xmlXPathParseNCName:
7214 * @ctxt: the XPath Parser context
7215 *
7216 * parse an XML namespace non qualified name.
7217 *
7218 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7219 *
7220 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7221 * CombiningChar | Extender
7222 *
7223 * Returns the namespace name or NULL
7224 */
7225
7226xmlChar *
7227xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007228 const xmlChar *in;
7229 xmlChar *ret;
7230 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007231
Daniel Veillard2156a562001-04-28 12:24:34 +00007232 /*
7233 * Accelerator for simple ASCII names
7234 */
7235 in = ctxt->cur;
7236 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7237 ((*in >= 0x41) && (*in <= 0x5A)) ||
7238 (*in == '_')) {
7239 in++;
7240 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7241 ((*in >= 0x41) && (*in <= 0x5A)) ||
7242 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007243 (*in == '_') || (*in == '.') ||
7244 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007245 in++;
7246 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7247 (*in == '[') || (*in == ']') || (*in == ':') ||
7248 (*in == '@') || (*in == '*')) {
7249 count = in - ctxt->cur;
7250 if (count == 0)
7251 return(NULL);
7252 ret = xmlStrndup(ctxt->cur, count);
7253 ctxt->cur = in;
7254 return(ret);
7255 }
7256 }
7257 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007258}
7259
Daniel Veillard2156a562001-04-28 12:24:34 +00007260
Owen Taylor3473f882001-02-23 17:55:21 +00007261/**
7262 * xmlXPathParseQName:
7263 * @ctxt: the XPath Parser context
7264 * @prefix: a xmlChar **
7265 *
7266 * parse an XML qualified name
7267 *
7268 * [NS 5] QName ::= (Prefix ':')? LocalPart
7269 *
7270 * [NS 6] Prefix ::= NCName
7271 *
7272 * [NS 7] LocalPart ::= NCName
7273 *
7274 * Returns the function returns the local part, and prefix is updated
7275 * to get the Prefix if any.
7276 */
7277
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007278static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007279xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7280 xmlChar *ret = NULL;
7281
7282 *prefix = NULL;
7283 ret = xmlXPathParseNCName(ctxt);
7284 if (CUR == ':') {
7285 *prefix = ret;
7286 NEXT;
7287 ret = xmlXPathParseNCName(ctxt);
7288 }
7289 return(ret);
7290}
7291
7292/**
7293 * xmlXPathParseName:
7294 * @ctxt: the XPath Parser context
7295 *
7296 * parse an XML name
7297 *
7298 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7299 * CombiningChar | Extender
7300 *
7301 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7302 *
7303 * Returns the namespace name or NULL
7304 */
7305
7306xmlChar *
7307xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007308 const xmlChar *in;
7309 xmlChar *ret;
7310 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007311
Daniel Veillard61d80a22001-04-27 17:13:01 +00007312 /*
7313 * Accelerator for simple ASCII names
7314 */
7315 in = ctxt->cur;
7316 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7317 ((*in >= 0x41) && (*in <= 0x5A)) ||
7318 (*in == '_') || (*in == ':')) {
7319 in++;
7320 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7321 ((*in >= 0x41) && (*in <= 0x5A)) ||
7322 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007323 (*in == '_') || (*in == '-') ||
7324 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007325 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007326 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007327 count = in - ctxt->cur;
7328 ret = xmlStrndup(ctxt->cur, count);
7329 ctxt->cur = in;
7330 return(ret);
7331 }
7332 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007333 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007334}
7335
Daniel Veillard61d80a22001-04-27 17:13:01 +00007336static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007337xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007338 xmlChar buf[XML_MAX_NAMELEN + 5];
7339 int len = 0, l;
7340 int c;
7341
7342 /*
7343 * Handler for more complex cases
7344 */
7345 c = CUR_CHAR(l);
7346 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007347 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7348 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007349 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007350 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007351 return(NULL);
7352 }
7353
7354 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7355 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7356 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007357 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007358 (IS_COMBINING(c)) ||
7359 (IS_EXTENDER(c)))) {
7360 COPY_BUF(l,buf,len,c);
7361 NEXTL(l);
7362 c = CUR_CHAR(l);
7363 if (len >= XML_MAX_NAMELEN) {
7364 /*
7365 * Okay someone managed to make a huge name, so he's ready to pay
7366 * for the processing speed.
7367 */
7368 xmlChar *buffer;
7369 int max = len * 2;
7370
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007371 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007372 if (buffer == NULL) {
7373 XP_ERROR0(XPATH_MEMORY_ERROR);
7374 }
7375 memcpy(buffer, buf, len);
7376 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7377 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007378 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007379 (IS_COMBINING(c)) ||
7380 (IS_EXTENDER(c))) {
7381 if (len + 10 > max) {
7382 max *= 2;
7383 buffer = (xmlChar *) xmlRealloc(buffer,
7384 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007385 if (buffer == NULL) {
7386 XP_ERROR0(XPATH_MEMORY_ERROR);
7387 }
7388 }
7389 COPY_BUF(l,buffer,len,c);
7390 NEXTL(l);
7391 c = CUR_CHAR(l);
7392 }
7393 buffer[len] = 0;
7394 return(buffer);
7395 }
7396 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007397 if (len == 0)
7398 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007399 return(xmlStrndup(buf, len));
7400}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007401
7402#define MAX_FRAC 20
7403
7404static double my_pow10[MAX_FRAC] = {
7405 1.0, 10.0, 100.0, 1000.0, 10000.0,
7406 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7407 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7408 100000000000000.0,
7409 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7410 1000000000000000000.0, 10000000000000000000.0
7411};
7412
Owen Taylor3473f882001-02-23 17:55:21 +00007413/**
7414 * xmlXPathStringEvalNumber:
7415 * @str: A string to scan
7416 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007417 * [30a] Float ::= Number ('e' Digits?)?
7418 *
Owen Taylor3473f882001-02-23 17:55:21 +00007419 * [30] Number ::= Digits ('.' Digits?)?
7420 * | '.' Digits
7421 * [31] Digits ::= [0-9]+
7422 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007423 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007424 * In complement of the Number expression, this function also handles
7425 * negative values : '-' Number.
7426 *
7427 * Returns the double value.
7428 */
7429double
7430xmlXPathStringEvalNumber(const xmlChar *str) {
7431 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007432 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007433 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007434 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007435 int exponent = 0;
7436 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007437#ifdef __GNUC__
7438 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007439 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007440#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007441 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007442 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007443 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7444 return(xmlXPathNAN);
7445 }
7446 if (*cur == '-') {
7447 isneg = 1;
7448 cur++;
7449 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007450
7451#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007452 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007453 * tmp/temp is a workaround against a gcc compiler bug
7454 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007455 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007456 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007457 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007458 ret = ret * 10;
7459 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007460 ok = 1;
7461 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007462 temp = (double) tmp;
7463 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007464 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007465#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007466 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007467 while ((*cur >= '0') && (*cur <= '9')) {
7468 ret = ret * 10 + (*cur - '0');
7469 ok = 1;
7470 cur++;
7471 }
7472#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007473
Owen Taylor3473f882001-02-23 17:55:21 +00007474 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007475 int v, frac = 0;
7476 double fraction = 0;
7477
Owen Taylor3473f882001-02-23 17:55:21 +00007478 cur++;
7479 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7480 return(xmlXPathNAN);
7481 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007482 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7483 v = (*cur - '0');
7484 fraction = fraction * 10 + v;
7485 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007486 cur++;
7487 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007488 fraction /= my_pow10[frac];
7489 ret = ret + fraction;
7490 while ((*cur >= '0') && (*cur <= '9'))
7491 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007492 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007493 if ((*cur == 'e') || (*cur == 'E')) {
7494 cur++;
7495 if (*cur == '-') {
7496 is_exponent_negative = 1;
7497 cur++;
7498 }
7499 while ((*cur >= '0') && (*cur <= '9')) {
7500 exponent = exponent * 10 + (*cur - '0');
7501 cur++;
7502 }
7503 }
William M. Brack76e95df2003-10-18 16:20:14 +00007504 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007505 if (*cur != 0) return(xmlXPathNAN);
7506 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007507 if (is_exponent_negative) exponent = -exponent;
7508 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007509 return(ret);
7510}
7511
7512/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007513 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007514 * @ctxt: the XPath Parser context
7515 *
7516 * [30] Number ::= Digits ('.' Digits?)?
7517 * | '.' Digits
7518 * [31] Digits ::= [0-9]+
7519 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007520 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007521 *
7522 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007523static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007524xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7525{
Owen Taylor3473f882001-02-23 17:55:21 +00007526 double ret = 0.0;
7527 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007528 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007529 int exponent = 0;
7530 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007531#ifdef __GNUC__
7532 unsigned long tmp = 0;
7533 double temp;
7534#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007535
7536 CHECK_ERROR;
7537 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7538 XP_ERROR(XPATH_NUMBER_ERROR);
7539 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007540#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007541 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007542 * tmp/temp is a workaround against a gcc compiler bug
7543 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007544 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007545 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007546 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007547 ret = ret * 10;
7548 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007549 ok = 1;
7550 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007551 temp = (double) tmp;
7552 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007553 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007554#else
7555 ret = 0;
7556 while ((CUR >= '0') && (CUR <= '9')) {
7557 ret = ret * 10 + (CUR - '0');
7558 ok = 1;
7559 NEXT;
7560 }
7561#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007562 if (CUR == '.') {
7563 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007564 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7565 XP_ERROR(XPATH_NUMBER_ERROR);
7566 }
7567 while ((CUR >= '0') && (CUR <= '9')) {
7568 mult /= 10;
7569 ret = ret + (CUR - '0') * mult;
7570 NEXT;
7571 }
Owen Taylor3473f882001-02-23 17:55:21 +00007572 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007573 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007574 NEXT;
7575 if (CUR == '-') {
7576 is_exponent_negative = 1;
7577 NEXT;
7578 }
7579 while ((CUR >= '0') && (CUR <= '9')) {
7580 exponent = exponent * 10 + (CUR - '0');
7581 NEXT;
7582 }
7583 if (is_exponent_negative)
7584 exponent = -exponent;
7585 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007586 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007587 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007588 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007589}
7590
7591/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007592 * xmlXPathParseLiteral:
7593 * @ctxt: the XPath Parser context
7594 *
7595 * Parse a Literal
7596 *
7597 * [29] Literal ::= '"' [^"]* '"'
7598 * | "'" [^']* "'"
7599 *
7600 * Returns the value found or NULL in case of error
7601 */
7602static xmlChar *
7603xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7604 const xmlChar *q;
7605 xmlChar *ret = NULL;
7606
7607 if (CUR == '"') {
7608 NEXT;
7609 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007610 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007611 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007612 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007613 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7614 } else {
7615 ret = xmlStrndup(q, CUR_PTR - q);
7616 NEXT;
7617 }
7618 } else if (CUR == '\'') {
7619 NEXT;
7620 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007621 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007622 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007623 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007624 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7625 } else {
7626 ret = xmlStrndup(q, CUR_PTR - q);
7627 NEXT;
7628 }
7629 } else {
7630 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7631 }
7632 return(ret);
7633}
7634
7635/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007636 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007637 * @ctxt: the XPath Parser context
7638 *
7639 * Parse a Literal and push it on the stack.
7640 *
7641 * [29] Literal ::= '"' [^"]* '"'
7642 * | "'" [^']* "'"
7643 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007644 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007645 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007646static void
7647xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007648 const xmlChar *q;
7649 xmlChar *ret = NULL;
7650
7651 if (CUR == '"') {
7652 NEXT;
7653 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007654 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007655 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007656 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007657 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7658 } else {
7659 ret = xmlStrndup(q, CUR_PTR - q);
7660 NEXT;
7661 }
7662 } else if (CUR == '\'') {
7663 NEXT;
7664 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007665 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007666 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007667 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007668 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7669 } else {
7670 ret = xmlStrndup(q, CUR_PTR - q);
7671 NEXT;
7672 }
7673 } else {
7674 XP_ERROR(XPATH_START_LITERAL_ERROR);
7675 }
7676 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007677 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7678 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007679 xmlFree(ret);
7680}
7681
7682/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007683 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007684 * @ctxt: the XPath Parser context
7685 *
7686 * Parse a VariableReference, evaluate it and push it on the stack.
7687 *
7688 * The variable bindings consist of a mapping from variable names
7689 * to variable values. The value of a variable is an object, which
7690 * of any of the types that are possible for the value of an expression,
7691 * and may also be of additional types not specified here.
7692 *
7693 * Early evaluation is possible since:
7694 * The variable bindings [...] used to evaluate a subexpression are
7695 * always the same as those used to evaluate the containing expression.
7696 *
7697 * [36] VariableReference ::= '$' QName
7698 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007699static void
7700xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007701 xmlChar *name;
7702 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007703
7704 SKIP_BLANKS;
7705 if (CUR != '$') {
7706 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7707 }
7708 NEXT;
7709 name = xmlXPathParseQName(ctxt, &prefix);
7710 if (name == NULL) {
7711 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7712 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007713 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007714 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7715 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007716 SKIP_BLANKS;
7717}
7718
7719/**
7720 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007721 * @name: a name string
7722 *
7723 * Is the name given a NodeType one.
7724 *
7725 * [38] NodeType ::= 'comment'
7726 * | 'text'
7727 * | 'processing-instruction'
7728 * | 'node'
7729 *
7730 * Returns 1 if true 0 otherwise
7731 */
7732int
7733xmlXPathIsNodeType(const xmlChar *name) {
7734 if (name == NULL)
7735 return(0);
7736
Daniel Veillard1971ee22002-01-31 20:29:19 +00007737 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007738 return(1);
7739 if (xmlStrEqual(name, BAD_CAST "text"))
7740 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007741 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007742 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007743 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007744 return(1);
7745 return(0);
7746}
7747
7748/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007749 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007750 * @ctxt: the XPath Parser context
7751 *
7752 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7753 * [17] Argument ::= Expr
7754 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007755 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007756 * pushed on the stack
7757 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007758static void
7759xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007760 xmlChar *name;
7761 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007762 int nbargs = 0;
7763
7764 name = xmlXPathParseQName(ctxt, &prefix);
7765 if (name == NULL) {
7766 XP_ERROR(XPATH_EXPR_ERROR);
7767 }
7768 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007769#ifdef DEBUG_EXPR
7770 if (prefix == NULL)
7771 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7772 name);
7773 else
7774 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7775 prefix, name);
7776#endif
7777
Owen Taylor3473f882001-02-23 17:55:21 +00007778 if (CUR != '(') {
7779 XP_ERROR(XPATH_EXPR_ERROR);
7780 }
7781 NEXT;
7782 SKIP_BLANKS;
7783
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007784 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007785 if (CUR != ')') {
7786 while (CUR != 0) {
7787 int op1 = ctxt->comp->last;
7788 ctxt->comp->last = -1;
7789 xmlXPathCompileExpr(ctxt);
7790 CHECK_ERROR;
7791 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7792 nbargs++;
7793 if (CUR == ')') break;
7794 if (CUR != ',') {
7795 XP_ERROR(XPATH_EXPR_ERROR);
7796 }
7797 NEXT;
7798 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007799 }
Owen Taylor3473f882001-02-23 17:55:21 +00007800 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007801 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7802 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007803 NEXT;
7804 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007805}
7806
7807/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007808 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007809 * @ctxt: the XPath Parser context
7810 *
7811 * [15] PrimaryExpr ::= VariableReference
7812 * | '(' Expr ')'
7813 * | Literal
7814 * | Number
7815 * | FunctionCall
7816 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007817 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007818 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007819static void
7820xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007821 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007822 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007823 else if (CUR == '(') {
7824 NEXT;
7825 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007826 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007827 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007828 if (CUR != ')') {
7829 XP_ERROR(XPATH_EXPR_ERROR);
7830 }
7831 NEXT;
7832 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007833 } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007834 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007835 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007836 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007837 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007838 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007839 }
7840 SKIP_BLANKS;
7841}
7842
7843/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007844 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007845 * @ctxt: the XPath Parser context
7846 *
7847 * [20] FilterExpr ::= PrimaryExpr
7848 * | FilterExpr Predicate
7849 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007850 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007851 * Square brackets are used to filter expressions in the same way that
7852 * they are used in location paths. It is an error if the expression to
7853 * be filtered does not evaluate to a node-set. The context node list
7854 * used for evaluating the expression in square brackets is the node-set
7855 * to be filtered listed in document order.
7856 */
7857
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007858static void
7859xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7860 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007861 CHECK_ERROR;
7862 SKIP_BLANKS;
7863
7864 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007865 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007866 SKIP_BLANKS;
7867 }
7868
7869
7870}
7871
7872/**
7873 * xmlXPathScanName:
7874 * @ctxt: the XPath Parser context
7875 *
7876 * Trickery: parse an XML name but without consuming the input flow
7877 * Needed to avoid insanity in the parser state.
7878 *
7879 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7880 * CombiningChar | Extender
7881 *
7882 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7883 *
7884 * [6] Names ::= Name (S Name)*
7885 *
7886 * Returns the Name parsed or NULL
7887 */
7888
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007889static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007890xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7891 xmlChar buf[XML_MAX_NAMELEN];
7892 int len = 0;
7893
7894 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007895 if (!IS_LETTER_CH(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00007896 (CUR != ':')) {
7897 return(NULL);
7898 }
7899
William M. Brack76e95df2003-10-18 16:20:14 +00007900 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007901 (NXT(len) == '.') || (NXT(len) == '-') ||
7902 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007903 (IS_COMBINING_CH(NXT(len))) ||
7904 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007905 buf[len] = NXT(len);
7906 len++;
7907 if (len >= XML_MAX_NAMELEN) {
7908 xmlGenericError(xmlGenericErrorContext,
7909 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brack76e95df2003-10-18 16:20:14 +00007910 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007911 (NXT(len) == '.') || (NXT(len) == '-') ||
7912 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007913 (IS_COMBINING_CH(NXT(len))) ||
7914 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00007915 len++;
7916 break;
7917 }
7918 }
7919 return(xmlStrndup(buf, len));
7920}
7921
7922/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007923 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007924 * @ctxt: the XPath Parser context
7925 *
7926 * [19] PathExpr ::= LocationPath
7927 * | FilterExpr
7928 * | FilterExpr '/' RelativeLocationPath
7929 * | FilterExpr '//' RelativeLocationPath
7930 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007931 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007932 * The / operator and // operators combine an arbitrary expression
7933 * and a relative location path. It is an error if the expression
7934 * does not evaluate to a node-set.
7935 * The / operator does composition in the same way as when / is
7936 * used in a location path. As in location paths, // is short for
7937 * /descendant-or-self::node()/.
7938 */
7939
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007940static void
7941xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007942 int lc = 1; /* Should we branch to LocationPath ? */
7943 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7944
7945 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007946 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
7947 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007948 lc = 0;
7949 } else if (CUR == '*') {
7950 /* relative or absolute location path */
7951 lc = 1;
7952 } else if (CUR == '/') {
7953 /* relative or absolute location path */
7954 lc = 1;
7955 } else if (CUR == '@') {
7956 /* relative abbreviated attribute location path */
7957 lc = 1;
7958 } else if (CUR == '.') {
7959 /* relative abbreviated attribute location path */
7960 lc = 1;
7961 } else {
7962 /*
7963 * Problem is finding if we have a name here whether it's:
7964 * - a nodetype
7965 * - a function call in which case it's followed by '('
7966 * - an axis in which case it's followed by ':'
7967 * - a element name
7968 * We do an a priori analysis here rather than having to
7969 * maintain parsed token content through the recursive function
7970 * calls. This looks uglier but makes the code quite easier to
7971 * read/write/debug.
7972 */
7973 SKIP_BLANKS;
7974 name = xmlXPathScanName(ctxt);
7975 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7976#ifdef DEBUG_STEP
7977 xmlGenericError(xmlGenericErrorContext,
7978 "PathExpr: Axis\n");
7979#endif
7980 lc = 1;
7981 xmlFree(name);
7982 } else if (name != NULL) {
7983 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00007984
7985
7986 while (NXT(len) != 0) {
7987 if (NXT(len) == '/') {
7988 /* element name */
7989#ifdef DEBUG_STEP
7990 xmlGenericError(xmlGenericErrorContext,
7991 "PathExpr: AbbrRelLocation\n");
7992#endif
7993 lc = 1;
7994 break;
William M. Brack76e95df2003-10-18 16:20:14 +00007995 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00007996 /* ignore blanks */
7997 ;
Owen Taylor3473f882001-02-23 17:55:21 +00007998 } else if (NXT(len) == ':') {
7999#ifdef DEBUG_STEP
8000 xmlGenericError(xmlGenericErrorContext,
8001 "PathExpr: AbbrRelLocation\n");
8002#endif
8003 lc = 1;
8004 break;
8005 } else if ((NXT(len) == '(')) {
8006 /* Note Type or Function */
8007 if (xmlXPathIsNodeType(name)) {
8008#ifdef DEBUG_STEP
8009 xmlGenericError(xmlGenericErrorContext,
8010 "PathExpr: Type search\n");
8011#endif
8012 lc = 1;
8013 } else {
8014#ifdef DEBUG_STEP
8015 xmlGenericError(xmlGenericErrorContext,
8016 "PathExpr: function call\n");
8017#endif
8018 lc = 0;
8019 }
8020 break;
8021 } else if ((NXT(len) == '[')) {
8022 /* element name */
8023#ifdef DEBUG_STEP
8024 xmlGenericError(xmlGenericErrorContext,
8025 "PathExpr: AbbrRelLocation\n");
8026#endif
8027 lc = 1;
8028 break;
8029 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8030 (NXT(len) == '=')) {
8031 lc = 1;
8032 break;
8033 } else {
8034 lc = 1;
8035 break;
8036 }
8037 len++;
8038 }
8039 if (NXT(len) == 0) {
8040#ifdef DEBUG_STEP
8041 xmlGenericError(xmlGenericErrorContext,
8042 "PathExpr: AbbrRelLocation\n");
8043#endif
8044 /* element name */
8045 lc = 1;
8046 }
8047 xmlFree(name);
8048 } else {
8049 /* make sure all cases are covered explicitely */
8050 XP_ERROR(XPATH_EXPR_ERROR);
8051 }
8052 }
8053
8054 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008055 if (CUR == '/') {
8056 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8057 } else {
8058 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008059 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008060 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008061 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008062 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008063 CHECK_ERROR;
8064 if ((CUR == '/') && (NXT(1) == '/')) {
8065 SKIP(2);
8066 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008067
8068 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8069 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8070 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8071
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008072 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008073 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008074 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008075 }
8076 }
8077 SKIP_BLANKS;
8078}
8079
8080/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008081 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008082 * @ctxt: the XPath Parser context
8083 *
8084 * [18] UnionExpr ::= PathExpr
8085 * | UnionExpr '|' PathExpr
8086 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008087 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008088 */
8089
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008090static void
8091xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8092 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008093 CHECK_ERROR;
8094 SKIP_BLANKS;
8095 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008096 int op1 = ctxt->comp->last;
8097 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008098
8099 NEXT;
8100 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008101 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008102
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008103 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8104
Owen Taylor3473f882001-02-23 17:55:21 +00008105 SKIP_BLANKS;
8106 }
Owen Taylor3473f882001-02-23 17:55:21 +00008107}
8108
8109/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008110 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008111 * @ctxt: the XPath Parser context
8112 *
8113 * [27] UnaryExpr ::= UnionExpr
8114 * | '-' UnaryExpr
8115 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008116 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008117 */
8118
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008119static void
8120xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008121 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008122 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008123
8124 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008125 while (CUR == '-') {
8126 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008127 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008128 NEXT;
8129 SKIP_BLANKS;
8130 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008131
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008132 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008133 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008134 if (found) {
8135 if (minus)
8136 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8137 else
8138 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008139 }
8140}
8141
8142/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008143 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008144 * @ctxt: the XPath Parser context
8145 *
8146 * [26] MultiplicativeExpr ::= UnaryExpr
8147 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8148 * | MultiplicativeExpr 'div' UnaryExpr
8149 * | MultiplicativeExpr 'mod' UnaryExpr
8150 * [34] MultiplyOperator ::= '*'
8151 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008152 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008153 */
8154
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008155static void
8156xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8157 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008158 CHECK_ERROR;
8159 SKIP_BLANKS;
8160 while ((CUR == '*') ||
8161 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8162 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8163 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008164 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008165
8166 if (CUR == '*') {
8167 op = 0;
8168 NEXT;
8169 } else if (CUR == 'd') {
8170 op = 1;
8171 SKIP(3);
8172 } else if (CUR == 'm') {
8173 op = 2;
8174 SKIP(3);
8175 }
8176 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008177 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008178 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008179 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008180 SKIP_BLANKS;
8181 }
8182}
8183
8184/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008185 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008186 * @ctxt: the XPath Parser context
8187 *
8188 * [25] AdditiveExpr ::= MultiplicativeExpr
8189 * | AdditiveExpr '+' MultiplicativeExpr
8190 * | AdditiveExpr '-' MultiplicativeExpr
8191 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008192 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008193 */
8194
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008195static void
8196xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008197
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008198 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008199 CHECK_ERROR;
8200 SKIP_BLANKS;
8201 while ((CUR == '+') || (CUR == '-')) {
8202 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008203 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008204
8205 if (CUR == '+') plus = 1;
8206 else plus = 0;
8207 NEXT;
8208 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008209 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008210 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008211 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008212 SKIP_BLANKS;
8213 }
8214}
8215
8216/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008217 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008218 * @ctxt: the XPath Parser context
8219 *
8220 * [24] RelationalExpr ::= AdditiveExpr
8221 * | RelationalExpr '<' AdditiveExpr
8222 * | RelationalExpr '>' AdditiveExpr
8223 * | RelationalExpr '<=' AdditiveExpr
8224 * | RelationalExpr '>=' AdditiveExpr
8225 *
8226 * A <= B > C is allowed ? Answer from James, yes with
8227 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8228 * which is basically what got implemented.
8229 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008230 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008231 * on the stack
8232 */
8233
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008234static void
8235xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8236 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008237 CHECK_ERROR;
8238 SKIP_BLANKS;
8239 while ((CUR == '<') ||
8240 (CUR == '>') ||
8241 ((CUR == '<') && (NXT(1) == '=')) ||
8242 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008243 int inf, strict;
8244 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008245
8246 if (CUR == '<') inf = 1;
8247 else inf = 0;
8248 if (NXT(1) == '=') strict = 0;
8249 else strict = 1;
8250 NEXT;
8251 if (!strict) NEXT;
8252 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008253 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008254 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008255 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008256 SKIP_BLANKS;
8257 }
8258}
8259
8260/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008261 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008262 * @ctxt: the XPath Parser context
8263 *
8264 * [23] EqualityExpr ::= RelationalExpr
8265 * | EqualityExpr '=' RelationalExpr
8266 * | EqualityExpr '!=' RelationalExpr
8267 *
8268 * A != B != C is allowed ? Answer from James, yes with
8269 * (RelationalExpr = RelationalExpr) = RelationalExpr
8270 * (RelationalExpr != RelationalExpr) != RelationalExpr
8271 * which is basically what got implemented.
8272 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008273 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008274 *
8275 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008276static void
8277xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8278 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008279 CHECK_ERROR;
8280 SKIP_BLANKS;
8281 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008282 int eq;
8283 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008284
8285 if (CUR == '=') eq = 1;
8286 else eq = 0;
8287 NEXT;
8288 if (!eq) NEXT;
8289 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008290 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008291 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008292 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008293 SKIP_BLANKS;
8294 }
8295}
8296
8297/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008298 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008299 * @ctxt: the XPath Parser context
8300 *
8301 * [22] AndExpr ::= EqualityExpr
8302 * | AndExpr 'and' EqualityExpr
8303 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008304 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008305 *
8306 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008307static void
8308xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8309 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008310 CHECK_ERROR;
8311 SKIP_BLANKS;
8312 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008313 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008314 SKIP(3);
8315 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008316 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008317 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008318 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008319 SKIP_BLANKS;
8320 }
8321}
8322
8323/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008324 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008325 * @ctxt: the XPath Parser context
8326 *
8327 * [14] Expr ::= OrExpr
8328 * [21] OrExpr ::= AndExpr
8329 * | OrExpr 'or' AndExpr
8330 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008331 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008332 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008333static void
8334xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8335 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008336 CHECK_ERROR;
8337 SKIP_BLANKS;
8338 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008339 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008340 SKIP(2);
8341 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008342 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008343 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008344 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8345 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008346 SKIP_BLANKS;
8347 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008348 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8349 /* more ops could be optimized too */
8350 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8351 }
Owen Taylor3473f882001-02-23 17:55:21 +00008352}
8353
8354/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008355 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008356 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008357 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008358 *
8359 * [8] Predicate ::= '[' PredicateExpr ']'
8360 * [9] PredicateExpr ::= Expr
8361 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008362 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008363 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008364static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008365xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008366 int op1 = ctxt->comp->last;
8367
8368 SKIP_BLANKS;
8369 if (CUR != '[') {
8370 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8371 }
8372 NEXT;
8373 SKIP_BLANKS;
8374
8375 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008376 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008377 CHECK_ERROR;
8378
8379 if (CUR != ']') {
8380 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8381 }
8382
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008383 if (filter)
8384 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8385 else
8386 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008387
8388 NEXT;
8389 SKIP_BLANKS;
8390}
8391
8392/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008393 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008394 * @ctxt: the XPath Parser context
8395 * @test: pointer to a xmlXPathTestVal
8396 * @type: pointer to a xmlXPathTypeVal
8397 * @prefix: placeholder for a possible name prefix
8398 *
8399 * [7] NodeTest ::= NameTest
8400 * | NodeType '(' ')'
8401 * | 'processing-instruction' '(' Literal ')'
8402 *
8403 * [37] NameTest ::= '*'
8404 * | NCName ':' '*'
8405 * | QName
8406 * [38] NodeType ::= 'comment'
8407 * | 'text'
8408 * | 'processing-instruction'
8409 * | 'node'
8410 *
8411 * Returns the name found and update @test, @type and @prefix appropriately
8412 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008413static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008414xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8415 xmlXPathTypeVal *type, const xmlChar **prefix,
8416 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008417 int blanks;
8418
8419 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8420 STRANGE;
8421 return(NULL);
8422 }
William M. Brack78637da2003-07-31 14:47:38 +00008423 *type = (xmlXPathTypeVal) 0;
8424 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008425 *prefix = NULL;
8426 SKIP_BLANKS;
8427
8428 if ((name == NULL) && (CUR == '*')) {
8429 /*
8430 * All elements
8431 */
8432 NEXT;
8433 *test = NODE_TEST_ALL;
8434 return(NULL);
8435 }
8436
8437 if (name == NULL)
8438 name = xmlXPathParseNCName(ctxt);
8439 if (name == NULL) {
8440 XP_ERROR0(XPATH_EXPR_ERROR);
8441 }
8442
William M. Brack76e95df2003-10-18 16:20:14 +00008443 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008444 SKIP_BLANKS;
8445 if (CUR == '(') {
8446 NEXT;
8447 /*
8448 * NodeType or PI search
8449 */
8450 if (xmlStrEqual(name, BAD_CAST "comment"))
8451 *type = NODE_TYPE_COMMENT;
8452 else if (xmlStrEqual(name, BAD_CAST "node"))
8453 *type = NODE_TYPE_NODE;
8454 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8455 *type = NODE_TYPE_PI;
8456 else if (xmlStrEqual(name, BAD_CAST "text"))
8457 *type = NODE_TYPE_TEXT;
8458 else {
8459 if (name != NULL)
8460 xmlFree(name);
8461 XP_ERROR0(XPATH_EXPR_ERROR);
8462 }
8463
8464 *test = NODE_TEST_TYPE;
8465
8466 SKIP_BLANKS;
8467 if (*type == NODE_TYPE_PI) {
8468 /*
8469 * Specific case: search a PI by name.
8470 */
Owen Taylor3473f882001-02-23 17:55:21 +00008471 if (name != NULL)
8472 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008473 name = NULL;
8474 if (CUR != ')') {
8475 name = xmlXPathParseLiteral(ctxt);
8476 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008477 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008478 SKIP_BLANKS;
8479 }
Owen Taylor3473f882001-02-23 17:55:21 +00008480 }
8481 if (CUR != ')') {
8482 if (name != NULL)
8483 xmlFree(name);
8484 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8485 }
8486 NEXT;
8487 return(name);
8488 }
8489 *test = NODE_TEST_NAME;
8490 if ((!blanks) && (CUR == ':')) {
8491 NEXT;
8492
8493 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008494 * Since currently the parser context don't have a
8495 * namespace list associated:
8496 * The namespace name for this prefix can be computed
8497 * only at evaluation time. The compilation is done
8498 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008499 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008500#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008501 *prefix = xmlXPathNsLookup(ctxt->context, name);
8502 if (name != NULL)
8503 xmlFree(name);
8504 if (*prefix == NULL) {
8505 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8506 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008507#else
8508 *prefix = name;
8509#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008510
8511 if (CUR == '*') {
8512 /*
8513 * All elements
8514 */
8515 NEXT;
8516 *test = NODE_TEST_ALL;
8517 return(NULL);
8518 }
8519
8520 name = xmlXPathParseNCName(ctxt);
8521 if (name == NULL) {
8522 XP_ERROR0(XPATH_EXPR_ERROR);
8523 }
8524 }
8525 return(name);
8526}
8527
8528/**
8529 * xmlXPathIsAxisName:
8530 * @name: a preparsed name token
8531 *
8532 * [6] AxisName ::= 'ancestor'
8533 * | 'ancestor-or-self'
8534 * | 'attribute'
8535 * | 'child'
8536 * | 'descendant'
8537 * | 'descendant-or-self'
8538 * | 'following'
8539 * | 'following-sibling'
8540 * | 'namespace'
8541 * | 'parent'
8542 * | 'preceding'
8543 * | 'preceding-sibling'
8544 * | 'self'
8545 *
8546 * Returns the axis or 0
8547 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008548static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008549xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008550 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008551 switch (name[0]) {
8552 case 'a':
8553 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8554 ret = AXIS_ANCESTOR;
8555 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8556 ret = AXIS_ANCESTOR_OR_SELF;
8557 if (xmlStrEqual(name, BAD_CAST "attribute"))
8558 ret = AXIS_ATTRIBUTE;
8559 break;
8560 case 'c':
8561 if (xmlStrEqual(name, BAD_CAST "child"))
8562 ret = AXIS_CHILD;
8563 break;
8564 case 'd':
8565 if (xmlStrEqual(name, BAD_CAST "descendant"))
8566 ret = AXIS_DESCENDANT;
8567 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8568 ret = AXIS_DESCENDANT_OR_SELF;
8569 break;
8570 case 'f':
8571 if (xmlStrEqual(name, BAD_CAST "following"))
8572 ret = AXIS_FOLLOWING;
8573 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8574 ret = AXIS_FOLLOWING_SIBLING;
8575 break;
8576 case 'n':
8577 if (xmlStrEqual(name, BAD_CAST "namespace"))
8578 ret = AXIS_NAMESPACE;
8579 break;
8580 case 'p':
8581 if (xmlStrEqual(name, BAD_CAST "parent"))
8582 ret = AXIS_PARENT;
8583 if (xmlStrEqual(name, BAD_CAST "preceding"))
8584 ret = AXIS_PRECEDING;
8585 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8586 ret = AXIS_PRECEDING_SIBLING;
8587 break;
8588 case 's':
8589 if (xmlStrEqual(name, BAD_CAST "self"))
8590 ret = AXIS_SELF;
8591 break;
8592 }
8593 return(ret);
8594}
8595
8596/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008597 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008598 * @ctxt: the XPath Parser context
8599 *
8600 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8601 * | AbbreviatedStep
8602 *
8603 * [12] AbbreviatedStep ::= '.' | '..'
8604 *
8605 * [5] AxisSpecifier ::= AxisName '::'
8606 * | AbbreviatedAxisSpecifier
8607 *
8608 * [13] AbbreviatedAxisSpecifier ::= '@'?
8609 *
8610 * Modified for XPtr range support as:
8611 *
8612 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8613 * | AbbreviatedStep
8614 * | 'range-to' '(' Expr ')' Predicate*
8615 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008616 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008617 * A location step of . is short for self::node(). This is
8618 * particularly useful in conjunction with //. For example, the
8619 * location path .//para is short for
8620 * self::node()/descendant-or-self::node()/child::para
8621 * and so will select all para descendant elements of the context
8622 * node.
8623 * Similarly, a location step of .. is short for parent::node().
8624 * For example, ../title is short for parent::node()/child::title
8625 * and so will select the title children of the parent of the context
8626 * node.
8627 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008628static void
8629xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008630#ifdef LIBXML_XPTR_ENABLED
8631 int rangeto = 0;
8632 int op2 = -1;
8633#endif
8634
Owen Taylor3473f882001-02-23 17:55:21 +00008635 SKIP_BLANKS;
8636 if ((CUR == '.') && (NXT(1) == '.')) {
8637 SKIP(2);
8638 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008639 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8640 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008641 } else if (CUR == '.') {
8642 NEXT;
8643 SKIP_BLANKS;
8644 } else {
8645 xmlChar *name = NULL;
8646 const xmlChar *prefix = NULL;
8647 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008648 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008649 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008650 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008651
8652 /*
8653 * The modification needed for XPointer change to the production
8654 */
8655#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008656 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008657 name = xmlXPathParseNCName(ctxt);
8658 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008659 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008660 xmlFree(name);
8661 SKIP_BLANKS;
8662 if (CUR != '(') {
8663 XP_ERROR(XPATH_EXPR_ERROR);
8664 }
8665 NEXT;
8666 SKIP_BLANKS;
8667
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008668 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008669 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008670 CHECK_ERROR;
8671
8672 SKIP_BLANKS;
8673 if (CUR != ')') {
8674 XP_ERROR(XPATH_EXPR_ERROR);
8675 }
8676 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008677 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008678 goto eval_predicates;
8679 }
8680 }
8681#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008682 if (CUR == '*') {
8683 axis = AXIS_CHILD;
8684 } else {
8685 if (name == NULL)
8686 name = xmlXPathParseNCName(ctxt);
8687 if (name != NULL) {
8688 axis = xmlXPathIsAxisName(name);
8689 if (axis != 0) {
8690 SKIP_BLANKS;
8691 if ((CUR == ':') && (NXT(1) == ':')) {
8692 SKIP(2);
8693 xmlFree(name);
8694 name = NULL;
8695 } else {
8696 /* an element name can conflict with an axis one :-\ */
8697 axis = AXIS_CHILD;
8698 }
Owen Taylor3473f882001-02-23 17:55:21 +00008699 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008700 axis = AXIS_CHILD;
8701 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008702 } else if (CUR == '@') {
8703 NEXT;
8704 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008705 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008706 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008707 }
Owen Taylor3473f882001-02-23 17:55:21 +00008708 }
8709
8710 CHECK_ERROR;
8711
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008712 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008713 if (test == 0)
8714 return;
8715
8716#ifdef DEBUG_STEP
8717 xmlGenericError(xmlGenericErrorContext,
8718 "Basis : computing new set\n");
8719#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008720
Owen Taylor3473f882001-02-23 17:55:21 +00008721#ifdef DEBUG_STEP
8722 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008723 if (ctxt->value == NULL)
8724 xmlGenericError(xmlGenericErrorContext, "no value\n");
8725 else if (ctxt->value->nodesetval == NULL)
8726 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8727 else
8728 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008729#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008730
8731eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008732 op1 = ctxt->comp->last;
8733 ctxt->comp->last = -1;
8734
Owen Taylor3473f882001-02-23 17:55:21 +00008735 SKIP_BLANKS;
8736 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008737 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008738 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008739
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008740#ifdef LIBXML_XPTR_ENABLED
8741 if (rangeto) {
8742 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8743 } else
8744#endif
8745 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8746 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008747
Owen Taylor3473f882001-02-23 17:55:21 +00008748 }
8749#ifdef DEBUG_STEP
8750 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008751 if (ctxt->value == NULL)
8752 xmlGenericError(xmlGenericErrorContext, "no value\n");
8753 else if (ctxt->value->nodesetval == NULL)
8754 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8755 else
8756 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8757 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008758#endif
8759}
8760
8761/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008762 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008763 * @ctxt: the XPath Parser context
8764 *
8765 * [3] RelativeLocationPath ::= Step
8766 * | RelativeLocationPath '/' Step
8767 * | AbbreviatedRelativeLocationPath
8768 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8769 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008770 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008771 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008772static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008773xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008774(xmlXPathParserContextPtr ctxt) {
8775 SKIP_BLANKS;
8776 if ((CUR == '/') && (NXT(1) == '/')) {
8777 SKIP(2);
8778 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008779 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8780 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008781 } else if (CUR == '/') {
8782 NEXT;
8783 SKIP_BLANKS;
8784 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008785 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008786 SKIP_BLANKS;
8787 while (CUR == '/') {
8788 if ((CUR == '/') && (NXT(1) == '/')) {
8789 SKIP(2);
8790 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008791 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008792 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008793 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008794 } else if (CUR == '/') {
8795 NEXT;
8796 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008797 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008798 }
8799 SKIP_BLANKS;
8800 }
8801}
8802
8803/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008804 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008805 * @ctxt: the XPath Parser context
8806 *
8807 * [1] LocationPath ::= RelativeLocationPath
8808 * | AbsoluteLocationPath
8809 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8810 * | AbbreviatedAbsoluteLocationPath
8811 * [10] AbbreviatedAbsoluteLocationPath ::=
8812 * '//' RelativeLocationPath
8813 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008814 * Compile a location path
8815 *
Owen Taylor3473f882001-02-23 17:55:21 +00008816 * // is short for /descendant-or-self::node()/. For example,
8817 * //para is short for /descendant-or-self::node()/child::para and
8818 * so will select any para element in the document (even a para element
8819 * that is a document element will be selected by //para since the
8820 * document element node is a child of the root node); div//para is
8821 * short for div/descendant-or-self::node()/child::para and so will
8822 * select all para descendants of div children.
8823 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008824static void
8825xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008826 SKIP_BLANKS;
8827 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008828 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008829 } else {
8830 while (CUR == '/') {
8831 if ((CUR == '/') && (NXT(1) == '/')) {
8832 SKIP(2);
8833 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008834 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8835 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008836 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008837 } else if (CUR == '/') {
8838 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008839 SKIP_BLANKS;
8840 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008841 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008842 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008843 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008844 }
8845 }
8846 }
8847}
8848
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008849/************************************************************************
8850 * *
8851 * XPath precompiled expression evaluation *
8852 * *
8853 ************************************************************************/
8854
Daniel Veillardf06307e2001-07-03 10:35:50 +00008855static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008856xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8857
8858/**
8859 * xmlXPathNodeCollectAndTest:
8860 * @ctxt: the XPath Parser context
8861 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008862 * @first: pointer to the first element in document order
8863 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008864 *
8865 * This is the function implementing a step: based on the current list
8866 * of nodes, it builds up a new list, looking at all nodes under that
8867 * axis and selecting them it also do the predicate filtering
8868 *
8869 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008870 *
8871 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008872 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008873static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008874xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 xmlXPathStepOpPtr op,
8876 xmlNodePtr * first, xmlNodePtr * last)
8877{
William M. Brack78637da2003-07-31 14:47:38 +00008878 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8879 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8880 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008881 const xmlChar *prefix = op->value4;
8882 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008883 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008884
8885#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008886 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008887#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008888 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008889 xmlNodeSetPtr ret, list;
8890 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008891 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008892 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008893 xmlNodePtr cur = NULL;
8894 xmlXPathObjectPtr obj;
8895 xmlNodeSetPtr nodelist;
8896 xmlNodePtr tmp;
8897
Daniel Veillardf06307e2001-07-03 10:35:50 +00008898 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008899 obj = valuePop(ctxt);
8900 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008901 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008902 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008903 URI = xmlXPathNsLookup(ctxt->context, prefix);
8904 if (URI == NULL)
8905 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008906 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008907#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008908 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008909#endif
8910 switch (axis) {
8911 case AXIS_ANCESTOR:
8912#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008913 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008914#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008915 first = NULL;
8916 next = xmlXPathNextAncestor;
8917 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008918 case AXIS_ANCESTOR_OR_SELF:
8919#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008920 xmlGenericError(xmlGenericErrorContext,
8921 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008922#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008923 first = NULL;
8924 next = xmlXPathNextAncestorOrSelf;
8925 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926 case AXIS_ATTRIBUTE:
8927#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008928 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008929#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008930 first = NULL;
8931 last = NULL;
8932 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008933 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008934 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008935 case AXIS_CHILD:
8936#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008937 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008938#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008939 last = NULL;
8940 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008941 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008942 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008943 case AXIS_DESCENDANT:
8944#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008945 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008946#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008947 last = NULL;
8948 next = xmlXPathNextDescendant;
8949 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008950 case AXIS_DESCENDANT_OR_SELF:
8951#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008952 xmlGenericError(xmlGenericErrorContext,
8953 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008954#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 last = NULL;
8956 next = xmlXPathNextDescendantOrSelf;
8957 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008958 case AXIS_FOLLOWING:
8959#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008960 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008961#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008962 last = NULL;
8963 next = xmlXPathNextFollowing;
8964 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008965 case AXIS_FOLLOWING_SIBLING:
8966#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008967 xmlGenericError(xmlGenericErrorContext,
8968 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008969#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008970 last = NULL;
8971 next = xmlXPathNextFollowingSibling;
8972 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973 case AXIS_NAMESPACE:
8974#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008976#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008977 first = NULL;
8978 last = NULL;
8979 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008980 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008981 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008982 case AXIS_PARENT:
8983#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008984 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008986 first = NULL;
8987 next = xmlXPathNextParent;
8988 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008989 case AXIS_PRECEDING:
8990#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008991 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008992#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008993 first = NULL;
8994 next = xmlXPathNextPrecedingInternal;
8995 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008996 case AXIS_PRECEDING_SIBLING:
8997#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008998 xmlGenericError(xmlGenericErrorContext,
8999 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009000#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009001 first = NULL;
9002 next = xmlXPathNextPrecedingSibling;
9003 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009004 case AXIS_SELF:
9005#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009006 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009007#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009008 first = NULL;
9009 last = NULL;
9010 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009011 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009012 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009013 }
9014 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009015 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009016
9017 nodelist = obj->nodesetval;
9018 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009019 xmlXPathFreeObject(obj);
9020 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9021 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009022 }
9023 addNode = xmlXPathNodeSetAddUnique;
9024 ret = NULL;
9025#ifdef DEBUG_STEP
9026 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009027 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009028 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009029 case NODE_TEST_NONE:
9030 xmlGenericError(xmlGenericErrorContext,
9031 " searching for none !!!\n");
9032 break;
9033 case NODE_TEST_TYPE:
9034 xmlGenericError(xmlGenericErrorContext,
9035 " searching for type %d\n", type);
9036 break;
9037 case NODE_TEST_PI:
9038 xmlGenericError(xmlGenericErrorContext,
9039 " searching for PI !!!\n");
9040 break;
9041 case NODE_TEST_ALL:
9042 xmlGenericError(xmlGenericErrorContext,
9043 " searching for *\n");
9044 break;
9045 case NODE_TEST_NS:
9046 xmlGenericError(xmlGenericErrorContext,
9047 " searching for namespace %s\n",
9048 prefix);
9049 break;
9050 case NODE_TEST_NAME:
9051 xmlGenericError(xmlGenericErrorContext,
9052 " searching for name %s\n", name);
9053 if (prefix != NULL)
9054 xmlGenericError(xmlGenericErrorContext,
9055 " with namespace %s\n", prefix);
9056 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009057 }
9058 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9059#endif
9060 /*
9061 * 2.3 Node Tests
9062 * - For the attribute axis, the principal node type is attribute.
9063 * - For the namespace axis, the principal node type is namespace.
9064 * - For other axes, the principal node type is element.
9065 *
9066 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009067 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009068 * select all element children of the context node
9069 */
9070 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009071 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009072 ctxt->context->node = nodelist->nodeTab[i];
9073
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 cur = NULL;
9075 list = xmlXPathNodeSetCreate(NULL);
9076 do {
9077 cur = next(ctxt, cur);
9078 if (cur == NULL)
9079 break;
9080 if ((first != NULL) && (*first == cur))
9081 break;
9082 if (((t % 256) == 0) &&
9083 (first != NULL) && (*first != NULL) &&
9084 (xmlXPathCmpNodes(*first, cur) >= 0))
9085 break;
9086 if ((last != NULL) && (*last == cur))
9087 break;
9088 if (((t % 256) == 0) &&
9089 (last != NULL) && (*last != NULL) &&
9090 (xmlXPathCmpNodes(cur, *last) >= 0))
9091 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009092 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009093#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009094 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9095#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009096 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009097 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 ctxt->context->node = tmp;
9099 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009100 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 if ((cur->type == type) ||
9102 ((type == NODE_TYPE_NODE) &&
9103 ((cur->type == XML_DOCUMENT_NODE) ||
9104 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9105 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009106 (cur->type == XML_NAMESPACE_DECL) ||
9107 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 (cur->type == XML_PI_NODE) ||
9109 (cur->type == XML_COMMENT_NODE) ||
9110 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009111 (cur->type == XML_TEXT_NODE))) ||
9112 ((type == NODE_TYPE_TEXT) &&
9113 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009114#ifdef DEBUG_STEP
9115 n++;
9116#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009117 addNode(list, cur);
9118 }
9119 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009120 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 if (cur->type == XML_PI_NODE) {
9122 if ((name != NULL) &&
9123 (!xmlStrEqual(name, cur->name)))
9124 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009125#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009126 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009127#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009128 addNode(list, cur);
9129 }
9130 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009131 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 if (axis == AXIS_ATTRIBUTE) {
9133 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009134#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009135 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009136#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009137 addNode(list, cur);
9138 }
9139 } else if (axis == AXIS_NAMESPACE) {
9140 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009141#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009142 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009143#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009144 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9145 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009146 }
9147 } else {
9148 if (cur->type == XML_ELEMENT_NODE) {
9149 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009150#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009152#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009153 addNode(list, cur);
9154 } else if ((cur->ns != NULL) &&
9155 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009156#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009157 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009158#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009159 addNode(list, cur);
9160 }
9161 }
9162 }
9163 break;
9164 case NODE_TEST_NS:{
9165 TODO;
9166 break;
9167 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009168 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009169 switch (cur->type) {
9170 case XML_ELEMENT_NODE:
9171 if (xmlStrEqual(name, cur->name)) {
9172 if (prefix == NULL) {
9173 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009174#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009176#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009177 addNode(list, cur);
9178 }
9179 } else {
9180 if ((cur->ns != NULL) &&
9181 (xmlStrEqual(URI,
9182 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009183#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009184 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009185#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009186 addNode(list, cur);
9187 }
9188 }
9189 }
9190 break;
9191 case XML_ATTRIBUTE_NODE:{
9192 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009193
Daniel Veillardf06307e2001-07-03 10:35:50 +00009194 if (xmlStrEqual(name, attr->name)) {
9195 if (prefix == NULL) {
9196 if ((attr->ns == NULL) ||
9197 (attr->ns->prefix == NULL)) {
9198#ifdef DEBUG_STEP
9199 n++;
9200#endif
9201 addNode(list,
9202 (xmlNodePtr) attr);
9203 }
9204 } else {
9205 if ((attr->ns != NULL) &&
9206 (xmlStrEqual(URI,
9207 attr->ns->
9208 href))) {
9209#ifdef DEBUG_STEP
9210 n++;
9211#endif
9212 addNode(list,
9213 (xmlNodePtr) attr);
9214 }
9215 }
9216 }
9217 break;
9218 }
9219 case XML_NAMESPACE_DECL:
9220 if (cur->type == XML_NAMESPACE_DECL) {
9221 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009222
Daniel Veillardf06307e2001-07-03 10:35:50 +00009223 if ((ns->prefix != NULL) && (name != NULL)
9224 && (xmlStrEqual(ns->prefix, name))) {
9225#ifdef DEBUG_STEP
9226 n++;
9227#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009228 xmlXPathNodeSetAddNs(list,
9229 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009230 }
9231 }
9232 break;
9233 default:
9234 break;
9235 }
9236 break;
9237 break;
9238 }
9239 } while (cur != NULL);
9240
9241 /*
9242 * If there is some predicate filtering do it now
9243 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009244 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009245 xmlXPathObjectPtr obj2;
9246
9247 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9248 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9249 CHECK_TYPE0(XPATH_NODESET);
9250 obj2 = valuePop(ctxt);
9251 list = obj2->nodesetval;
9252 obj2->nodesetval = NULL;
9253 xmlXPathFreeObject(obj2);
9254 }
9255 if (ret == NULL) {
9256 ret = list;
9257 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009258 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009259 xmlXPathFreeNodeSet(list);
9260 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009261 }
9262 ctxt->context->node = tmp;
9263#ifdef DEBUG_STEP
9264 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009265 "\nExamined %d nodes, found %d nodes at that step\n",
9266 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009267#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009268 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009269 if ((obj->boolval) && (obj->user != NULL)) {
9270 ctxt->value->boolval = 1;
9271 ctxt->value->user = obj->user;
9272 obj->user = NULL;
9273 obj->boolval = 0;
9274 }
9275 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009276 return(t);
9277}
9278
9279/**
9280 * xmlXPathNodeCollectAndTestNth:
9281 * @ctxt: the XPath Parser context
9282 * @op: the XPath precompiled step operation
9283 * @indx: the index to collect
9284 * @first: pointer to the first element in document order
9285 * @last: pointer to the last element in document order
9286 *
9287 * This is the function implementing a step: based on the current list
9288 * of nodes, it builds up a new list, looking at all nodes under that
9289 * axis and selecting them it also do the predicate filtering
9290 *
9291 * Pushes the new NodeSet resulting from the search.
9292 * Returns the number of node traversed
9293 */
9294static int
9295xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9296 xmlXPathStepOpPtr op, int indx,
9297 xmlNodePtr * first, xmlNodePtr * last)
9298{
William M. Brack78637da2003-07-31 14:47:38 +00009299 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9300 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9301 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009302 const xmlChar *prefix = op->value4;
9303 const xmlChar *name = op->value5;
9304 const xmlChar *URI = NULL;
9305 int n = 0, t = 0;
9306
9307 int i;
9308 xmlNodeSetPtr list;
9309 xmlXPathTraversalFunction next = NULL;
9310 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9311 xmlNodePtr cur = NULL;
9312 xmlXPathObjectPtr obj;
9313 xmlNodeSetPtr nodelist;
9314 xmlNodePtr tmp;
9315
9316 CHECK_TYPE0(XPATH_NODESET);
9317 obj = valuePop(ctxt);
9318 addNode = xmlXPathNodeSetAdd;
9319 if (prefix != NULL) {
9320 URI = xmlXPathNsLookup(ctxt->context, prefix);
9321 if (URI == NULL)
9322 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9323 }
9324#ifdef DEBUG_STEP_NTH
9325 xmlGenericError(xmlGenericErrorContext, "new step : ");
9326 if (first != NULL) {
9327 if (*first != NULL)
9328 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9329 (*first)->name);
9330 else
9331 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9332 }
9333 if (last != NULL) {
9334 if (*last != NULL)
9335 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9336 (*last)->name);
9337 else
9338 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9339 }
9340#endif
9341 switch (axis) {
9342 case AXIS_ANCESTOR:
9343#ifdef DEBUG_STEP_NTH
9344 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9345#endif
9346 first = NULL;
9347 next = xmlXPathNextAncestor;
9348 break;
9349 case AXIS_ANCESTOR_OR_SELF:
9350#ifdef DEBUG_STEP_NTH
9351 xmlGenericError(xmlGenericErrorContext,
9352 "axis 'ancestors-or-self' ");
9353#endif
9354 first = NULL;
9355 next = xmlXPathNextAncestorOrSelf;
9356 break;
9357 case AXIS_ATTRIBUTE:
9358#ifdef DEBUG_STEP_NTH
9359 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9360#endif
9361 first = NULL;
9362 last = NULL;
9363 next = xmlXPathNextAttribute;
9364 break;
9365 case AXIS_CHILD:
9366#ifdef DEBUG_STEP_NTH
9367 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9368#endif
9369 last = NULL;
9370 next = xmlXPathNextChild;
9371 break;
9372 case AXIS_DESCENDANT:
9373#ifdef DEBUG_STEP_NTH
9374 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9375#endif
9376 last = NULL;
9377 next = xmlXPathNextDescendant;
9378 break;
9379 case AXIS_DESCENDANT_OR_SELF:
9380#ifdef DEBUG_STEP_NTH
9381 xmlGenericError(xmlGenericErrorContext,
9382 "axis 'descendant-or-self' ");
9383#endif
9384 last = NULL;
9385 next = xmlXPathNextDescendantOrSelf;
9386 break;
9387 case AXIS_FOLLOWING:
9388#ifdef DEBUG_STEP_NTH
9389 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9390#endif
9391 last = NULL;
9392 next = xmlXPathNextFollowing;
9393 break;
9394 case AXIS_FOLLOWING_SIBLING:
9395#ifdef DEBUG_STEP_NTH
9396 xmlGenericError(xmlGenericErrorContext,
9397 "axis 'following-siblings' ");
9398#endif
9399 last = NULL;
9400 next = xmlXPathNextFollowingSibling;
9401 break;
9402 case AXIS_NAMESPACE:
9403#ifdef DEBUG_STEP_NTH
9404 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9405#endif
9406 last = NULL;
9407 first = NULL;
9408 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9409 break;
9410 case AXIS_PARENT:
9411#ifdef DEBUG_STEP_NTH
9412 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9413#endif
9414 first = NULL;
9415 next = xmlXPathNextParent;
9416 break;
9417 case AXIS_PRECEDING:
9418#ifdef DEBUG_STEP_NTH
9419 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9420#endif
9421 first = NULL;
9422 next = xmlXPathNextPrecedingInternal;
9423 break;
9424 case AXIS_PRECEDING_SIBLING:
9425#ifdef DEBUG_STEP_NTH
9426 xmlGenericError(xmlGenericErrorContext,
9427 "axis 'preceding-sibling' ");
9428#endif
9429 first = NULL;
9430 next = xmlXPathNextPrecedingSibling;
9431 break;
9432 case AXIS_SELF:
9433#ifdef DEBUG_STEP_NTH
9434 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9435#endif
9436 first = NULL;
9437 last = NULL;
9438 next = xmlXPathNextSelf;
9439 break;
9440 }
9441 if (next == NULL)
9442 return(0);
9443
9444 nodelist = obj->nodesetval;
9445 if (nodelist == NULL) {
9446 xmlXPathFreeObject(obj);
9447 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9448 return(0);
9449 }
9450 addNode = xmlXPathNodeSetAddUnique;
9451#ifdef DEBUG_STEP_NTH
9452 xmlGenericError(xmlGenericErrorContext,
9453 " context contains %d nodes\n", nodelist->nodeNr);
9454 switch (test) {
9455 case NODE_TEST_NONE:
9456 xmlGenericError(xmlGenericErrorContext,
9457 " searching for none !!!\n");
9458 break;
9459 case NODE_TEST_TYPE:
9460 xmlGenericError(xmlGenericErrorContext,
9461 " searching for type %d\n", type);
9462 break;
9463 case NODE_TEST_PI:
9464 xmlGenericError(xmlGenericErrorContext,
9465 " searching for PI !!!\n");
9466 break;
9467 case NODE_TEST_ALL:
9468 xmlGenericError(xmlGenericErrorContext,
9469 " searching for *\n");
9470 break;
9471 case NODE_TEST_NS:
9472 xmlGenericError(xmlGenericErrorContext,
9473 " searching for namespace %s\n",
9474 prefix);
9475 break;
9476 case NODE_TEST_NAME:
9477 xmlGenericError(xmlGenericErrorContext,
9478 " searching for name %s\n", name);
9479 if (prefix != NULL)
9480 xmlGenericError(xmlGenericErrorContext,
9481 " with namespace %s\n", prefix);
9482 break;
9483 }
9484 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9485#endif
9486 /*
9487 * 2.3 Node Tests
9488 * - For the attribute axis, the principal node type is attribute.
9489 * - For the namespace axis, the principal node type is namespace.
9490 * - For other axes, the principal node type is element.
9491 *
9492 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009493 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009494 * select all element children of the context node
9495 */
9496 tmp = ctxt->context->node;
9497 list = xmlXPathNodeSetCreate(NULL);
9498 for (i = 0; i < nodelist->nodeNr; i++) {
9499 ctxt->context->node = nodelist->nodeTab[i];
9500
9501 cur = NULL;
9502 n = 0;
9503 do {
9504 cur = next(ctxt, cur);
9505 if (cur == NULL)
9506 break;
9507 if ((first != NULL) && (*first == cur))
9508 break;
9509 if (((t % 256) == 0) &&
9510 (first != NULL) && (*first != NULL) &&
9511 (xmlXPathCmpNodes(*first, cur) >= 0))
9512 break;
9513 if ((last != NULL) && (*last == cur))
9514 break;
9515 if (((t % 256) == 0) &&
9516 (last != NULL) && (*last != NULL) &&
9517 (xmlXPathCmpNodes(cur, *last) >= 0))
9518 break;
9519 t++;
9520 switch (test) {
9521 case NODE_TEST_NONE:
9522 ctxt->context->node = tmp;
9523 STRANGE return(0);
9524 case NODE_TEST_TYPE:
9525 if ((cur->type == type) ||
9526 ((type == NODE_TYPE_NODE) &&
9527 ((cur->type == XML_DOCUMENT_NODE) ||
9528 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9529 (cur->type == XML_ELEMENT_NODE) ||
9530 (cur->type == XML_PI_NODE) ||
9531 (cur->type == XML_COMMENT_NODE) ||
9532 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009533 (cur->type == XML_TEXT_NODE))) ||
9534 ((type == NODE_TYPE_TEXT) &&
9535 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009536 n++;
9537 if (n == indx)
9538 addNode(list, cur);
9539 }
9540 break;
9541 case NODE_TEST_PI:
9542 if (cur->type == XML_PI_NODE) {
9543 if ((name != NULL) &&
9544 (!xmlStrEqual(name, cur->name)))
9545 break;
9546 n++;
9547 if (n == indx)
9548 addNode(list, cur);
9549 }
9550 break;
9551 case NODE_TEST_ALL:
9552 if (axis == AXIS_ATTRIBUTE) {
9553 if (cur->type == XML_ATTRIBUTE_NODE) {
9554 n++;
9555 if (n == indx)
9556 addNode(list, cur);
9557 }
9558 } else if (axis == AXIS_NAMESPACE) {
9559 if (cur->type == XML_NAMESPACE_DECL) {
9560 n++;
9561 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009562 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9563 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009564 }
9565 } else {
9566 if (cur->type == XML_ELEMENT_NODE) {
9567 if (prefix == NULL) {
9568 n++;
9569 if (n == indx)
9570 addNode(list, cur);
9571 } else if ((cur->ns != NULL) &&
9572 (xmlStrEqual(URI, cur->ns->href))) {
9573 n++;
9574 if (n == indx)
9575 addNode(list, cur);
9576 }
9577 }
9578 }
9579 break;
9580 case NODE_TEST_NS:{
9581 TODO;
9582 break;
9583 }
9584 case NODE_TEST_NAME:
9585 switch (cur->type) {
9586 case XML_ELEMENT_NODE:
9587 if (xmlStrEqual(name, cur->name)) {
9588 if (prefix == NULL) {
9589 if (cur->ns == NULL) {
9590 n++;
9591 if (n == indx)
9592 addNode(list, cur);
9593 }
9594 } else {
9595 if ((cur->ns != NULL) &&
9596 (xmlStrEqual(URI,
9597 cur->ns->href))) {
9598 n++;
9599 if (n == indx)
9600 addNode(list, cur);
9601 }
9602 }
9603 }
9604 break;
9605 case XML_ATTRIBUTE_NODE:{
9606 xmlAttrPtr attr = (xmlAttrPtr) cur;
9607
9608 if (xmlStrEqual(name, attr->name)) {
9609 if (prefix == NULL) {
9610 if ((attr->ns == NULL) ||
9611 (attr->ns->prefix == NULL)) {
9612 n++;
9613 if (n == indx)
9614 addNode(list, cur);
9615 }
9616 } else {
9617 if ((attr->ns != NULL) &&
9618 (xmlStrEqual(URI,
9619 attr->ns->
9620 href))) {
9621 n++;
9622 if (n == indx)
9623 addNode(list, cur);
9624 }
9625 }
9626 }
9627 break;
9628 }
9629 case XML_NAMESPACE_DECL:
9630 if (cur->type == XML_NAMESPACE_DECL) {
9631 xmlNsPtr ns = (xmlNsPtr) cur;
9632
9633 if ((ns->prefix != NULL) && (name != NULL)
9634 && (xmlStrEqual(ns->prefix, name))) {
9635 n++;
9636 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009637 xmlXPathNodeSetAddNs(list,
9638 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009639 }
9640 }
9641 break;
9642 default:
9643 break;
9644 }
9645 break;
9646 break;
9647 }
9648 } while (n < indx);
9649 }
9650 ctxt->context->node = tmp;
9651#ifdef DEBUG_STEP_NTH
9652 xmlGenericError(xmlGenericErrorContext,
9653 "\nExamined %d nodes, found %d nodes at that step\n",
9654 t, list->nodeNr);
9655#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009656 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009657 if ((obj->boolval) && (obj->user != NULL)) {
9658 ctxt->value->boolval = 1;
9659 ctxt->value->user = obj->user;
9660 obj->user = NULL;
9661 obj->boolval = 0;
9662 }
9663 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009664 return(t);
9665}
9666
9667/**
9668 * xmlXPathCompOpEvalFirst:
9669 * @ctxt: the XPath parser context with the compiled expression
9670 * @op: an XPath compiled operation
9671 * @first: the first elem found so far
9672 *
9673 * Evaluate the Precompiled XPath operation searching only the first
9674 * element in document order
9675 *
9676 * Returns the number of examined objects.
9677 */
9678static int
9679xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9680 xmlXPathStepOpPtr op, xmlNodePtr * first)
9681{
9682 int total = 0, cur;
9683 xmlXPathCompExprPtr comp;
9684 xmlXPathObjectPtr arg1, arg2;
9685
Daniel Veillard556c6682001-10-06 09:59:51 +00009686 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009687 comp = ctxt->comp;
9688 switch (op->op) {
9689 case XPATH_OP_END:
9690 return (0);
9691 case XPATH_OP_UNION:
9692 total =
9693 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9694 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009695 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009696 if ((ctxt->value != NULL)
9697 && (ctxt->value->type == XPATH_NODESET)
9698 && (ctxt->value->nodesetval != NULL)
9699 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9700 /*
9701 * limit tree traversing to first node in the result
9702 */
9703 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9704 *first = ctxt->value->nodesetval->nodeTab[0];
9705 }
9706 cur =
9707 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9708 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009709 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009710 CHECK_TYPE0(XPATH_NODESET);
9711 arg2 = valuePop(ctxt);
9712
9713 CHECK_TYPE0(XPATH_NODESET);
9714 arg1 = valuePop(ctxt);
9715
9716 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9717 arg2->nodesetval);
9718 valuePush(ctxt, arg1);
9719 xmlXPathFreeObject(arg2);
9720 /* optimizer */
9721 if (total > cur)
9722 xmlXPathCompSwap(op);
9723 return (total + cur);
9724 case XPATH_OP_ROOT:
9725 xmlXPathRoot(ctxt);
9726 return (0);
9727 case XPATH_OP_NODE:
9728 if (op->ch1 != -1)
9729 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009730 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009731 if (op->ch2 != -1)
9732 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009733 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009734 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9735 return (total);
9736 case XPATH_OP_RESET:
9737 if (op->ch1 != -1)
9738 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009739 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009740 if (op->ch2 != -1)
9741 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009742 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009743 ctxt->context->node = NULL;
9744 return (total);
9745 case XPATH_OP_COLLECT:{
9746 if (op->ch1 == -1)
9747 return (total);
9748
9749 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009750 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009751
9752 /*
9753 * Optimization for [n] selection where n is a number
9754 */
9755 if ((op->ch2 != -1) &&
9756 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9757 (comp->steps[op->ch2].ch1 == -1) &&
9758 (comp->steps[op->ch2].ch2 != -1) &&
9759 (comp->steps[comp->steps[op->ch2].ch2].op ==
9760 XPATH_OP_VALUE)) {
9761 xmlXPathObjectPtr val;
9762
9763 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9764 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9765 int indx = (int) val->floatval;
9766
9767 if (val->floatval == (float) indx) {
9768 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9769 first, NULL);
9770 return (total);
9771 }
9772 }
9773 }
9774 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9775 return (total);
9776 }
9777 case XPATH_OP_VALUE:
9778 valuePush(ctxt,
9779 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9780 return (0);
9781 case XPATH_OP_SORT:
9782 if (op->ch1 != -1)
9783 total +=
9784 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9785 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009786 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009787 if ((ctxt->value != NULL)
9788 && (ctxt->value->type == XPATH_NODESET)
9789 && (ctxt->value->nodesetval != NULL))
9790 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9791 return (total);
9792 default:
9793 return (xmlXPathCompOpEval(ctxt, op));
9794 }
9795}
9796
9797/**
9798 * xmlXPathCompOpEvalLast:
9799 * @ctxt: the XPath parser context with the compiled expression
9800 * @op: an XPath compiled operation
9801 * @last: the last elem found so far
9802 *
9803 * Evaluate the Precompiled XPath operation searching only the last
9804 * element in document order
9805 *
9806 * Returns the number of node traversed
9807 */
9808static int
9809xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9810 xmlNodePtr * last)
9811{
9812 int total = 0, cur;
9813 xmlXPathCompExprPtr comp;
9814 xmlXPathObjectPtr arg1, arg2;
9815
Daniel Veillard556c6682001-10-06 09:59:51 +00009816 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009817 comp = ctxt->comp;
9818 switch (op->op) {
9819 case XPATH_OP_END:
9820 return (0);
9821 case XPATH_OP_UNION:
9822 total =
9823 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009824 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009825 if ((ctxt->value != NULL)
9826 && (ctxt->value->type == XPATH_NODESET)
9827 && (ctxt->value->nodesetval != NULL)
9828 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9829 /*
9830 * limit tree traversing to first node in the result
9831 */
9832 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9833 *last =
9834 ctxt->value->nodesetval->nodeTab[ctxt->value->
9835 nodesetval->nodeNr -
9836 1];
9837 }
9838 cur =
9839 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009840 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009841 if ((ctxt->value != NULL)
9842 && (ctxt->value->type == XPATH_NODESET)
9843 && (ctxt->value->nodesetval != NULL)
9844 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9845 }
9846 CHECK_TYPE0(XPATH_NODESET);
9847 arg2 = valuePop(ctxt);
9848
9849 CHECK_TYPE0(XPATH_NODESET);
9850 arg1 = valuePop(ctxt);
9851
9852 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9853 arg2->nodesetval);
9854 valuePush(ctxt, arg1);
9855 xmlXPathFreeObject(arg2);
9856 /* optimizer */
9857 if (total > cur)
9858 xmlXPathCompSwap(op);
9859 return (total + cur);
9860 case XPATH_OP_ROOT:
9861 xmlXPathRoot(ctxt);
9862 return (0);
9863 case XPATH_OP_NODE:
9864 if (op->ch1 != -1)
9865 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009866 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009867 if (op->ch2 != -1)
9868 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009869 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009870 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9871 return (total);
9872 case XPATH_OP_RESET:
9873 if (op->ch1 != -1)
9874 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009875 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009876 if (op->ch2 != -1)
9877 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009878 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009879 ctxt->context->node = NULL;
9880 return (total);
9881 case XPATH_OP_COLLECT:{
9882 if (op->ch1 == -1)
9883 return (0);
9884
9885 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009886 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009887
9888 /*
9889 * Optimization for [n] selection where n is a number
9890 */
9891 if ((op->ch2 != -1) &&
9892 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9893 (comp->steps[op->ch2].ch1 == -1) &&
9894 (comp->steps[op->ch2].ch2 != -1) &&
9895 (comp->steps[comp->steps[op->ch2].ch2].op ==
9896 XPATH_OP_VALUE)) {
9897 xmlXPathObjectPtr val;
9898
9899 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9900 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9901 int indx = (int) val->floatval;
9902
9903 if (val->floatval == (float) indx) {
9904 total +=
9905 xmlXPathNodeCollectAndTestNth(ctxt, op,
9906 indx, NULL,
9907 last);
9908 return (total);
9909 }
9910 }
9911 }
9912 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9913 return (total);
9914 }
9915 case XPATH_OP_VALUE:
9916 valuePush(ctxt,
9917 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9918 return (0);
9919 case XPATH_OP_SORT:
9920 if (op->ch1 != -1)
9921 total +=
9922 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9923 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009924 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009925 if ((ctxt->value != NULL)
9926 && (ctxt->value->type == XPATH_NODESET)
9927 && (ctxt->value->nodesetval != NULL))
9928 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9929 return (total);
9930 default:
9931 return (xmlXPathCompOpEval(ctxt, op));
9932 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009933}
9934
Owen Taylor3473f882001-02-23 17:55:21 +00009935/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009936 * xmlXPathCompOpEval:
9937 * @ctxt: the XPath parser context with the compiled expression
9938 * @op: an XPath compiled operation
9939 *
9940 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009941 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009942 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009943static int
9944xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9945{
9946 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009947 int equal, ret;
9948 xmlXPathCompExprPtr comp;
9949 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009950 xmlNodePtr bak;
9951 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009952 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009953 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009954
Daniel Veillard556c6682001-10-06 09:59:51 +00009955 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009956 comp = ctxt->comp;
9957 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009958 case XPATH_OP_END:
9959 return (0);
9960 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009961 bakd = ctxt->context->doc;
9962 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009963 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009964 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009965 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009966 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009967 xmlXPathBooleanFunction(ctxt, 1);
9968 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9969 return (total);
9970 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009971 ctxt->context->doc = bakd;
9972 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009973 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009974 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009975 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009976 if (ctxt->error) {
9977 xmlXPathFreeObject(arg2);
9978 return(0);
9979 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980 xmlXPathBooleanFunction(ctxt, 1);
9981 arg1 = valuePop(ctxt);
9982 arg1->boolval &= arg2->boolval;
9983 valuePush(ctxt, arg1);
9984 xmlXPathFreeObject(arg2);
9985 return (total);
9986 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009987 bakd = ctxt->context->doc;
9988 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009989 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009990 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009991 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009992 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009993 xmlXPathBooleanFunction(ctxt, 1);
9994 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9995 return (total);
9996 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009997 ctxt->context->doc = bakd;
9998 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009999 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010000 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010001 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010002 if (ctxt->error) {
10003 xmlXPathFreeObject(arg2);
10004 return(0);
10005 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010006 xmlXPathBooleanFunction(ctxt, 1);
10007 arg1 = valuePop(ctxt);
10008 arg1->boolval |= arg2->boolval;
10009 valuePush(ctxt, arg1);
10010 xmlXPathFreeObject(arg2);
10011 return (total);
10012 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010013 bakd = ctxt->context->doc;
10014 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010015 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010016 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010017 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010018 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010019 ctxt->context->doc = bakd;
10020 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010021 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010022 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010023 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010024 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010025 if (op->value)
10026 equal = xmlXPathEqualValues(ctxt);
10027 else
10028 equal = xmlXPathNotEqualValues(ctxt);
10029 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010030 return (total);
10031 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010032 bakd = ctxt->context->doc;
10033 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010034 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010035 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010036 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010037 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010038 ctxt->context->doc = bakd;
10039 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010040 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010041 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010042 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010043 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010044 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10045 valuePush(ctxt, xmlXPathNewBoolean(ret));
10046 return (total);
10047 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010048 bakd = ctxt->context->doc;
10049 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010050 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010051 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010052 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010053 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010054 if (op->ch2 != -1) {
10055 ctxt->context->doc = bakd;
10056 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010057 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010058 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010060 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010061 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010062 if (op->value == 0)
10063 xmlXPathSubValues(ctxt);
10064 else if (op->value == 1)
10065 xmlXPathAddValues(ctxt);
10066 else if (op->value == 2)
10067 xmlXPathValueFlipSign(ctxt);
10068 else if (op->value == 3) {
10069 CAST_TO_NUMBER;
10070 CHECK_TYPE0(XPATH_NUMBER);
10071 }
10072 return (total);
10073 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010074 bakd = ctxt->context->doc;
10075 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010076 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010077 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010078 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010079 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010080 ctxt->context->doc = bakd;
10081 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010082 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010083 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010084 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010085 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010086 if (op->value == 0)
10087 xmlXPathMultValues(ctxt);
10088 else if (op->value == 1)
10089 xmlXPathDivValues(ctxt);
10090 else if (op->value == 2)
10091 xmlXPathModValues(ctxt);
10092 return (total);
10093 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010094 bakd = ctxt->context->doc;
10095 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010096 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010097 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010098 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010099 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010100 ctxt->context->doc = bakd;
10101 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010102 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010103 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010104 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010105 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010106 CHECK_TYPE0(XPATH_NODESET);
10107 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010108
Daniel Veillardf06307e2001-07-03 10:35:50 +000010109 CHECK_TYPE0(XPATH_NODESET);
10110 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010111
Daniel Veillardf06307e2001-07-03 10:35:50 +000010112 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10113 arg2->nodesetval);
10114 valuePush(ctxt, arg1);
10115 xmlXPathFreeObject(arg2);
10116 return (total);
10117 case XPATH_OP_ROOT:
10118 xmlXPathRoot(ctxt);
10119 return (total);
10120 case XPATH_OP_NODE:
10121 if (op->ch1 != -1)
10122 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010123 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010124 if (op->ch2 != -1)
10125 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010126 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010127 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10128 return (total);
10129 case XPATH_OP_RESET:
10130 if (op->ch1 != -1)
10131 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010132 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010133 if (op->ch2 != -1)
10134 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010135 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010136 ctxt->context->node = NULL;
10137 return (total);
10138 case XPATH_OP_COLLECT:{
10139 if (op->ch1 == -1)
10140 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010141
Daniel Veillardf06307e2001-07-03 10:35:50 +000010142 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010143 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010144
Daniel Veillardf06307e2001-07-03 10:35:50 +000010145 /*
10146 * Optimization for [n] selection where n is a number
10147 */
10148 if ((op->ch2 != -1) &&
10149 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10150 (comp->steps[op->ch2].ch1 == -1) &&
10151 (comp->steps[op->ch2].ch2 != -1) &&
10152 (comp->steps[comp->steps[op->ch2].ch2].op ==
10153 XPATH_OP_VALUE)) {
10154 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010155
Daniel Veillardf06307e2001-07-03 10:35:50 +000010156 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10157 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10158 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010159
Daniel Veillardf06307e2001-07-03 10:35:50 +000010160 if (val->floatval == (float) indx) {
10161 total +=
10162 xmlXPathNodeCollectAndTestNth(ctxt, op,
10163 indx, NULL,
10164 NULL);
10165 return (total);
10166 }
10167 }
10168 }
10169 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10170 return (total);
10171 }
10172 case XPATH_OP_VALUE:
10173 valuePush(ctxt,
10174 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10175 return (total);
10176 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010177 xmlXPathObjectPtr val;
10178
Daniel Veillardf06307e2001-07-03 10:35:50 +000010179 if (op->ch1 != -1)
10180 total +=
10181 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010182 if (op->value5 == NULL) {
10183 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10184 if (val == NULL) {
10185 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10186 return(0);
10187 }
10188 valuePush(ctxt, val);
10189 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010190 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010191
Daniel Veillardf06307e2001-07-03 10:35:50 +000010192 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10193 if (URI == NULL) {
10194 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010195 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010196 op->value4, op->value5);
10197 return (total);
10198 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010199 val = xmlXPathVariableLookupNS(ctxt->context,
10200 op->value4, URI);
10201 if (val == NULL) {
10202 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10203 return(0);
10204 }
10205 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010206 }
10207 return (total);
10208 }
10209 case XPATH_OP_FUNCTION:{
10210 xmlXPathFunction func;
10211 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010212 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010213
10214 if (op->ch1 != -1)
10215 total +=
10216 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010217 if (ctxt->valueNr < op->value) {
10218 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010219 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010220 ctxt->error = XPATH_INVALID_OPERAND;
10221 return (total);
10222 }
10223 for (i = 0; i < op->value; i++)
10224 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10225 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010226 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010227 ctxt->error = XPATH_INVALID_OPERAND;
10228 return (total);
10229 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010230 if (op->cache != NULL)
10231 func = (xmlXPathFunction) op->cache;
10232 else {
10233 const xmlChar *URI = NULL;
10234
10235 if (op->value5 == NULL)
10236 func =
10237 xmlXPathFunctionLookup(ctxt->context,
10238 op->value4);
10239 else {
10240 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10241 if (URI == NULL) {
10242 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010243 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010244 op->value4, op->value5);
10245 return (total);
10246 }
10247 func = xmlXPathFunctionLookupNS(ctxt->context,
10248 op->value4, URI);
10249 }
10250 if (func == NULL) {
10251 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010252 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010253 op->value4);
10254 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010255 }
10256 op->cache = (void *) func;
10257 op->cacheURI = (void *) URI;
10258 }
10259 oldFunc = ctxt->context->function;
10260 oldFuncURI = ctxt->context->functionURI;
10261 ctxt->context->function = op->value4;
10262 ctxt->context->functionURI = op->cacheURI;
10263 func(ctxt, op->value);
10264 ctxt->context->function = oldFunc;
10265 ctxt->context->functionURI = oldFuncURI;
10266 return (total);
10267 }
10268 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010269 bakd = ctxt->context->doc;
10270 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010271 if (op->ch1 != -1)
10272 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010273 ctxt->context->doc = bakd;
10274 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010275 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010276 if (op->ch2 != -1)
10277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010278 ctxt->context->doc = bakd;
10279 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010280 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010281 return (total);
10282 case XPATH_OP_PREDICATE:
10283 case XPATH_OP_FILTER:{
10284 xmlXPathObjectPtr res;
10285 xmlXPathObjectPtr obj, tmp;
10286 xmlNodeSetPtr newset = NULL;
10287 xmlNodeSetPtr oldset;
10288 xmlNodePtr oldnode;
10289 int i;
10290
10291 /*
10292 * Optimization for ()[1] selection i.e. the first elem
10293 */
10294 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10295 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10296 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10297 xmlXPathObjectPtr val;
10298
10299 val = comp->steps[op->ch2].value4;
10300 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10301 (val->floatval == 1.0)) {
10302 xmlNodePtr first = NULL;
10303
10304 total +=
10305 xmlXPathCompOpEvalFirst(ctxt,
10306 &comp->steps[op->ch1],
10307 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010308 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010309 /*
10310 * The nodeset should be in document order,
10311 * Keep only the first value
10312 */
10313 if ((ctxt->value != NULL) &&
10314 (ctxt->value->type == XPATH_NODESET) &&
10315 (ctxt->value->nodesetval != NULL) &&
10316 (ctxt->value->nodesetval->nodeNr > 1))
10317 ctxt->value->nodesetval->nodeNr = 1;
10318 return (total);
10319 }
10320 }
10321 /*
10322 * Optimization for ()[last()] selection i.e. the last elem
10323 */
10324 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10325 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10326 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10327 int f = comp->steps[op->ch2].ch1;
10328
10329 if ((f != -1) &&
10330 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10331 (comp->steps[f].value5 == NULL) &&
10332 (comp->steps[f].value == 0) &&
10333 (comp->steps[f].value4 != NULL) &&
10334 (xmlStrEqual
10335 (comp->steps[f].value4, BAD_CAST "last"))) {
10336 xmlNodePtr last = NULL;
10337
10338 total +=
10339 xmlXPathCompOpEvalLast(ctxt,
10340 &comp->steps[op->ch1],
10341 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010342 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010343 /*
10344 * The nodeset should be in document order,
10345 * Keep only the last value
10346 */
10347 if ((ctxt->value != NULL) &&
10348 (ctxt->value->type == XPATH_NODESET) &&
10349 (ctxt->value->nodesetval != NULL) &&
10350 (ctxt->value->nodesetval->nodeTab != NULL) &&
10351 (ctxt->value->nodesetval->nodeNr > 1)) {
10352 ctxt->value->nodesetval->nodeTab[0] =
10353 ctxt->value->nodesetval->nodeTab[ctxt->
10354 value->
10355 nodesetval->
10356 nodeNr -
10357 1];
10358 ctxt->value->nodesetval->nodeNr = 1;
10359 }
10360 return (total);
10361 }
10362 }
10363
10364 if (op->ch1 != -1)
10365 total +=
10366 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010367 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010368 if (op->ch2 == -1)
10369 return (total);
10370 if (ctxt->value == NULL)
10371 return (total);
10372
10373 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010374
10375#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010376 /*
10377 * Hum are we filtering the result of an XPointer expression
10378 */
10379 if (ctxt->value->type == XPATH_LOCATIONSET) {
10380 xmlLocationSetPtr newlocset = NULL;
10381 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010382
Daniel Veillardf06307e2001-07-03 10:35:50 +000010383 /*
10384 * Extract the old locset, and then evaluate the result of the
10385 * expression for all the element in the locset. use it to grow
10386 * up a new locset.
10387 */
10388 CHECK_TYPE0(XPATH_LOCATIONSET);
10389 obj = valuePop(ctxt);
10390 oldlocset = obj->user;
10391 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010392
Daniel Veillardf06307e2001-07-03 10:35:50 +000010393 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10394 ctxt->context->contextSize = 0;
10395 ctxt->context->proximityPosition = 0;
10396 if (op->ch2 != -1)
10397 total +=
10398 xmlXPathCompOpEval(ctxt,
10399 &comp->steps[op->ch2]);
10400 res = valuePop(ctxt);
10401 if (res != NULL)
10402 xmlXPathFreeObject(res);
10403 valuePush(ctxt, obj);
10404 CHECK_ERROR0;
10405 return (total);
10406 }
10407 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010408
Daniel Veillardf06307e2001-07-03 10:35:50 +000010409 for (i = 0; i < oldlocset->locNr; i++) {
10410 /*
10411 * Run the evaluation with a node list made of a
10412 * single item in the nodelocset.
10413 */
10414 ctxt->context->node = oldlocset->locTab[i]->user;
10415 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10416 valuePush(ctxt, tmp);
10417 ctxt->context->contextSize = oldlocset->locNr;
10418 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010419
Daniel Veillardf06307e2001-07-03 10:35:50 +000010420 if (op->ch2 != -1)
10421 total +=
10422 xmlXPathCompOpEval(ctxt,
10423 &comp->steps[op->ch2]);
10424 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010425
Daniel Veillardf06307e2001-07-03 10:35:50 +000010426 /*
10427 * The result of the evaluation need to be tested to
10428 * decided whether the filter succeeded or not
10429 */
10430 res = valuePop(ctxt);
10431 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10432 xmlXPtrLocationSetAdd(newlocset,
10433 xmlXPathObjectCopy
10434 (oldlocset->locTab[i]));
10435 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010436
Daniel Veillardf06307e2001-07-03 10:35:50 +000010437 /*
10438 * Cleanup
10439 */
10440 if (res != NULL)
10441 xmlXPathFreeObject(res);
10442 if (ctxt->value == tmp) {
10443 res = valuePop(ctxt);
10444 xmlXPathFreeObject(res);
10445 }
10446
10447 ctxt->context->node = NULL;
10448 }
10449
10450 /*
10451 * The result is used as the new evaluation locset.
10452 */
10453 xmlXPathFreeObject(obj);
10454 ctxt->context->node = NULL;
10455 ctxt->context->contextSize = -1;
10456 ctxt->context->proximityPosition = -1;
10457 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10458 ctxt->context->node = oldnode;
10459 return (total);
10460 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010461#endif /* LIBXML_XPTR_ENABLED */
10462
Daniel Veillardf06307e2001-07-03 10:35:50 +000010463 /*
10464 * Extract the old set, and then evaluate the result of the
10465 * expression for all the element in the set. use it to grow
10466 * up a new set.
10467 */
10468 CHECK_TYPE0(XPATH_NODESET);
10469 obj = valuePop(ctxt);
10470 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010471
Daniel Veillardf06307e2001-07-03 10:35:50 +000010472 oldnode = ctxt->context->node;
10473 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010474
Daniel Veillardf06307e2001-07-03 10:35:50 +000010475 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10476 ctxt->context->contextSize = 0;
10477 ctxt->context->proximityPosition = 0;
10478 if (op->ch2 != -1)
10479 total +=
10480 xmlXPathCompOpEval(ctxt,
10481 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010482 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010483 res = valuePop(ctxt);
10484 if (res != NULL)
10485 xmlXPathFreeObject(res);
10486 valuePush(ctxt, obj);
10487 ctxt->context->node = oldnode;
10488 CHECK_ERROR0;
10489 } else {
10490 /*
10491 * Initialize the new set.
10492 */
10493 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010494
Daniel Veillardf06307e2001-07-03 10:35:50 +000010495 for (i = 0; i < oldset->nodeNr; i++) {
10496 /*
10497 * Run the evaluation with a node list made of
10498 * a single item in the nodeset.
10499 */
10500 ctxt->context->node = oldset->nodeTab[i];
10501 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10502 valuePush(ctxt, tmp);
10503 ctxt->context->contextSize = oldset->nodeNr;
10504 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010505
Daniel Veillardf06307e2001-07-03 10:35:50 +000010506 if (op->ch2 != -1)
10507 total +=
10508 xmlXPathCompOpEval(ctxt,
10509 &comp->steps[op->ch2]);
10510 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010511
Daniel Veillardf06307e2001-07-03 10:35:50 +000010512 /*
10513 * The result of the evaluation need to be tested to
10514 * decided whether the filter succeeded or not
10515 */
10516 res = valuePop(ctxt);
10517 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10518 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10519 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010520
Daniel Veillardf06307e2001-07-03 10:35:50 +000010521 /*
10522 * Cleanup
10523 */
10524 if (res != NULL)
10525 xmlXPathFreeObject(res);
10526 if (ctxt->value == tmp) {
10527 res = valuePop(ctxt);
10528 xmlXPathFreeObject(res);
10529 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010530
Daniel Veillardf06307e2001-07-03 10:35:50 +000010531 ctxt->context->node = NULL;
10532 }
10533
10534 /*
10535 * The result is used as the new evaluation set.
10536 */
10537 xmlXPathFreeObject(obj);
10538 ctxt->context->node = NULL;
10539 ctxt->context->contextSize = -1;
10540 ctxt->context->proximityPosition = -1;
10541 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10542 }
10543 ctxt->context->node = oldnode;
10544 return (total);
10545 }
10546 case XPATH_OP_SORT:
10547 if (op->ch1 != -1)
10548 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010549 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010550 if ((ctxt->value != NULL) &&
10551 (ctxt->value->type == XPATH_NODESET) &&
10552 (ctxt->value->nodesetval != NULL))
10553 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10554 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010555#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010556 case XPATH_OP_RANGETO:{
10557 xmlXPathObjectPtr range;
10558 xmlXPathObjectPtr res, obj;
10559 xmlXPathObjectPtr tmp;
10560 xmlLocationSetPtr newset = NULL;
10561 xmlNodeSetPtr oldset;
10562 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010563
Daniel Veillardf06307e2001-07-03 10:35:50 +000010564 if (op->ch1 != -1)
10565 total +=
10566 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10567 if (op->ch2 == -1)
10568 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010569
Daniel Veillardf06307e2001-07-03 10:35:50 +000010570 CHECK_TYPE0(XPATH_NODESET);
10571 obj = valuePop(ctxt);
10572 oldset = obj->nodesetval;
10573 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010574
Daniel Veillardf06307e2001-07-03 10:35:50 +000010575 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010576
Daniel Veillardf06307e2001-07-03 10:35:50 +000010577 if (oldset != NULL) {
10578 for (i = 0; i < oldset->nodeNr; i++) {
10579 /*
10580 * Run the evaluation with a node list made of a single item
10581 * in the nodeset.
10582 */
10583 ctxt->context->node = oldset->nodeTab[i];
10584 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10585 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010586
Daniel Veillardf06307e2001-07-03 10:35:50 +000010587 if (op->ch2 != -1)
10588 total +=
10589 xmlXPathCompOpEval(ctxt,
10590 &comp->steps[op->ch2]);
10591 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010592
Daniel Veillardf06307e2001-07-03 10:35:50 +000010593 /*
10594 * The result of the evaluation need to be tested to
10595 * decided whether the filter succeeded or not
10596 */
10597 res = valuePop(ctxt);
10598 range =
10599 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10600 res);
10601 if (range != NULL) {
10602 xmlXPtrLocationSetAdd(newset, range);
10603 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010604
Daniel Veillardf06307e2001-07-03 10:35:50 +000010605 /*
10606 * Cleanup
10607 */
10608 if (res != NULL)
10609 xmlXPathFreeObject(res);
10610 if (ctxt->value == tmp) {
10611 res = valuePop(ctxt);
10612 xmlXPathFreeObject(res);
10613 }
10614
10615 ctxt->context->node = NULL;
10616 }
10617 }
10618
10619 /*
10620 * The result is used as the new evaluation set.
10621 */
10622 xmlXPathFreeObject(obj);
10623 ctxt->context->node = NULL;
10624 ctxt->context->contextSize = -1;
10625 ctxt->context->proximityPosition = -1;
10626 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10627 return (total);
10628 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010629#endif /* LIBXML_XPTR_ENABLED */
10630 }
10631 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010632 "XPath: unknown precompiled operation %d\n", op->op);
10633 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010634}
10635
10636/**
10637 * xmlXPathRunEval:
10638 * @ctxt: the XPath parser context with the compiled expression
10639 *
10640 * Evaluate the Precompiled XPath expression in the given context.
10641 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010642static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010643xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10644 xmlXPathCompExprPtr comp;
10645
10646 if ((ctxt == NULL) || (ctxt->comp == NULL))
10647 return;
10648
10649 if (ctxt->valueTab == NULL) {
10650 /* Allocate the value stack */
10651 ctxt->valueTab = (xmlXPathObjectPtr *)
10652 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10653 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010654 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010655 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010656 }
10657 ctxt->valueNr = 0;
10658 ctxt->valueMax = 10;
10659 ctxt->value = NULL;
10660 }
10661 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010662 if(comp->last < 0) {
10663 xmlGenericError(xmlGenericErrorContext,
10664 "xmlXPathRunEval: last is less than zero\n");
10665 return;
10666 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010667 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10668}
10669
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010670/************************************************************************
10671 * *
10672 * Public interfaces *
10673 * *
10674 ************************************************************************/
10675
10676/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010677 * xmlXPathEvalPredicate:
10678 * @ctxt: the XPath context
10679 * @res: the Predicate Expression evaluation result
10680 *
10681 * Evaluate a predicate result for the current node.
10682 * A PredicateExpr is evaluated by evaluating the Expr and converting
10683 * the result to a boolean. If the result is a number, the result will
10684 * be converted to true if the number is equal to the position of the
10685 * context node in the context node list (as returned by the position
10686 * function) and will be converted to false otherwise; if the result
10687 * is not a number, then the result will be converted as if by a call
10688 * to the boolean function.
10689 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010690 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010691 */
10692int
10693xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10694 if (res == NULL) return(0);
10695 switch (res->type) {
10696 case XPATH_BOOLEAN:
10697 return(res->boolval);
10698 case XPATH_NUMBER:
10699 return(res->floatval == ctxt->proximityPosition);
10700 case XPATH_NODESET:
10701 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010702 if (res->nodesetval == NULL)
10703 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010704 return(res->nodesetval->nodeNr != 0);
10705 case XPATH_STRING:
10706 return((res->stringval != NULL) &&
10707 (xmlStrlen(res->stringval) != 0));
10708 default:
10709 STRANGE
10710 }
10711 return(0);
10712}
10713
10714/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010715 * xmlXPathEvaluatePredicateResult:
10716 * @ctxt: the XPath Parser context
10717 * @res: the Predicate Expression evaluation result
10718 *
10719 * Evaluate a predicate result for the current node.
10720 * A PredicateExpr is evaluated by evaluating the Expr and converting
10721 * the result to a boolean. If the result is a number, the result will
10722 * be converted to true if the number is equal to the position of the
10723 * context node in the context node list (as returned by the position
10724 * function) and will be converted to false otherwise; if the result
10725 * is not a number, then the result will be converted as if by a call
10726 * to the boolean function.
10727 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010728 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010729 */
10730int
10731xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10732 xmlXPathObjectPtr res) {
10733 if (res == NULL) return(0);
10734 switch (res->type) {
10735 case XPATH_BOOLEAN:
10736 return(res->boolval);
10737 case XPATH_NUMBER:
10738 return(res->floatval == ctxt->context->proximityPosition);
10739 case XPATH_NODESET:
10740 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010741 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010742 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010743 return(res->nodesetval->nodeNr != 0);
10744 case XPATH_STRING:
10745 return((res->stringval != NULL) &&
10746 (xmlStrlen(res->stringval) != 0));
10747 default:
10748 STRANGE
10749 }
10750 return(0);
10751}
10752
10753/**
10754 * xmlXPathCompile:
10755 * @str: the XPath expression
10756 *
10757 * Compile an XPath expression
10758 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010759 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010760 * the caller has to free the object.
10761 */
10762xmlXPathCompExprPtr
10763xmlXPathCompile(const xmlChar *str) {
10764 xmlXPathParserContextPtr ctxt;
10765 xmlXPathCompExprPtr comp;
10766
10767 xmlXPathInit();
10768
10769 ctxt = xmlXPathNewParserContext(str, NULL);
10770 xmlXPathCompileExpr(ctxt);
Daniel Veillardae9733a2003-10-28 19:02:21 +000010771
10772 if( ctxt->error != XPATH_EXPRESSION_OK )
10773 {
10774 xmlXPathFreeParserContext(ctxt);
10775 return (0);
10776 }
10777
Daniel Veillard40af6492001-04-22 08:50:55 +000010778 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010779 /*
10780 * aleksey: in some cases this line prints *second* error message
10781 * (see bug #78858) and probably this should be fixed.
10782 * However, we are not sure that all error messages are printed
10783 * out in other places. It's not critical so we leave it as-is for now
10784 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010785 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10786 comp = NULL;
10787 } else {
10788 comp = ctxt->comp;
10789 ctxt->comp = NULL;
10790 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010791 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010792 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010793 comp->expr = xmlStrdup(str);
10794#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010795 comp->string = xmlStrdup(str);
10796 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010797#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010798 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010799 return(comp);
10800}
10801
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010802/**
10803 * xmlXPathCompiledEval:
10804 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010805 * @ctx: the XPath context
10806 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010807 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010808 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010809 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010810 * the caller has to free the object.
10811 */
10812xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010813xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010814 xmlXPathParserContextPtr ctxt;
10815 xmlXPathObjectPtr res, tmp, init = NULL;
10816 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010817#ifndef LIBXML_THREAD_ENABLED
10818 static int reentance = 0;
10819#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010820
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010821 if ((comp == NULL) || (ctx == NULL))
10822 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010823 xmlXPathInit();
10824
10825 CHECK_CONTEXT(ctx)
10826
Daniel Veillard81463942001-10-16 12:34:39 +000010827#ifndef LIBXML_THREAD_ENABLED
10828 reentance++;
10829 if (reentance > 1)
10830 xmlXPathDisableOptimizer = 1;
10831#endif
10832
Daniel Veillardf06307e2001-07-03 10:35:50 +000010833#ifdef DEBUG_EVAL_COUNTS
10834 comp->nb++;
10835 if ((comp->string != NULL) && (comp->nb > 100)) {
10836 fprintf(stderr, "100 x %s\n", comp->string);
10837 comp->nb = 0;
10838 }
10839#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010840 ctxt = xmlXPathCompParserContext(comp, ctx);
10841 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010842
10843 if (ctxt->value == NULL) {
10844 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010845 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010846 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010847 } else {
10848 res = valuePop(ctxt);
10849 }
10850
Daniel Veillardf06307e2001-07-03 10:35:50 +000010851
Owen Taylor3473f882001-02-23 17:55:21 +000010852 do {
10853 tmp = valuePop(ctxt);
10854 if (tmp != NULL) {
10855 if (tmp != init)
10856 stack++;
10857 xmlXPathFreeObject(tmp);
10858 }
10859 } while (tmp != NULL);
10860 if ((stack != 0) && (res != NULL)) {
10861 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010862 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010863 stack);
10864 }
10865 if (ctxt->error != XPATH_EXPRESSION_OK) {
10866 xmlXPathFreeObject(res);
10867 res = NULL;
10868 }
10869
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010870
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010871 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010872 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010873#ifndef LIBXML_THREAD_ENABLED
10874 reentance--;
10875#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010876 return(res);
10877}
10878
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010879/**
10880 * xmlXPathEvalExpr:
10881 * @ctxt: the XPath Parser context
10882 *
10883 * Parse and evaluate an XPath expression in the given context,
10884 * then push the result on the context stack
10885 */
10886void
10887xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10888 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010889 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010890 xmlXPathRunEval(ctxt);
10891}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010892
10893/**
10894 * xmlXPathEval:
10895 * @str: the XPath expression
10896 * @ctx: the XPath context
10897 *
10898 * Evaluate the XPath Location Path in the given context.
10899 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010900 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010901 * the caller has to free the object.
10902 */
10903xmlXPathObjectPtr
10904xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10905 xmlXPathParserContextPtr ctxt;
10906 xmlXPathObjectPtr res, tmp, init = NULL;
10907 int stack = 0;
10908
10909 xmlXPathInit();
10910
10911 CHECK_CONTEXT(ctx)
10912
10913 ctxt = xmlXPathNewParserContext(str, ctx);
10914 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010915
10916 if (ctxt->value == NULL) {
10917 xmlGenericError(xmlGenericErrorContext,
10918 "xmlXPathEval: evaluation failed\n");
10919 res = NULL;
10920 } else if (*ctxt->cur != 0) {
10921 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10922 res = NULL;
10923 } else {
10924 res = valuePop(ctxt);
10925 }
10926
10927 do {
10928 tmp = valuePop(ctxt);
10929 if (tmp != NULL) {
10930 if (tmp != init)
10931 stack++;
10932 xmlXPathFreeObject(tmp);
10933 }
10934 } while (tmp != NULL);
10935 if ((stack != 0) && (res != NULL)) {
10936 xmlGenericError(xmlGenericErrorContext,
10937 "xmlXPathEval: %d object left on the stack\n",
10938 stack);
10939 }
10940 if (ctxt->error != XPATH_EXPRESSION_OK) {
10941 xmlXPathFreeObject(res);
10942 res = NULL;
10943 }
10944
Owen Taylor3473f882001-02-23 17:55:21 +000010945 xmlXPathFreeParserContext(ctxt);
10946 return(res);
10947}
10948
10949/**
10950 * xmlXPathEvalExpression:
10951 * @str: the XPath expression
10952 * @ctxt: the XPath context
10953 *
10954 * Evaluate the XPath expression in the given context.
10955 *
10956 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10957 * the caller has to free the object.
10958 */
10959xmlXPathObjectPtr
10960xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10961 xmlXPathParserContextPtr pctxt;
10962 xmlXPathObjectPtr res, tmp;
10963 int stack = 0;
10964
10965 xmlXPathInit();
10966
10967 CHECK_CONTEXT(ctxt)
10968
10969 pctxt = xmlXPathNewParserContext(str, ctxt);
10970 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010971
10972 if (*pctxt->cur != 0) {
10973 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10974 res = NULL;
10975 } else {
10976 res = valuePop(pctxt);
10977 }
10978 do {
10979 tmp = valuePop(pctxt);
10980 if (tmp != NULL) {
10981 xmlXPathFreeObject(tmp);
10982 stack++;
10983 }
10984 } while (tmp != NULL);
10985 if ((stack != 0) && (res != NULL)) {
10986 xmlGenericError(xmlGenericErrorContext,
10987 "xmlXPathEvalExpression: %d object left on the stack\n",
10988 stack);
10989 }
10990 xmlXPathFreeParserContext(pctxt);
10991 return(res);
10992}
10993
Daniel Veillard42766c02002-08-22 20:52:17 +000010994/************************************************************************
10995 * *
10996 * Extra functions not pertaining to the XPath spec *
10997 * *
10998 ************************************************************************/
10999/**
11000 * xmlXPathEscapeUriFunction:
11001 * @ctxt: the XPath Parser context
11002 * @nargs: the number of arguments
11003 *
11004 * Implement the escape-uri() XPath function
11005 * string escape-uri(string $str, bool $escape-reserved)
11006 *
11007 * This function applies the URI escaping rules defined in section 2 of [RFC
11008 * 2396] to the string supplied as $uri-part, which typically represents all
11009 * or part of a URI. The effect of the function is to replace any special
11010 * character in the string by an escape sequence of the form %xx%yy...,
11011 * where xxyy... is the hexadecimal representation of the octets used to
11012 * represent the character in UTF-8.
11013 *
11014 * The set of characters that are escaped depends on the setting of the
11015 * boolean argument $escape-reserved.
11016 *
11017 * If $escape-reserved is true, all characters are escaped other than lower
11018 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11019 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11020 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11021 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11022 * A-F).
11023 *
11024 * If $escape-reserved is false, the behavior differs in that characters
11025 * referred to in [RFC 2396] as reserved characters are not escaped. These
11026 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11027 *
11028 * [RFC 2396] does not define whether escaped URIs should use lower case or
11029 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11030 * compared using string comparison functions, this function must always use
11031 * the upper-case letters A-F.
11032 *
11033 * Generally, $escape-reserved should be set to true when escaping a string
11034 * that is to form a single part of a URI, and to false when escaping an
11035 * entire URI or URI reference.
11036 *
11037 * In the case of non-ascii characters, the string is encoded according to
11038 * utf-8 and then converted according to RFC 2396.
11039 *
11040 * Examples
11041 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11042 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11043 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11044 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11045 *
11046 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011047static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011048xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11049 xmlXPathObjectPtr str;
11050 int escape_reserved;
11051 xmlBufferPtr target;
11052 xmlChar *cptr;
11053 xmlChar escape[4];
11054
11055 CHECK_ARITY(2);
11056
11057 escape_reserved = xmlXPathPopBoolean(ctxt);
11058
11059 CAST_TO_STRING;
11060 str = valuePop(ctxt);
11061
11062 target = xmlBufferCreate();
11063
11064 escape[0] = '%';
11065 escape[3] = 0;
11066
11067 if (target) {
11068 for (cptr = str->stringval; *cptr; cptr++) {
11069 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11070 (*cptr >= 'a' && *cptr <= 'z') ||
11071 (*cptr >= '0' && *cptr <= '9') ||
11072 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11073 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11074 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11075 (*cptr == '%' &&
11076 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11077 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11078 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11079 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11080 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11081 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11082 (!escape_reserved &&
11083 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11084 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11085 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11086 *cptr == ','))) {
11087 xmlBufferAdd(target, cptr, 1);
11088 } else {
11089 if ((*cptr >> 4) < 10)
11090 escape[1] = '0' + (*cptr >> 4);
11091 else
11092 escape[1] = 'A' - 10 + (*cptr >> 4);
11093 if ((*cptr & 0xF) < 10)
11094 escape[2] = '0' + (*cptr & 0xF);
11095 else
11096 escape[2] = 'A' - 10 + (*cptr & 0xF);
11097
11098 xmlBufferAdd(target, &escape[0], 3);
11099 }
11100 }
11101 }
11102 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11103 xmlBufferFree(target);
11104 xmlXPathFreeObject(str);
11105}
11106
Owen Taylor3473f882001-02-23 17:55:21 +000011107/**
11108 * xmlXPathRegisterAllFunctions:
11109 * @ctxt: the XPath context
11110 *
11111 * Registers all default XPath functions in this context
11112 */
11113void
11114xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11115{
11116 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11117 xmlXPathBooleanFunction);
11118 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11119 xmlXPathCeilingFunction);
11120 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11121 xmlXPathCountFunction);
11122 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11123 xmlXPathConcatFunction);
11124 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11125 xmlXPathContainsFunction);
11126 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11127 xmlXPathIdFunction);
11128 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11129 xmlXPathFalseFunction);
11130 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11131 xmlXPathFloorFunction);
11132 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11133 xmlXPathLastFunction);
11134 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11135 xmlXPathLangFunction);
11136 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11137 xmlXPathLocalNameFunction);
11138 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11139 xmlXPathNotFunction);
11140 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11141 xmlXPathNameFunction);
11142 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11143 xmlXPathNamespaceURIFunction);
11144 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11145 xmlXPathNormalizeFunction);
11146 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11147 xmlXPathNumberFunction);
11148 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11149 xmlXPathPositionFunction);
11150 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11151 xmlXPathRoundFunction);
11152 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11153 xmlXPathStringFunction);
11154 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11155 xmlXPathStringLengthFunction);
11156 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11157 xmlXPathStartsWithFunction);
11158 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11159 xmlXPathSubstringFunction);
11160 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11161 xmlXPathSubstringBeforeFunction);
11162 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11163 xmlXPathSubstringAfterFunction);
11164 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11165 xmlXPathSumFunction);
11166 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11167 xmlXPathTrueFunction);
11168 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11169 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011170
11171 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11172 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11173 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011174}
11175
11176#endif /* LIBXML_XPATH_ENABLED */