blob: dab054598615a0136d78e9a9cbffdafa3a098139 [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 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Daniel Veillard34ce8be2002-03-18 19:37:11 +000019#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000020#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000021#ifdef LIBXML_XPATH_ENABLED
22
Owen Taylor3473f882001-02-23 17:55:21 +000023#include <string.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31#ifdef HAVE_FLOAT_H
32#include <float.h>
33#endif
Owen Taylor3473f882001-02-23 17:55:21 +000034#ifdef HAVE_CTYPE_H
35#include <ctype.h>
36#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000037#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000039#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
41#include <libxml/xmlmemory.h>
42#include <libxml/tree.h>
43#include <libxml/valid.h>
44#include <libxml/xpath.h>
45#include <libxml/xpathInternals.h>
46#include <libxml/parserInternals.h>
47#include <libxml/hash.h>
48#ifdef LIBXML_XPTR_ENABLED
49#include <libxml/xpointer.h>
50#endif
51#ifdef LIBXML_DEBUG_ENABLED
52#include <libxml/debugXML.h>
53#endif
54#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000055#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000056#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000057
58/* #define DEBUG */
59/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000060/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000061/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000062/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000063
Daniel Veillard5792e162001-04-30 17:44:45 +000064double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000065
Daniel Veillard20ee8c02001-10-05 09:18:14 +000066static xmlNs xmlXPathXMLNamespaceStruct = {
67 NULL,
68 XML_NAMESPACE_DECL,
69 XML_XML_NAMESPACE,
70 BAD_CAST "xml"
71};
72static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillardda423da2002-04-10 19:25:38 +000073#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +000074/*
75 * Optimizer is disabled only when threaded apps are detected while
76 * the library ain't compiled for thread safety.
77 */
78static int xmlXPathDisableOptimizer = 0;
79#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000080
Daniel Veillard9e7160d2001-03-18 23:17:47 +000081/************************************************************************
82 * *
83 * Floating point stuff *
84 * *
85 ************************************************************************/
86
Daniel Veillardc0631a62001-09-20 13:56:06 +000087#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000088#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000089#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000090#include "trionan.c"
91
Owen Taylor3473f882001-02-23 17:55:21 +000092/*
Owen Taylor3473f882001-02-23 17:55:21 +000093 * The lack of portability of this section of the libc is annoying !
94 */
95double xmlXPathNAN = 0;
96double xmlXPathPINF = 1;
97double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000098double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000099static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000100
Owen Taylor3473f882001-02-23 17:55:21 +0000101/**
102 * xmlXPathInit:
103 *
104 * Initialize the XPath environment
105 */
106void
107xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000108 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000109
Bjorn Reese45029602001-08-21 09:23:53 +0000110 xmlXPathPINF = trio_pinf();
111 xmlXPathNINF = trio_ninf();
112 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000113 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000114
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000115 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000116}
117
Daniel Veillardcda96922001-08-21 10:56:31 +0000118/**
119 * xmlXPathIsNaN:
120 * @val: a double value
121 *
122 * Provides a portable isnan() function to detect whether a double
123 * is a NotaNumber. Based on trio code
124 * http://sourceforge.net/projects/ctrio/
125 *
126 * Returns 1 if the value is a NaN, 0 otherwise
127 */
128int
129xmlXPathIsNaN(double val) {
130 return(trio_isnan(val));
131}
132
133/**
134 * xmlXPathIsInf:
135 * @val: a double value
136 *
137 * Provides a portable isinf() function to detect whether a double
138 * is a +Infinite or -Infinite. Based on trio code
139 * http://sourceforge.net/projects/ctrio/
140 *
141 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
142 */
143int
144xmlXPathIsInf(double val) {
145 return(trio_isinf(val));
146}
147
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000148/**
149 * xmlXPathGetSign:
150 * @val: a double value
151 *
152 * Provides a portable function to detect the sign of a double
153 * Modified from trio code
154 * http://sourceforge.net/projects/ctrio/
155 *
156 * Returns 1 if the value is Negative, 0 if positive
157 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000158static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000159xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000160 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000161}
162
163
Owen Taylor3473f882001-02-23 17:55:21 +0000164/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000165 * *
166 * Parser Types *
167 * *
168 ************************************************************************/
169
170/*
171 * Types are private:
172 */
173
174typedef enum {
175 XPATH_OP_END=0,
176 XPATH_OP_AND,
177 XPATH_OP_OR,
178 XPATH_OP_EQUAL,
179 XPATH_OP_CMP,
180 XPATH_OP_PLUS,
181 XPATH_OP_MULT,
182 XPATH_OP_UNION,
183 XPATH_OP_ROOT,
184 XPATH_OP_NODE,
185 XPATH_OP_RESET,
186 XPATH_OP_COLLECT,
187 XPATH_OP_VALUE,
188 XPATH_OP_VARIABLE,
189 XPATH_OP_FUNCTION,
190 XPATH_OP_ARG,
191 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000192 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000193 XPATH_OP_SORT
194#ifdef LIBXML_XPTR_ENABLED
195 ,XPATH_OP_RANGETO
196#endif
197} xmlXPathOp;
198
199typedef enum {
200 AXIS_ANCESTOR = 1,
201 AXIS_ANCESTOR_OR_SELF,
202 AXIS_ATTRIBUTE,
203 AXIS_CHILD,
204 AXIS_DESCENDANT,
205 AXIS_DESCENDANT_OR_SELF,
206 AXIS_FOLLOWING,
207 AXIS_FOLLOWING_SIBLING,
208 AXIS_NAMESPACE,
209 AXIS_PARENT,
210 AXIS_PRECEDING,
211 AXIS_PRECEDING_SIBLING,
212 AXIS_SELF
213} xmlXPathAxisVal;
214
215typedef enum {
216 NODE_TEST_NONE = 0,
217 NODE_TEST_TYPE = 1,
218 NODE_TEST_PI = 2,
219 NODE_TEST_ALL = 3,
220 NODE_TEST_NS = 4,
221 NODE_TEST_NAME = 5
222} xmlXPathTestVal;
223
224typedef enum {
225 NODE_TYPE_NODE = 0,
226 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
227 NODE_TYPE_TEXT = XML_TEXT_NODE,
228 NODE_TYPE_PI = XML_PI_NODE
229} xmlXPathTypeVal;
230
231
232typedef struct _xmlXPathStepOp xmlXPathStepOp;
233typedef xmlXPathStepOp *xmlXPathStepOpPtr;
234struct _xmlXPathStepOp {
235 xmlXPathOp op;
236 int ch1;
237 int ch2;
238 int value;
239 int value2;
240 int value3;
241 void *value4;
242 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000243 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000244 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000245};
246
247struct _xmlXPathCompExpr {
248 int nbStep;
249 int maxStep;
250 xmlXPathStepOp *steps; /* ops for computation */
251 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000252#ifdef DEBUG_EVAL_COUNTS
253 int nb;
254 xmlChar *string;
255#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000256};
257
258/************************************************************************
259 * *
260 * Parser Type functions *
261 * *
262 ************************************************************************/
263
264/**
265 * xmlXPathNewCompExpr:
266 *
267 * Create a new Xpath component
268 *
269 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
270 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000271static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000272xmlXPathNewCompExpr(void) {
273 xmlXPathCompExprPtr cur;
274
275 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
276 if (cur == NULL) {
277 xmlGenericError(xmlGenericErrorContext,
278 "xmlXPathNewCompExpr : malloc failed\n");
279 return(NULL);
280 }
281 memset(cur, 0, sizeof(xmlXPathCompExpr));
282 cur->maxStep = 10;
283 cur->nbStep = 0;
284 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
285 sizeof(xmlXPathStepOp));
286 if (cur->steps == NULL) {
287 xmlGenericError(xmlGenericErrorContext,
288 "xmlXPathNewCompExpr : malloc failed\n");
289 xmlFree(cur);
290 return(NULL);
291 }
292 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
293 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000294#ifdef DEBUG_EVAL_COUNTS
295 cur->nb = 0;
296#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000297 return(cur);
298}
299
300/**
301 * xmlXPathFreeCompExpr:
302 * @comp: an XPATH comp
303 *
304 * Free up the memory allocated by @comp
305 */
306void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000307xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
308{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000309 xmlXPathStepOpPtr op;
310 int i;
311
312 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000313 return;
314 for (i = 0; i < comp->nbStep; i++) {
315 op = &comp->steps[i];
316 if (op->value4 != NULL) {
317 if (op->op == XPATH_OP_VALUE)
318 xmlXPathFreeObject(op->value4);
319 else
320 xmlFree(op->value4);
321 }
322 if (op->value5 != NULL)
323 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000324 }
325 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000326 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000327 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328#ifdef DEBUG_EVAL_COUNTS
329 if (comp->string != NULL) {
330 xmlFree(comp->string);
331 }
332#endif
333
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000334 xmlFree(comp);
335}
336
337/**
338 * xmlXPathCompExprAdd:
339 * @comp: the compiled expression
340 * @ch1: first child index
341 * @ch2: second child index
342 * @op: an op
343 * @value: the first int value
344 * @value2: the second int value
345 * @value3: the third int value
346 * @value4: the first string value
347 * @value5: the second string value
348 *
349 * Add an step to an XPath Compiled Expression
350 *
351 * Returns -1 in case of failure, the index otherwise
352 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000353static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000354xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
355 xmlXPathOp op, int value,
356 int value2, int value3, void *value4, void *value5) {
357 if (comp->nbStep >= comp->maxStep) {
358 xmlXPathStepOp *real;
359
360 comp->maxStep *= 2;
361 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
362 comp->maxStep * sizeof(xmlXPathStepOp));
363 if (real == NULL) {
364 comp->maxStep /= 2;
365 xmlGenericError(xmlGenericErrorContext,
366 "xmlXPathCompExprAdd : realloc failed\n");
367 return(-1);
368 }
369 comp->steps = real;
370 }
371 comp->last = comp->nbStep;
372 comp->steps[comp->nbStep].ch1 = ch1;
373 comp->steps[comp->nbStep].ch2 = ch2;
374 comp->steps[comp->nbStep].op = op;
375 comp->steps[comp->nbStep].value = value;
376 comp->steps[comp->nbStep].value2 = value2;
377 comp->steps[comp->nbStep].value3 = value3;
378 comp->steps[comp->nbStep].value4 = value4;
379 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000380 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000381 return(comp->nbStep++);
382}
383
Daniel Veillardf06307e2001-07-03 10:35:50 +0000384/**
385 * xmlXPathCompSwap:
386 * @comp: the compiled expression
387 * @op: operation index
388 *
389 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000390 */
391static void
392xmlXPathCompSwap(xmlXPathStepOpPtr op) {
393 int tmp;
394
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000395#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000396 /*
397 * Since this manipulates possibly shared variables, this is
398 * disable if one detects that the library is used in a multithreaded
399 * application
400 */
401 if (xmlXPathDisableOptimizer)
402 return;
403#endif
404
Daniel Veillardf06307e2001-07-03 10:35:50 +0000405 tmp = op->ch1;
406 op->ch1 = op->ch2;
407 op->ch2 = tmp;
408}
409
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000410#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
411 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
412 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000413#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
414 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
415 (op), (val), (val2), (val3), (val4), (val5))
416
417#define PUSH_LEAVE_EXPR(op, val, val2) \
418xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
419
420#define PUSH_UNARY_EXPR(op, ch, val, val2) \
421xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
422
423#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
424xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
425
426/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000427 * *
428 * Debugging related functions *
429 * *
430 ************************************************************************/
431
432#define TODO \
433 xmlGenericError(xmlGenericErrorContext, \
434 "Unimplemented block at %s:%d\n", \
435 __FILE__, __LINE__);
436
437#define STRANGE \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Internal error at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000443static void
444xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000445 int i;
446 char shift[100];
447
448 for (i = 0;((i < depth) && (i < 25));i++)
449 shift[2 * i] = shift[2 * i + 1] = ' ';
450 shift[2 * i] = shift[2 * i + 1] = 0;
451 if (cur == NULL) {
452 fprintf(output, shift);
453 fprintf(output, "Node is NULL !\n");
454 return;
455
456 }
457
458 if ((cur->type == XML_DOCUMENT_NODE) ||
459 (cur->type == XML_HTML_DOCUMENT_NODE)) {
460 fprintf(output, shift);
461 fprintf(output, " /\n");
462 } else if (cur->type == XML_ATTRIBUTE_NODE)
463 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
464 else
465 xmlDebugDumpOneNode(output, cur, depth);
466}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000467static void
468xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000469 xmlNodePtr tmp;
470 int i;
471 char shift[100];
472
473 for (i = 0;((i < depth) && (i < 25));i++)
474 shift[2 * i] = shift[2 * i + 1] = ' ';
475 shift[2 * i] = shift[2 * i + 1] = 0;
476 if (cur == NULL) {
477 fprintf(output, shift);
478 fprintf(output, "Node is NULL !\n");
479 return;
480
481 }
482
483 while (cur != NULL) {
484 tmp = cur;
485 cur = cur->next;
486 xmlDebugDumpOneNode(output, tmp, depth);
487 }
488}
Owen Taylor3473f882001-02-23 17:55:21 +0000489
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000490static void
491xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000492 int i;
493 char shift[100];
494
495 for (i = 0;((i < depth) && (i < 25));i++)
496 shift[2 * i] = shift[2 * i + 1] = ' ';
497 shift[2 * i] = shift[2 * i + 1] = 0;
498
499 if (cur == NULL) {
500 fprintf(output, shift);
501 fprintf(output, "NodeSet is NULL !\n");
502 return;
503
504 }
505
Daniel Veillard911f49a2001-04-07 15:39:35 +0000506 if (cur != NULL) {
507 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
508 for (i = 0;i < cur->nodeNr;i++) {
509 fprintf(output, shift);
510 fprintf(output, "%d", i + 1);
511 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
512 }
Owen Taylor3473f882001-02-23 17:55:21 +0000513 }
514}
515
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000516static void
517xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000518 int i;
519 char shift[100];
520
521 for (i = 0;((i < depth) && (i < 25));i++)
522 shift[2 * i] = shift[2 * i + 1] = ' ';
523 shift[2 * i] = shift[2 * i + 1] = 0;
524
525 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
526 fprintf(output, shift);
527 fprintf(output, "Value Tree is NULL !\n");
528 return;
529
530 }
531
532 fprintf(output, shift);
533 fprintf(output, "%d", i + 1);
534 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
535}
Owen Taylor3473f882001-02-23 17:55:21 +0000536#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000537static void
538xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000539 int i;
540 char shift[100];
541
542 for (i = 0;((i < depth) && (i < 25));i++)
543 shift[2 * i] = shift[2 * i + 1] = ' ';
544 shift[2 * i] = shift[2 * i + 1] = 0;
545
546 if (cur == NULL) {
547 fprintf(output, shift);
548 fprintf(output, "LocationSet is NULL !\n");
549 return;
550
551 }
552
553 for (i = 0;i < cur->locNr;i++) {
554 fprintf(output, shift);
555 fprintf(output, "%d : ", i + 1);
556 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
557 }
558}
Daniel Veillard017b1082001-06-21 11:20:21 +0000559#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000560
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000561/**
562 * xmlXPathDebugDumpObject:
563 * @output: the FILE * to dump the output
564 * @cur: the object to inspect
565 * @depth: indentation level
566 *
567 * Dump the content of the object for debugging purposes
568 */
569void
570xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000571 int i;
572 char shift[100];
573
574 for (i = 0;((i < depth) && (i < 25));i++)
575 shift[2 * i] = shift[2 * i + 1] = ' ';
576 shift[2 * i] = shift[2 * i + 1] = 0;
577
578 fprintf(output, shift);
579
580 if (cur == NULL) {
581 fprintf(output, "Object is empty (NULL)\n");
582 return;
583 }
584 switch(cur->type) {
585 case XPATH_UNDEFINED:
586 fprintf(output, "Object is uninitialized\n");
587 break;
588 case XPATH_NODESET:
589 fprintf(output, "Object is a Node Set :\n");
590 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
591 break;
592 case XPATH_XSLT_TREE:
593 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000594 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000595 break;
596 case XPATH_BOOLEAN:
597 fprintf(output, "Object is a Boolean : ");
598 if (cur->boolval) fprintf(output, "true\n");
599 else fprintf(output, "false\n");
600 break;
601 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000602 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000603 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000604 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000605 break;
606 case -1:
607 fprintf(output, "Object is a number : -Infinity\n");
608 break;
609 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000610 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000611 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000612 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
613 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000614 } else {
615 fprintf(output, "Object is a number : %0g\n", cur->floatval);
616 }
617 }
Owen Taylor3473f882001-02-23 17:55:21 +0000618 break;
619 case XPATH_STRING:
620 fprintf(output, "Object is a string : ");
621 xmlDebugDumpString(output, cur->stringval);
622 fprintf(output, "\n");
623 break;
624 case XPATH_POINT:
625 fprintf(output, "Object is a point : index %d in node", cur->index);
626 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
627 fprintf(output, "\n");
628 break;
629 case XPATH_RANGE:
630 if ((cur->user2 == NULL) ||
631 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
632 fprintf(output, "Object is a collapsed range :\n");
633 fprintf(output, shift);
634 if (cur->index >= 0)
635 fprintf(output, "index %d in ", cur->index);
636 fprintf(output, "node\n");
637 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
638 depth + 1);
639 } else {
640 fprintf(output, "Object is a range :\n");
641 fprintf(output, shift);
642 fprintf(output, "From ");
643 if (cur->index >= 0)
644 fprintf(output, "index %d in ", cur->index);
645 fprintf(output, "node\n");
646 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
647 depth + 1);
648 fprintf(output, shift);
649 fprintf(output, "To ");
650 if (cur->index2 >= 0)
651 fprintf(output, "index %d in ", cur->index2);
652 fprintf(output, "node\n");
653 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
654 depth + 1);
655 fprintf(output, "\n");
656 }
657 break;
658 case XPATH_LOCATIONSET:
659#if defined(LIBXML_XPTR_ENABLED)
660 fprintf(output, "Object is a Location Set:\n");
661 xmlXPathDebugDumpLocationSet(output,
662 (xmlLocationSetPtr) cur->user, depth);
663#endif
664 break;
665 case XPATH_USERS:
666 fprintf(output, "Object is user defined\n");
667 break;
668 }
669}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000670
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000671static void
672xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000673 xmlXPathStepOpPtr op, int depth) {
674 int i;
675 char shift[100];
676
677 for (i = 0;((i < depth) && (i < 25));i++)
678 shift[2 * i] = shift[2 * i + 1] = ' ';
679 shift[2 * i] = shift[2 * i + 1] = 0;
680
681 fprintf(output, shift);
682 if (op == NULL) {
683 fprintf(output, "Step is NULL\n");
684 return;
685 }
686 switch (op->op) {
687 case XPATH_OP_END:
688 fprintf(output, "END"); break;
689 case XPATH_OP_AND:
690 fprintf(output, "AND"); break;
691 case XPATH_OP_OR:
692 fprintf(output, "OR"); break;
693 case XPATH_OP_EQUAL:
694 if (op->value)
695 fprintf(output, "EQUAL =");
696 else
697 fprintf(output, "EQUAL !=");
698 break;
699 case XPATH_OP_CMP:
700 if (op->value)
701 fprintf(output, "CMP <");
702 else
703 fprintf(output, "CMP >");
704 if (!op->value2)
705 fprintf(output, "=");
706 break;
707 case XPATH_OP_PLUS:
708 if (op->value == 0)
709 fprintf(output, "PLUS -");
710 else if (op->value == 1)
711 fprintf(output, "PLUS +");
712 else if (op->value == 2)
713 fprintf(output, "PLUS unary -");
714 else if (op->value == 3)
715 fprintf(output, "PLUS unary - -");
716 break;
717 case XPATH_OP_MULT:
718 if (op->value == 0)
719 fprintf(output, "MULT *");
720 else if (op->value == 1)
721 fprintf(output, "MULT div");
722 else
723 fprintf(output, "MULT mod");
724 break;
725 case XPATH_OP_UNION:
726 fprintf(output, "UNION"); break;
727 case XPATH_OP_ROOT:
728 fprintf(output, "ROOT"); break;
729 case XPATH_OP_NODE:
730 fprintf(output, "NODE"); break;
731 case XPATH_OP_RESET:
732 fprintf(output, "RESET"); break;
733 case XPATH_OP_SORT:
734 fprintf(output, "SORT"); break;
735 case XPATH_OP_COLLECT: {
736 xmlXPathAxisVal axis = op->value;
737 xmlXPathTestVal test = op->value2;
738 xmlXPathTypeVal type = op->value3;
739 const xmlChar *prefix = op->value4;
740 const xmlChar *name = op->value5;
741
742 fprintf(output, "COLLECT ");
743 switch (axis) {
744 case AXIS_ANCESTOR:
745 fprintf(output, " 'ancestors' "); break;
746 case AXIS_ANCESTOR_OR_SELF:
747 fprintf(output, " 'ancestors-or-self' "); break;
748 case AXIS_ATTRIBUTE:
749 fprintf(output, " 'attributes' "); break;
750 case AXIS_CHILD:
751 fprintf(output, " 'child' "); break;
752 case AXIS_DESCENDANT:
753 fprintf(output, " 'descendant' "); break;
754 case AXIS_DESCENDANT_OR_SELF:
755 fprintf(output, " 'descendant-or-self' "); break;
756 case AXIS_FOLLOWING:
757 fprintf(output, " 'following' "); break;
758 case AXIS_FOLLOWING_SIBLING:
759 fprintf(output, " 'following-siblings' "); break;
760 case AXIS_NAMESPACE:
761 fprintf(output, " 'namespace' "); break;
762 case AXIS_PARENT:
763 fprintf(output, " 'parent' "); break;
764 case AXIS_PRECEDING:
765 fprintf(output, " 'preceding' "); break;
766 case AXIS_PRECEDING_SIBLING:
767 fprintf(output, " 'preceding-sibling' "); break;
768 case AXIS_SELF:
769 fprintf(output, " 'self' "); break;
770 }
771 switch (test) {
772 case NODE_TEST_NONE:
773 fprintf(output, "'none' "); break;
774 case NODE_TEST_TYPE:
775 fprintf(output, "'type' "); break;
776 case NODE_TEST_PI:
777 fprintf(output, "'PI' "); break;
778 case NODE_TEST_ALL:
779 fprintf(output, "'all' "); break;
780 case NODE_TEST_NS:
781 fprintf(output, "'namespace' "); break;
782 case NODE_TEST_NAME:
783 fprintf(output, "'name' "); break;
784 }
785 switch (type) {
786 case NODE_TYPE_NODE:
787 fprintf(output, "'node' "); break;
788 case NODE_TYPE_COMMENT:
789 fprintf(output, "'comment' "); break;
790 case NODE_TYPE_TEXT:
791 fprintf(output, "'text' "); break;
792 case NODE_TYPE_PI:
793 fprintf(output, "'PI' "); break;
794 }
795 if (prefix != NULL)
796 fprintf(output, "%s:", prefix);
797 if (name != NULL)
798 fprintf(output, "%s", name);
799 break;
800
801 }
802 case XPATH_OP_VALUE: {
803 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
804
805 fprintf(output, "ELEM ");
806 xmlXPathDebugDumpObject(output, object, 0);
807 goto finish;
808 }
809 case XPATH_OP_VARIABLE: {
810 const xmlChar *prefix = op->value5;
811 const xmlChar *name = op->value4;
812
813 if (prefix != NULL)
814 fprintf(output, "VARIABLE %s:%s", prefix, name);
815 else
816 fprintf(output, "VARIABLE %s", name);
817 break;
818 }
819 case XPATH_OP_FUNCTION: {
820 int nbargs = op->value;
821 const xmlChar *prefix = op->value5;
822 const xmlChar *name = op->value4;
823
824 if (prefix != NULL)
825 fprintf(output, "FUNCTION %s:%s(%d args)",
826 prefix, name, nbargs);
827 else
828 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
829 break;
830 }
831 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
832 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000833 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000834#ifdef LIBXML_XPTR_ENABLED
835 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
836#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000837 default:
838 fprintf(output, "UNKNOWN %d\n", op->op); return;
839 }
840 fprintf(output, "\n");
841finish:
842 if (op->ch1 >= 0)
843 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
844 if (op->ch2 >= 0)
845 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
846}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000847
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000848/**
849 * xmlXPathDebugDumpCompExpr:
850 * @output: the FILE * for the output
851 * @comp: the precompiled XPath expression
852 * @depth: the indentation level.
853 *
854 * Dumps the tree of the compiled XPath expression.
855 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000856void
857xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
858 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000859 int i;
860 char shift[100];
861
862 for (i = 0;((i < depth) && (i < 25));i++)
863 shift[2 * i] = shift[2 * i + 1] = ' ';
864 shift[2 * i] = shift[2 * i + 1] = 0;
865
866 fprintf(output, shift);
867
868 if (comp == NULL) {
869 fprintf(output, "Compiled Expression is NULL\n");
870 return;
871 }
872 fprintf(output, "Compiled Expression : %d elements\n",
873 comp->nbStep);
874 i = comp->last;
875 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
876}
Daniel Veillard017b1082001-06-21 11:20:21 +0000877#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000878
879/************************************************************************
880 * *
881 * Parser stacks related functions and macros *
882 * *
883 ************************************************************************/
884
885/*
886 * Generic function for accessing stacks in the Parser Context
887 */
888
889#define PUSH_AND_POP(type, name) \
890extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
891 if (ctxt->name##Nr >= ctxt->name##Max) { \
892 ctxt->name##Max *= 2; \
893 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
894 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
895 if (ctxt->name##Tab == NULL) { \
896 xmlGenericError(xmlGenericErrorContext, \
897 "realloc failed !\n"); \
898 return(0); \
899 } \
900 } \
901 ctxt->name##Tab[ctxt->name##Nr] = value; \
902 ctxt->name = value; \
903 return(ctxt->name##Nr++); \
904} \
905extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
906 type ret; \
907 if (ctxt->name##Nr <= 0) return(0); \
908 ctxt->name##Nr--; \
909 if (ctxt->name##Nr > 0) \
910 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
911 else \
912 ctxt->name = NULL; \
913 ret = ctxt->name##Tab[ctxt->name##Nr]; \
914 ctxt->name##Tab[ctxt->name##Nr] = 0; \
915 return(ret); \
916} \
917
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000918/**
919 * valuePop:
920 * @ctxt: an XPath evaluation context
921 *
922 * Pops the top XPath object from the value stack
923 *
924 * Returns the XPath object just removed
925 */
926/**
927 * valuePush:
928 * @ctxt: an XPath evaluation context
929 * @value: the XPath object
930 *
931 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000932 *
933 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000934 */
Owen Taylor3473f882001-02-23 17:55:21 +0000935PUSH_AND_POP(xmlXPathObjectPtr, value)
936
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000937/**
938 * xmlXPathPopBoolean:
939 * @ctxt: an XPath parser context
940 *
941 * Pops a boolean from the stack, handling conversion if needed.
942 * Check error with #xmlXPathCheckError.
943 *
944 * Returns the boolean
945 */
946int
947xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
948 xmlXPathObjectPtr obj;
949 int ret;
950
951 obj = valuePop(ctxt);
952 if (obj == NULL) {
953 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
954 return(0);
955 }
956 ret = xmlXPathCastToBoolean(obj);
957 xmlXPathFreeObject(obj);
958 return(ret);
959}
960
961/**
962 * xmlXPathPopNumber:
963 * @ctxt: an XPath parser context
964 *
965 * Pops a number from the stack, handling conversion if needed.
966 * Check error with #xmlXPathCheckError.
967 *
968 * Returns the number
969 */
970double
971xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
972 xmlXPathObjectPtr obj;
973 double ret;
974
975 obj = valuePop(ctxt);
976 if (obj == NULL) {
977 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
978 return(0);
979 }
980 ret = xmlXPathCastToNumber(obj);
981 xmlXPathFreeObject(obj);
982 return(ret);
983}
984
985/**
986 * xmlXPathPopString:
987 * @ctxt: an XPath parser context
988 *
989 * Pops a string from the stack, handling conversion if needed.
990 * Check error with #xmlXPathCheckError.
991 *
992 * Returns the string
993 */
994xmlChar *
995xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
996 xmlXPathObjectPtr obj;
997 xmlChar * ret;
998
999 obj = valuePop(ctxt);
1000 if (obj == NULL) {
1001 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1002 return(NULL);
1003 }
1004 ret = xmlXPathCastToString(obj);
1005 /* TODO: needs refactoring somewhere else */
1006 if (obj->stringval == ret)
1007 obj->stringval = NULL;
1008 xmlXPathFreeObject(obj);
1009 return(ret);
1010}
1011
1012/**
1013 * xmlXPathPopNodeSet:
1014 * @ctxt: an XPath parser context
1015 *
1016 * Pops a node-set from the stack, handling conversion if needed.
1017 * Check error with #xmlXPathCheckError.
1018 *
1019 * Returns the node-set
1020 */
1021xmlNodeSetPtr
1022xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1023 xmlXPathObjectPtr obj;
1024 xmlNodeSetPtr ret;
1025
1026 if (ctxt->value == NULL) {
1027 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1028 return(NULL);
1029 }
1030 if (!xmlXPathStackIsNodeSet(ctxt)) {
1031 xmlXPathSetTypeError(ctxt);
1032 return(NULL);
1033 }
1034 obj = valuePop(ctxt);
1035 ret = obj->nodesetval;
1036 xmlXPathFreeNodeSetList(obj);
1037 return(ret);
1038}
1039
1040/**
1041 * xmlXPathPopExternal:
1042 * @ctxt: an XPath parser context
1043 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001044 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001045 * Check error with #xmlXPathCheckError.
1046 *
1047 * Returns the object
1048 */
1049void *
1050xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1051 xmlXPathObjectPtr obj;
1052 void * ret;
1053
1054 if (ctxt->value == NULL) {
1055 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1056 return(NULL);
1057 }
1058 if (ctxt->value->type != XPATH_USERS) {
1059 xmlXPathSetTypeError(ctxt);
1060 return(NULL);
1061 }
1062 obj = valuePop(ctxt);
1063 ret = obj->user;
1064 xmlXPathFreeObject(obj);
1065 return(ret);
1066}
1067
Owen Taylor3473f882001-02-23 17:55:21 +00001068/*
1069 * Macros for accessing the content. Those should be used only by the parser,
1070 * and not exported.
1071 *
1072 * Dirty macros, i.e. one need to make assumption on the context to use them
1073 *
1074 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1075 * CUR returns the current xmlChar value, i.e. a 8 bit value
1076 * in ISO-Latin or UTF-8.
1077 * This should be used internally by the parser
1078 * only to compare to ASCII values otherwise it would break when
1079 * running with UTF-8 encoding.
1080 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1081 * to compare on ASCII based substring.
1082 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1083 * strings within the parser.
1084 * CURRENT Returns the current char value, with the full decoding of
1085 * UTF-8 if we are using this mode. It returns an int.
1086 * NEXT Skip to the next character, this does the proper decoding
1087 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1088 * It returns the pointer to the current xmlChar.
1089 */
1090
1091#define CUR (*ctxt->cur)
1092#define SKIP(val) ctxt->cur += (val)
1093#define NXT(val) ctxt->cur[(val)]
1094#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001095#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1096
1097#define COPY_BUF(l,b,i,v) \
1098 if (l == 1) b[i++] = (xmlChar) v; \
1099 else i += xmlCopyChar(l,&b[i],v)
1100
1101#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001102
1103#define SKIP_BLANKS \
1104 while (IS_BLANK(*(ctxt->cur))) NEXT
1105
1106#define CURRENT (*ctxt->cur)
1107#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1108
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001109
1110#ifndef DBL_DIG
1111#define DBL_DIG 16
1112#endif
1113#ifndef DBL_EPSILON
1114#define DBL_EPSILON 1E-9
1115#endif
1116
1117#define UPPER_DOUBLE 1E9
1118#define LOWER_DOUBLE 1E-5
1119
1120#define INTEGER_DIGITS DBL_DIG
1121#define FRACTION_DIGITS (DBL_DIG + 1)
1122#define EXPONENT_DIGITS (3 + 2)
1123
1124/**
1125 * xmlXPathFormatNumber:
1126 * @number: number to format
1127 * @buffer: output buffer
1128 * @buffersize: size of output buffer
1129 *
1130 * Convert the number into a string representation.
1131 */
1132static void
1133xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1134{
Daniel Veillardcda96922001-08-21 10:56:31 +00001135 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001136 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001137 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001138 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001139 break;
1140 case -1:
1141 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001142 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001143 break;
1144 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001145 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001146 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001147 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001148 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001149 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001150 } else if (number == ((int) number)) {
1151 char work[30];
1152 char *ptr, *cur;
1153 int res, value = (int) number;
1154
1155 ptr = &buffer[0];
1156 if (value < 0) {
1157 *ptr++ = '-';
1158 value = -value;
1159 }
1160 if (value == 0) {
1161 *ptr++ = '0';
1162 } else {
1163 cur = &work[0];
1164 while (value != 0) {
1165 res = value % 10;
1166 value = value / 10;
1167 *cur++ = '0' + res;
1168 }
1169 cur--;
1170 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1171 *ptr++ = *cur--;
1172 }
1173 }
1174 if (ptr - buffer < buffersize) {
1175 *ptr = 0;
1176 } else if (buffersize > 0) {
1177 ptr--;
1178 *ptr = 0;
1179 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001180 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001181 /* 3 is sign, decimal point, and terminating zero */
1182 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1183 int integer_place, fraction_place;
1184 char *ptr;
1185 char *after_fraction;
1186 double absolute_value;
1187 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001188
Bjorn Reese70a9da52001-04-21 16:57:29 +00001189 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001190
Bjorn Reese70a9da52001-04-21 16:57:29 +00001191 /*
1192 * First choose format - scientific or regular floating point.
1193 * In either case, result is in work, and after_fraction points
1194 * just past the fractional part.
1195 */
1196 if ( ((absolute_value > UPPER_DOUBLE) ||
1197 (absolute_value < LOWER_DOUBLE)) &&
1198 (absolute_value != 0.0) ) {
1199 /* Use scientific notation */
1200 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1201 fraction_place = DBL_DIG - 1;
1202 snprintf(work, sizeof(work),"%*.*e",
1203 integer_place, fraction_place, number);
1204 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001205 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001206 else {
1207 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001208 if (absolute_value > 0.0)
1209 integer_place = 1 + (int)log10(absolute_value);
1210 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001211 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001212 fraction_place = (integer_place > 0)
1213 ? DBL_DIG - integer_place
1214 : DBL_DIG;
1215 size = snprintf(work, sizeof(work), "%0.*f",
1216 fraction_place, number);
1217 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001218 }
1219
Bjorn Reese70a9da52001-04-21 16:57:29 +00001220 /* Remove fractional trailing zeroes */
1221 ptr = after_fraction;
1222 while (*(--ptr) == '0')
1223 ;
1224 if (*ptr != '.')
1225 ptr++;
1226 strcpy(ptr, after_fraction);
1227
1228 /* Finally copy result back to caller */
1229 size = strlen(work) + 1;
1230 if (size > buffersize) {
1231 work[buffersize - 1] = 0;
1232 size = buffersize;
1233 }
1234 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001235 }
1236 break;
1237 }
1238}
1239
Owen Taylor3473f882001-02-23 17:55:21 +00001240/************************************************************************
1241 * *
1242 * Error handling routines *
1243 * *
1244 ************************************************************************/
1245
1246
Daniel Veillardb44025c2001-10-11 22:55:55 +00001247static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001248 "Ok",
1249 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001250 "Unfinished literal",
1251 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001252 "Expected $ for variable reference",
1253 "Undefined variable",
1254 "Invalid predicate",
1255 "Invalid expression",
1256 "Missing closing curly brace",
1257 "Unregistered function",
1258 "Invalid operand",
1259 "Invalid type",
1260 "Invalid number of arguments",
1261 "Invalid context size",
1262 "Invalid context position",
1263 "Memory allocation error",
1264 "Syntax error",
1265 "Resource error",
1266 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001267 "Undefined namespace prefix",
1268 "Encoding error",
1269 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001270};
1271
1272/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001273 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001274 * @ctxt: the XPath Parser context
1275 * @file: the file name
1276 * @line: the line number
1277 * @no: the error number
1278 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001279 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001280 */
1281void
Daniel Veillard21458c82002-03-27 16:12:22 +00001282xmlXPatherror(xmlXPathParserContextPtr ctxt, ATTRIBUTE_UNUSED const char *file,
1283 ATTRIBUTE_UNUSED int line, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001284 int n;
1285 const xmlChar *cur;
1286 const xmlChar *base;
1287
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001288/* xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00001289 "Error %s:%d: %s\n", file, line,
1290 xmlXPathErrorMessages[no]);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001291*/
1292 xmlGenericError(xmlGenericErrorContext,
1293 "Error %s\n", xmlXPathErrorMessages[no]);
Owen Taylor3473f882001-02-23 17:55:21 +00001294
1295 cur = ctxt->cur;
1296 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001297 if ((cur == NULL) || (base == NULL))
1298 return;
1299
Owen Taylor3473f882001-02-23 17:55:21 +00001300 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1301 cur--;
1302 }
1303 n = 0;
1304 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1305 cur--;
1306 if ((*cur == '\n') || (*cur == '\r')) cur++;
1307 base = cur;
1308 n = 0;
1309 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1310 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1311 n++;
1312 }
1313 xmlGenericError(xmlGenericErrorContext, "\n");
1314 cur = ctxt->cur;
1315 while ((*cur == '\n') || (*cur == '\r'))
1316 cur--;
1317 n = 0;
1318 while ((cur != base) && (n++ < 80)) {
1319 xmlGenericError(xmlGenericErrorContext, " ");
1320 base++;
1321 }
1322 xmlGenericError(xmlGenericErrorContext,"^\n");
1323}
1324
1325
1326/************************************************************************
1327 * *
1328 * Routines to handle NodeSets *
1329 * *
1330 ************************************************************************/
1331
1332/**
1333 * xmlXPathCmpNodes:
1334 * @node1: the first node
1335 * @node2: the second node
1336 *
1337 * Compare two nodes w.r.t document order
1338 *
1339 * Returns -2 in case of error 1 if first point < second point, 0 if
1340 * that's the same node, -1 otherwise
1341 */
1342int
1343xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1344 int depth1, depth2;
1345 xmlNodePtr cur, root;
1346
1347 if ((node1 == NULL) || (node2 == NULL))
1348 return(-2);
1349 /*
1350 * a couple of optimizations which will avoid computations in most cases
1351 */
1352 if (node1 == node2)
1353 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001354 if ((node1->type == XML_NAMESPACE_DECL) ||
1355 (node2->type == XML_NAMESPACE_DECL))
1356 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001357 if (node1 == node2->prev)
1358 return(1);
1359 if (node1 == node2->next)
1360 return(-1);
1361
1362 /*
1363 * compute depth to root
1364 */
1365 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1366 if (cur == node1)
1367 return(1);
1368 depth2++;
1369 }
1370 root = cur;
1371 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1372 if (cur == node2)
1373 return(-1);
1374 depth1++;
1375 }
1376 /*
1377 * Distinct document (or distinct entities :-( ) case.
1378 */
1379 if (root != cur) {
1380 return(-2);
1381 }
1382 /*
1383 * get the nearest common ancestor.
1384 */
1385 while (depth1 > depth2) {
1386 depth1--;
1387 node1 = node1->parent;
1388 }
1389 while (depth2 > depth1) {
1390 depth2--;
1391 node2 = node2->parent;
1392 }
1393 while (node1->parent != node2->parent) {
1394 node1 = node1->parent;
1395 node2 = node2->parent;
1396 /* should not happen but just in case ... */
1397 if ((node1 == NULL) || (node2 == NULL))
1398 return(-2);
1399 }
1400 /*
1401 * Find who's first.
1402 */
1403 if (node1 == node2->next)
1404 return(-1);
1405 for (cur = node1->next;cur != NULL;cur = cur->next)
1406 if (cur == node2)
1407 return(1);
1408 return(-1); /* assume there is no sibling list corruption */
1409}
1410
1411/**
1412 * xmlXPathNodeSetSort:
1413 * @set: the node set
1414 *
1415 * Sort the node set in document order
1416 */
1417void
1418xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001419 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001420 xmlNodePtr tmp;
1421
1422 if (set == NULL)
1423 return;
1424
1425 /* Use Shell's sort to sort the node-set */
1426 len = set->nodeNr;
1427 for (incr = len / 2; incr > 0; incr /= 2) {
1428 for (i = incr; i < len; i++) {
1429 j = i - incr;
1430 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001431 if (xmlXPathCmpNodes(set->nodeTab[j],
1432 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001433 tmp = set->nodeTab[j];
1434 set->nodeTab[j] = set->nodeTab[j + incr];
1435 set->nodeTab[j + incr] = tmp;
1436 j -= incr;
1437 } else
1438 break;
1439 }
1440 }
1441 }
1442}
1443
1444#define XML_NODESET_DEFAULT 10
1445/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001446 * xmlXPathNodeSetDupNs:
1447 * @node: the parent node of the namespace XPath node
1448 * @ns: the libxml namespace declaration node.
1449 *
1450 * Namespace node in libxml don't match the XPath semantic. In a node set
1451 * the namespace nodes are duplicated and the next pointer is set to the
1452 * parent node in the XPath semantic.
1453 *
1454 * Returns the newly created object.
1455 */
1456static xmlNodePtr
1457xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1458 xmlNsPtr cur;
1459
1460 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1461 return(NULL);
1462 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1463 return((xmlNodePtr) ns);
1464
1465 /*
1466 * Allocate a new Namespace and fill the fields.
1467 */
1468 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1469 if (cur == NULL) {
1470 xmlGenericError(xmlGenericErrorContext,
1471 "xmlXPathNodeSetDupNs : malloc failed\n");
1472 return(NULL);
1473 }
1474 memset(cur, 0, sizeof(xmlNs));
1475 cur->type = XML_NAMESPACE_DECL;
1476 if (ns->href != NULL)
1477 cur->href = xmlStrdup(ns->href);
1478 if (ns->prefix != NULL)
1479 cur->prefix = xmlStrdup(ns->prefix);
1480 cur->next = (xmlNsPtr) node;
1481 return((xmlNodePtr) cur);
1482}
1483
1484/**
1485 * xmlXPathNodeSetFreeNs:
1486 * @ns: the XPath namespace node found in a nodeset.
1487 *
1488 * Namespace node in libxml don't match the XPath semantic. In a node set
1489 * the namespace nodes are duplicated and the next pointer is set to the
1490 * parent node in the XPath semantic. Check if such a node need to be freed
1491 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001492void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001493xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1494 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1495 return;
1496
1497 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1498 if (ns->href != NULL)
1499 xmlFree((xmlChar *)ns->href);
1500 if (ns->prefix != NULL)
1501 xmlFree((xmlChar *)ns->prefix);
1502 xmlFree(ns);
1503 }
1504}
1505
1506/**
Owen Taylor3473f882001-02-23 17:55:21 +00001507 * xmlXPathNodeSetCreate:
1508 * @val: an initial xmlNodePtr, or NULL
1509 *
1510 * Create a new xmlNodeSetPtr of type double and of value @val
1511 *
1512 * Returns the newly created object.
1513 */
1514xmlNodeSetPtr
1515xmlXPathNodeSetCreate(xmlNodePtr val) {
1516 xmlNodeSetPtr ret;
1517
1518 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1519 if (ret == NULL) {
1520 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001521 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001522 return(NULL);
1523 }
1524 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1525 if (val != NULL) {
1526 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1527 sizeof(xmlNodePtr));
1528 if (ret->nodeTab == NULL) {
1529 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001530 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001531 return(NULL);
1532 }
1533 memset(ret->nodeTab, 0 ,
1534 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1535 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001536 if (val->type == XML_NAMESPACE_DECL) {
1537 xmlNsPtr ns = (xmlNsPtr) val;
1538
1539 ret->nodeTab[ret->nodeNr++] =
1540 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1541 } else
1542 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001543 }
1544 return(ret);
1545}
1546
1547/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001548 * xmlXPathNodeSetContains:
1549 * @cur: the node-set
1550 * @val: the node
1551 *
1552 * checks whether @cur contains @val
1553 *
1554 * Returns true (1) if @cur contains @val, false (0) otherwise
1555 */
1556int
1557xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1558 int i;
1559
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001560 if (val->type == XML_NAMESPACE_DECL) {
1561 for (i = 0; i < cur->nodeNr; i++) {
1562 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1563 xmlNsPtr ns1, ns2;
1564
1565 ns1 = (xmlNsPtr) val;
1566 ns2 = (xmlNsPtr) cur->nodeTab[i];
1567 if (ns1 == ns2)
1568 return(1);
1569 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1570 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1571 return(1);
1572 }
1573 }
1574 } else {
1575 for (i = 0; i < cur->nodeNr; i++) {
1576 if (cur->nodeTab[i] == val)
1577 return(1);
1578 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001579 }
1580 return(0);
1581}
1582
1583/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001584 * xmlXPathNodeSetAddNs:
1585 * @cur: the initial node set
1586 * @node: the hosting node
1587 * @ns: a the namespace node
1588 *
1589 * add a new namespace node to an existing NodeSet
1590 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001591void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001592xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1593 int i;
1594
1595 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1596 (node->type != XML_ELEMENT_NODE))
1597 return;
1598
1599 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1600 /*
1601 * check against doublons
1602 */
1603 for (i = 0;i < cur->nodeNr;i++) {
1604 if ((cur->nodeTab[i] != NULL) &&
1605 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001606 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001607 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1608 return;
1609 }
1610
1611 /*
1612 * grow the nodeTab if needed
1613 */
1614 if (cur->nodeMax == 0) {
1615 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1616 sizeof(xmlNodePtr));
1617 if (cur->nodeTab == NULL) {
1618 xmlGenericError(xmlGenericErrorContext,
1619 "xmlXPathNodeSetAdd: out of memory\n");
1620 return;
1621 }
1622 memset(cur->nodeTab, 0 ,
1623 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1624 cur->nodeMax = XML_NODESET_DEFAULT;
1625 } else if (cur->nodeNr == cur->nodeMax) {
1626 xmlNodePtr *temp;
1627
1628 cur->nodeMax *= 2;
1629 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1630 sizeof(xmlNodePtr));
1631 if (temp == NULL) {
1632 xmlGenericError(xmlGenericErrorContext,
1633 "xmlXPathNodeSetAdd: out of memory\n");
1634 return;
1635 }
1636 cur->nodeTab = temp;
1637 }
1638 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1639}
1640
1641/**
Owen Taylor3473f882001-02-23 17:55:21 +00001642 * xmlXPathNodeSetAdd:
1643 * @cur: the initial node set
1644 * @val: a new xmlNodePtr
1645 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001646 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001647 */
1648void
1649xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1650 int i;
1651
1652 if (val == NULL) return;
1653
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001654 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001655 /*
1656 * check against doublons
1657 */
1658 for (i = 0;i < cur->nodeNr;i++)
1659 if (cur->nodeTab[i] == val) return;
1660
1661 /*
1662 * grow the nodeTab if needed
1663 */
1664 if (cur->nodeMax == 0) {
1665 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1666 sizeof(xmlNodePtr));
1667 if (cur->nodeTab == NULL) {
1668 xmlGenericError(xmlGenericErrorContext,
1669 "xmlXPathNodeSetAdd: out of memory\n");
1670 return;
1671 }
1672 memset(cur->nodeTab, 0 ,
1673 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1674 cur->nodeMax = XML_NODESET_DEFAULT;
1675 } else if (cur->nodeNr == cur->nodeMax) {
1676 xmlNodePtr *temp;
1677
1678 cur->nodeMax *= 2;
1679 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1680 sizeof(xmlNodePtr));
1681 if (temp == NULL) {
1682 xmlGenericError(xmlGenericErrorContext,
1683 "xmlXPathNodeSetAdd: out of memory\n");
1684 return;
1685 }
1686 cur->nodeTab = temp;
1687 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001688 if (val->type == XML_NAMESPACE_DECL) {
1689 xmlNsPtr ns = (xmlNsPtr) val;
1690
1691 cur->nodeTab[cur->nodeNr++] =
1692 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1693 } else
1694 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001695}
1696
1697/**
1698 * xmlXPathNodeSetAddUnique:
1699 * @cur: the initial node set
1700 * @val: a new xmlNodePtr
1701 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001702 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001703 * when we are sure the node is not already in the set.
1704 */
1705void
1706xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1707 if (val == NULL) return;
1708
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001709 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001710 /*
1711 * grow the nodeTab if needed
1712 */
1713 if (cur->nodeMax == 0) {
1714 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1715 sizeof(xmlNodePtr));
1716 if (cur->nodeTab == NULL) {
1717 xmlGenericError(xmlGenericErrorContext,
1718 "xmlXPathNodeSetAddUnique: out of memory\n");
1719 return;
1720 }
1721 memset(cur->nodeTab, 0 ,
1722 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1723 cur->nodeMax = XML_NODESET_DEFAULT;
1724 } else if (cur->nodeNr == cur->nodeMax) {
1725 xmlNodePtr *temp;
1726
1727 cur->nodeMax *= 2;
1728 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1729 sizeof(xmlNodePtr));
1730 if (temp == NULL) {
1731 xmlGenericError(xmlGenericErrorContext,
1732 "xmlXPathNodeSetAddUnique: out of memory\n");
1733 return;
1734 }
1735 cur->nodeTab = temp;
1736 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001737 if (val->type == XML_NAMESPACE_DECL) {
1738 xmlNsPtr ns = (xmlNsPtr) val;
1739
1740 cur->nodeTab[cur->nodeNr++] =
1741 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1742 } else
1743 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001744}
1745
1746/**
1747 * xmlXPathNodeSetMerge:
1748 * @val1: the first NodeSet or NULL
1749 * @val2: the second NodeSet
1750 *
1751 * Merges two nodesets, all nodes from @val2 are added to @val1
1752 * if @val1 is NULL, a new set is created and copied from @val2
1753 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001754 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001755 */
1756xmlNodeSetPtr
1757xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001758 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001759
1760 if (val2 == NULL) return(val1);
1761 if (val1 == NULL) {
1762 val1 = xmlXPathNodeSetCreate(NULL);
1763 }
1764
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001765 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001766 initNr = val1->nodeNr;
1767
1768 for (i = 0;i < val2->nodeNr;i++) {
1769 /*
1770 * check against doublons
1771 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001772 skip = 0;
1773 for (j = 0; j < initNr; j++) {
1774 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1775 skip = 1;
1776 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001777 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1778 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1779 xmlNsPtr ns1, ns2;
1780 ns1 = (xmlNsPtr) val1->nodeTab[j];
1781 ns2 = (xmlNsPtr) val2->nodeTab[i];
1782 if ((ns1->next == ns2->next) &&
1783 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1784 skip = 1;
1785 break;
1786 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001787 }
1788 }
1789 if (skip)
1790 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001791
1792 /*
1793 * grow the nodeTab if needed
1794 */
1795 if (val1->nodeMax == 0) {
1796 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1797 sizeof(xmlNodePtr));
1798 if (val1->nodeTab == NULL) {
1799 xmlGenericError(xmlGenericErrorContext,
1800 "xmlXPathNodeSetMerge: out of memory\n");
1801 return(NULL);
1802 }
1803 memset(val1->nodeTab, 0 ,
1804 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1805 val1->nodeMax = XML_NODESET_DEFAULT;
1806 } else if (val1->nodeNr == val1->nodeMax) {
1807 xmlNodePtr *temp;
1808
1809 val1->nodeMax *= 2;
1810 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1811 sizeof(xmlNodePtr));
1812 if (temp == NULL) {
1813 xmlGenericError(xmlGenericErrorContext,
1814 "xmlXPathNodeSetMerge: out of memory\n");
1815 return(NULL);
1816 }
1817 val1->nodeTab = temp;
1818 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001819 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1820 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1821
1822 val1->nodeTab[val1->nodeNr++] =
1823 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1824 } else
1825 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001826 }
1827
1828 return(val1);
1829}
1830
1831/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001832 * xmlXPathNodeSetMergeUnique:
1833 * @val1: the first NodeSet or NULL
1834 * @val2: the second NodeSet
1835 *
1836 * Merges two nodesets, all nodes from @val2 are added to @val1
1837 * if @val1 is NULL, a new set is created and copied from @val2
1838 *
1839 * Returns @val1 once extended or NULL in case of error.
1840 */
1841static xmlNodeSetPtr
1842xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1843 int i, initNr;
1844
1845 if (val2 == NULL) return(val1);
1846 if (val1 == NULL) {
1847 val1 = xmlXPathNodeSetCreate(NULL);
1848 }
1849
1850 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1851 initNr = val1->nodeNr;
1852
1853 for (i = 0;i < val2->nodeNr;i++) {
1854 /*
1855 * grow the nodeTab if needed
1856 */
1857 if (val1->nodeMax == 0) {
1858 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1859 sizeof(xmlNodePtr));
1860 if (val1->nodeTab == NULL) {
1861 xmlGenericError(xmlGenericErrorContext,
1862 "xmlXPathNodeSetMerge: out of memory\n");
1863 return(NULL);
1864 }
1865 memset(val1->nodeTab, 0 ,
1866 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1867 val1->nodeMax = XML_NODESET_DEFAULT;
1868 } else if (val1->nodeNr == val1->nodeMax) {
1869 xmlNodePtr *temp;
1870
1871 val1->nodeMax *= 2;
1872 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1873 sizeof(xmlNodePtr));
1874 if (temp == NULL) {
1875 xmlGenericError(xmlGenericErrorContext,
1876 "xmlXPathNodeSetMerge: out of memory\n");
1877 return(NULL);
1878 }
1879 val1->nodeTab = temp;
1880 }
1881 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1882 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1883
1884 val1->nodeTab[val1->nodeNr++] =
1885 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1886 } else
1887 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1888 }
1889
1890 return(val1);
1891}
1892
1893/**
Owen Taylor3473f882001-02-23 17:55:21 +00001894 * xmlXPathNodeSetDel:
1895 * @cur: the initial node set
1896 * @val: an xmlNodePtr
1897 *
1898 * Removes an xmlNodePtr from an existing NodeSet
1899 */
1900void
1901xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1902 int i;
1903
1904 if (cur == NULL) return;
1905 if (val == NULL) return;
1906
1907 /*
1908 * check against doublons
1909 */
1910 for (i = 0;i < cur->nodeNr;i++)
1911 if (cur->nodeTab[i] == val) break;
1912
1913 if (i >= cur->nodeNr) {
1914#ifdef DEBUG
1915 xmlGenericError(xmlGenericErrorContext,
1916 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1917 val->name);
1918#endif
1919 return;
1920 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001921 if ((cur->nodeTab[i] != NULL) &&
1922 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1923 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001924 cur->nodeNr--;
1925 for (;i < cur->nodeNr;i++)
1926 cur->nodeTab[i] = cur->nodeTab[i + 1];
1927 cur->nodeTab[cur->nodeNr] = NULL;
1928}
1929
1930/**
1931 * xmlXPathNodeSetRemove:
1932 * @cur: the initial node set
1933 * @val: the index to remove
1934 *
1935 * Removes an entry from an existing NodeSet list.
1936 */
1937void
1938xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1939 if (cur == NULL) return;
1940 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001941 if ((cur->nodeTab[val] != NULL) &&
1942 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1943 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001944 cur->nodeNr--;
1945 for (;val < cur->nodeNr;val++)
1946 cur->nodeTab[val] = cur->nodeTab[val + 1];
1947 cur->nodeTab[cur->nodeNr] = NULL;
1948}
1949
1950/**
1951 * xmlXPathFreeNodeSet:
1952 * @obj: the xmlNodeSetPtr to free
1953 *
1954 * Free the NodeSet compound (not the actual nodes !).
1955 */
1956void
1957xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1958 if (obj == NULL) return;
1959 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001960 int i;
1961
1962 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1963 for (i = 0;i < obj->nodeNr;i++)
1964 if ((obj->nodeTab[i] != NULL) &&
1965 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1966 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001967 xmlFree(obj->nodeTab);
1968 }
Owen Taylor3473f882001-02-23 17:55:21 +00001969 xmlFree(obj);
1970}
1971
1972/**
1973 * xmlXPathFreeValueTree:
1974 * @obj: the xmlNodeSetPtr to free
1975 *
1976 * Free the NodeSet compound and the actual tree, this is different
1977 * from xmlXPathFreeNodeSet()
1978 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001979static void
Owen Taylor3473f882001-02-23 17:55:21 +00001980xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1981 int i;
1982
1983 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001984
1985 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001986 for (i = 0;i < obj->nodeNr;i++) {
1987 if (obj->nodeTab[i] != NULL) {
1988 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1989 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
1990 } else {
1991 xmlFreeNodeList(obj->nodeTab[i]);
1992 }
1993 }
1994 }
Owen Taylor3473f882001-02-23 17:55:21 +00001995 xmlFree(obj->nodeTab);
1996 }
Owen Taylor3473f882001-02-23 17:55:21 +00001997 xmlFree(obj);
1998}
1999
2000#if defined(DEBUG) || defined(DEBUG_STEP)
2001/**
2002 * xmlGenericErrorContextNodeSet:
2003 * @output: a FILE * for the output
2004 * @obj: the xmlNodeSetPtr to free
2005 *
2006 * Quick display of a NodeSet
2007 */
2008void
2009xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2010 int i;
2011
2012 if (output == NULL) output = xmlGenericErrorContext;
2013 if (obj == NULL) {
2014 fprintf(output, "NodeSet == NULL !\n");
2015 return;
2016 }
2017 if (obj->nodeNr == 0) {
2018 fprintf(output, "NodeSet is empty\n");
2019 return;
2020 }
2021 if (obj->nodeTab == NULL) {
2022 fprintf(output, " nodeTab == NULL !\n");
2023 return;
2024 }
2025 for (i = 0; i < obj->nodeNr; i++) {
2026 if (obj->nodeTab[i] == NULL) {
2027 fprintf(output, " NULL !\n");
2028 return;
2029 }
2030 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2031 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2032 fprintf(output, " /");
2033 else if (obj->nodeTab[i]->name == NULL)
2034 fprintf(output, " noname!");
2035 else fprintf(output, " %s", obj->nodeTab[i]->name);
2036 }
2037 fprintf(output, "\n");
2038}
2039#endif
2040
2041/**
2042 * xmlXPathNewNodeSet:
2043 * @val: the NodePtr value
2044 *
2045 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2046 * it with the single Node @val
2047 *
2048 * Returns the newly created object.
2049 */
2050xmlXPathObjectPtr
2051xmlXPathNewNodeSet(xmlNodePtr val) {
2052 xmlXPathObjectPtr ret;
2053
2054 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2055 if (ret == NULL) {
2056 xmlGenericError(xmlGenericErrorContext,
2057 "xmlXPathNewNodeSet: out of memory\n");
2058 return(NULL);
2059 }
2060 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2061 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002062 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002063 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002064 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002065 return(ret);
2066}
2067
2068/**
2069 * xmlXPathNewValueTree:
2070 * @val: the NodePtr value
2071 *
2072 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2073 * it with the tree root @val
2074 *
2075 * Returns the newly created object.
2076 */
2077xmlXPathObjectPtr
2078xmlXPathNewValueTree(xmlNodePtr val) {
2079 xmlXPathObjectPtr ret;
2080
2081 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2082 if (ret == NULL) {
2083 xmlGenericError(xmlGenericErrorContext,
2084 "xmlXPathNewNodeSet: out of memory\n");
2085 return(NULL);
2086 }
2087 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2088 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002089 ret->boolval = 1;
2090 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002091 ret->nodesetval = xmlXPathNodeSetCreate(val);
2092 return(ret);
2093}
2094
2095/**
2096 * xmlXPathNewNodeSetList:
2097 * @val: an existing NodeSet
2098 *
2099 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2100 * it with the Nodeset @val
2101 *
2102 * Returns the newly created object.
2103 */
2104xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002105xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2106{
Owen Taylor3473f882001-02-23 17:55:21 +00002107 xmlXPathObjectPtr ret;
2108 int i;
2109
2110 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002111 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002112 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002113 ret = xmlXPathNewNodeSet(NULL);
2114 else {
2115 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2116 for (i = 1; i < val->nodeNr; ++i)
2117 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2118 }
Owen Taylor3473f882001-02-23 17:55:21 +00002119
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002120 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002121}
2122
2123/**
2124 * xmlXPathWrapNodeSet:
2125 * @val: the NodePtr value
2126 *
2127 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2128 *
2129 * Returns the newly created object.
2130 */
2131xmlXPathObjectPtr
2132xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2133 xmlXPathObjectPtr ret;
2134
2135 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2136 if (ret == NULL) {
2137 xmlGenericError(xmlGenericErrorContext,
2138 "xmlXPathWrapNodeSet: out of memory\n");
2139 return(NULL);
2140 }
2141 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2142 ret->type = XPATH_NODESET;
2143 ret->nodesetval = val;
2144 return(ret);
2145}
2146
2147/**
2148 * xmlXPathFreeNodeSetList:
2149 * @obj: an existing NodeSetList object
2150 *
2151 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2152 * the list contrary to xmlXPathFreeObject().
2153 */
2154void
2155xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2156 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002157 xmlFree(obj);
2158}
2159
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002160/**
2161 * xmlXPathDifference:
2162 * @nodes1: a node-set
2163 * @nodes2: a node-set
2164 *
2165 * Implements the EXSLT - Sets difference() function:
2166 * node-set set:difference (node-set, node-set)
2167 *
2168 * Returns the difference between the two node sets, or nodes1 if
2169 * nodes2 is empty
2170 */
2171xmlNodeSetPtr
2172xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2173 xmlNodeSetPtr ret;
2174 int i, l1;
2175 xmlNodePtr cur;
2176
2177 if (xmlXPathNodeSetIsEmpty(nodes2))
2178 return(nodes1);
2179
2180 ret = xmlXPathNodeSetCreate(NULL);
2181 if (xmlXPathNodeSetIsEmpty(nodes1))
2182 return(ret);
2183
2184 l1 = xmlXPathNodeSetGetLength(nodes1);
2185
2186 for (i = 0; i < l1; i++) {
2187 cur = xmlXPathNodeSetItem(nodes1, i);
2188 if (!xmlXPathNodeSetContains(nodes2, cur))
2189 xmlXPathNodeSetAddUnique(ret, cur);
2190 }
2191 return(ret);
2192}
2193
2194/**
2195 * xmlXPathIntersection:
2196 * @nodes1: a node-set
2197 * @nodes2: a node-set
2198 *
2199 * Implements the EXSLT - Sets intersection() function:
2200 * node-set set:intersection (node-set, node-set)
2201 *
2202 * Returns a node set comprising the nodes that are within both the
2203 * node sets passed as arguments
2204 */
2205xmlNodeSetPtr
2206xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2207 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2208 int i, l1;
2209 xmlNodePtr cur;
2210
2211 if (xmlXPathNodeSetIsEmpty(nodes1))
2212 return(ret);
2213 if (xmlXPathNodeSetIsEmpty(nodes2))
2214 return(ret);
2215
2216 l1 = xmlXPathNodeSetGetLength(nodes1);
2217
2218 for (i = 0; i < l1; i++) {
2219 cur = xmlXPathNodeSetItem(nodes1, i);
2220 if (xmlXPathNodeSetContains(nodes2, cur))
2221 xmlXPathNodeSetAddUnique(ret, cur);
2222 }
2223 return(ret);
2224}
2225
2226/**
2227 * xmlXPathDistinctSorted:
2228 * @nodes: a node-set, sorted by document order
2229 *
2230 * Implements the EXSLT - Sets distinct() function:
2231 * node-set set:distinct (node-set)
2232 *
2233 * Returns a subset of the nodes contained in @nodes, or @nodes if
2234 * it is empty
2235 */
2236xmlNodeSetPtr
2237xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2238 xmlNodeSetPtr ret;
2239 xmlHashTablePtr hash;
2240 int i, l;
2241 xmlChar * strval;
2242 xmlNodePtr cur;
2243
2244 if (xmlXPathNodeSetIsEmpty(nodes))
2245 return(nodes);
2246
2247 ret = xmlXPathNodeSetCreate(NULL);
2248 l = xmlXPathNodeSetGetLength(nodes);
2249 hash = xmlHashCreate (l);
2250 for (i = 0; i < l; i++) {
2251 cur = xmlXPathNodeSetItem(nodes, i);
2252 strval = xmlXPathCastNodeToString(cur);
2253 if (xmlHashLookup(hash, strval) == NULL) {
2254 xmlHashAddEntry(hash, strval, strval);
2255 xmlXPathNodeSetAddUnique(ret, cur);
2256 } else {
2257 xmlFree(strval);
2258 }
2259 }
2260 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2261 return(ret);
2262}
2263
2264/**
2265 * xmlXPathDistinct:
2266 * @nodes: a node-set
2267 *
2268 * Implements the EXSLT - Sets distinct() function:
2269 * node-set set:distinct (node-set)
2270 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2271 * is called with the sorted node-set
2272 *
2273 * Returns a subset of the nodes contained in @nodes, or @nodes if
2274 * it is empty
2275 */
2276xmlNodeSetPtr
2277xmlXPathDistinct (xmlNodeSetPtr nodes) {
2278 if (xmlXPathNodeSetIsEmpty(nodes))
2279 return(nodes);
2280
2281 xmlXPathNodeSetSort(nodes);
2282 return(xmlXPathDistinctSorted(nodes));
2283}
2284
2285/**
2286 * xmlXPathHasSameNodes:
2287 * @nodes1: a node-set
2288 * @nodes2: a node-set
2289 *
2290 * Implements the EXSLT - Sets has-same-nodes function:
2291 * boolean set:has-same-node(node-set, node-set)
2292 *
2293 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2294 * otherwise
2295 */
2296int
2297xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2298 int i, l;
2299 xmlNodePtr cur;
2300
2301 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2302 xmlXPathNodeSetIsEmpty(nodes2))
2303 return(0);
2304
2305 l = xmlXPathNodeSetGetLength(nodes1);
2306 for (i = 0; i < l; i++) {
2307 cur = xmlXPathNodeSetItem(nodes1, i);
2308 if (xmlXPathNodeSetContains(nodes2, cur))
2309 return(1);
2310 }
2311 return(0);
2312}
2313
2314/**
2315 * xmlXPathNodeLeadingSorted:
2316 * @nodes: a node-set, sorted by document order
2317 * @node: a node
2318 *
2319 * Implements the EXSLT - Sets leading() function:
2320 * node-set set:leading (node-set, node-set)
2321 *
2322 * Returns the nodes in @nodes that precede @node in document order,
2323 * @nodes if @node is NULL or an empty node-set if @nodes
2324 * doesn't contain @node
2325 */
2326xmlNodeSetPtr
2327xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2328 int i, l;
2329 xmlNodePtr cur;
2330 xmlNodeSetPtr ret;
2331
2332 if (node == NULL)
2333 return(nodes);
2334
2335 ret = xmlXPathNodeSetCreate(NULL);
2336 if (xmlXPathNodeSetIsEmpty(nodes) ||
2337 (!xmlXPathNodeSetContains(nodes, node)))
2338 return(ret);
2339
2340 l = xmlXPathNodeSetGetLength(nodes);
2341 for (i = 0; i < l; i++) {
2342 cur = xmlXPathNodeSetItem(nodes, i);
2343 if (cur == node)
2344 break;
2345 xmlXPathNodeSetAddUnique(ret, cur);
2346 }
2347 return(ret);
2348}
2349
2350/**
2351 * xmlXPathNodeLeading:
2352 * @nodes: a node-set
2353 * @node: a node
2354 *
2355 * Implements the EXSLT - Sets leading() function:
2356 * node-set set:leading (node-set, node-set)
2357 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2358 * is called.
2359 *
2360 * Returns the nodes in @nodes that precede @node in document order,
2361 * @nodes if @node is NULL or an empty node-set if @nodes
2362 * doesn't contain @node
2363 */
2364xmlNodeSetPtr
2365xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2366 xmlXPathNodeSetSort(nodes);
2367 return(xmlXPathNodeLeadingSorted(nodes, node));
2368}
2369
2370/**
2371 * xmlXPathLeadingSorted:
2372 * @nodes1: a node-set, sorted by document order
2373 * @nodes2: a node-set, sorted by document order
2374 *
2375 * Implements the EXSLT - Sets leading() function:
2376 * node-set set:leading (node-set, node-set)
2377 *
2378 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2379 * in document order, @nodes1 if @nodes2 is NULL or empty or
2380 * an empty node-set if @nodes1 doesn't contain @nodes2
2381 */
2382xmlNodeSetPtr
2383xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2384 if (xmlXPathNodeSetIsEmpty(nodes2))
2385 return(nodes1);
2386 return(xmlXPathNodeLeadingSorted(nodes1,
2387 xmlXPathNodeSetItem(nodes2, 1)));
2388}
2389
2390/**
2391 * xmlXPathLeading:
2392 * @nodes1: a node-set
2393 * @nodes2: a node-set
2394 *
2395 * Implements the EXSLT - Sets leading() function:
2396 * node-set set:leading (node-set, node-set)
2397 * @nodes1 and @nodes2 are sorted by document order, then
2398 * #exslSetsLeadingSorted is called.
2399 *
2400 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2401 * in document order, @nodes1 if @nodes2 is NULL or empty or
2402 * an empty node-set if @nodes1 doesn't contain @nodes2
2403 */
2404xmlNodeSetPtr
2405xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2406 if (xmlXPathNodeSetIsEmpty(nodes2))
2407 return(nodes1);
2408 if (xmlXPathNodeSetIsEmpty(nodes1))
2409 return(xmlXPathNodeSetCreate(NULL));
2410 xmlXPathNodeSetSort(nodes1);
2411 xmlXPathNodeSetSort(nodes2);
2412 return(xmlXPathNodeLeadingSorted(nodes1,
2413 xmlXPathNodeSetItem(nodes2, 1)));
2414}
2415
2416/**
2417 * xmlXPathNodeTrailingSorted:
2418 * @nodes: a node-set, sorted by document order
2419 * @node: a node
2420 *
2421 * Implements the EXSLT - Sets trailing() function:
2422 * node-set set:trailing (node-set, node-set)
2423 *
2424 * Returns the nodes in @nodes that follow @node in document order,
2425 * @nodes if @node is NULL or an empty node-set if @nodes
2426 * doesn't contain @node
2427 */
2428xmlNodeSetPtr
2429xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2430 int i, l;
2431 xmlNodePtr cur;
2432 xmlNodeSetPtr ret;
2433
2434 if (node == NULL)
2435 return(nodes);
2436
2437 ret = xmlXPathNodeSetCreate(NULL);
2438 if (xmlXPathNodeSetIsEmpty(nodes) ||
2439 (!xmlXPathNodeSetContains(nodes, node)))
2440 return(ret);
2441
2442 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002443 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002444 cur = xmlXPathNodeSetItem(nodes, i);
2445 if (cur == node)
2446 break;
2447 xmlXPathNodeSetAddUnique(ret, cur);
2448 }
2449 return(ret);
2450}
2451
2452/**
2453 * xmlXPathNodeTrailing:
2454 * @nodes: a node-set
2455 * @node: a node
2456 *
2457 * Implements the EXSLT - Sets trailing() function:
2458 * node-set set:trailing (node-set, node-set)
2459 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2460 * is called.
2461 *
2462 * Returns the nodes in @nodes that follow @node in document order,
2463 * @nodes if @node is NULL or an empty node-set if @nodes
2464 * doesn't contain @node
2465 */
2466xmlNodeSetPtr
2467xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2468 xmlXPathNodeSetSort(nodes);
2469 return(xmlXPathNodeTrailingSorted(nodes, node));
2470}
2471
2472/**
2473 * xmlXPathTrailingSorted:
2474 * @nodes1: a node-set, sorted by document order
2475 * @nodes2: a node-set, sorted by document order
2476 *
2477 * Implements the EXSLT - Sets trailing() function:
2478 * node-set set:trailing (node-set, node-set)
2479 *
2480 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2481 * in document order, @nodes1 if @nodes2 is NULL or empty or
2482 * an empty node-set if @nodes1 doesn't contain @nodes2
2483 */
2484xmlNodeSetPtr
2485xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2486 if (xmlXPathNodeSetIsEmpty(nodes2))
2487 return(nodes1);
2488 return(xmlXPathNodeTrailingSorted(nodes1,
2489 xmlXPathNodeSetItem(nodes2, 0)));
2490}
2491
2492/**
2493 * xmlXPathTrailing:
2494 * @nodes1: a node-set
2495 * @nodes2: a node-set
2496 *
2497 * Implements the EXSLT - Sets trailing() function:
2498 * node-set set:trailing (node-set, node-set)
2499 * @nodes1 and @nodes2 are sorted by document order, then
2500 * #xmlXPathTrailingSorted is called.
2501 *
2502 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2503 * in document order, @nodes1 if @nodes2 is NULL or empty or
2504 * an empty node-set if @nodes1 doesn't contain @nodes2
2505 */
2506xmlNodeSetPtr
2507xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2508 if (xmlXPathNodeSetIsEmpty(nodes2))
2509 return(nodes1);
2510 if (xmlXPathNodeSetIsEmpty(nodes1))
2511 return(xmlXPathNodeSetCreate(NULL));
2512 xmlXPathNodeSetSort(nodes1);
2513 xmlXPathNodeSetSort(nodes2);
2514 return(xmlXPathNodeTrailingSorted(nodes1,
2515 xmlXPathNodeSetItem(nodes2, 0)));
2516}
2517
Owen Taylor3473f882001-02-23 17:55:21 +00002518/************************************************************************
2519 * *
2520 * Routines to handle extra functions *
2521 * *
2522 ************************************************************************/
2523
2524/**
2525 * xmlXPathRegisterFunc:
2526 * @ctxt: the XPath context
2527 * @name: the function name
2528 * @f: the function implementation or NULL
2529 *
2530 * Register a new function. If @f is NULL it unregisters the function
2531 *
2532 * Returns 0 in case of success, -1 in case of error
2533 */
2534int
2535xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2536 xmlXPathFunction f) {
2537 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2538}
2539
2540/**
2541 * xmlXPathRegisterFuncNS:
2542 * @ctxt: the XPath context
2543 * @name: the function name
2544 * @ns_uri: the function namespace URI
2545 * @f: the function implementation or NULL
2546 *
2547 * Register a new function. If @f is NULL it unregisters the function
2548 *
2549 * Returns 0 in case of success, -1 in case of error
2550 */
2551int
2552xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2553 const xmlChar *ns_uri, xmlXPathFunction f) {
2554 if (ctxt == NULL)
2555 return(-1);
2556 if (name == NULL)
2557 return(-1);
2558
2559 if (ctxt->funcHash == NULL)
2560 ctxt->funcHash = xmlHashCreate(0);
2561 if (ctxt->funcHash == NULL)
2562 return(-1);
2563 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2564}
2565
2566/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002567 * xmlXPathRegisterFuncLookup:
2568 * @ctxt: the XPath context
2569 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002570 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002571 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002572 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002573 */
2574void
2575xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2576 xmlXPathFuncLookupFunc f,
2577 void *funcCtxt) {
2578 if (ctxt == NULL)
2579 return;
2580 ctxt->funcLookupFunc = (void *) f;
2581 ctxt->funcLookupData = funcCtxt;
2582}
2583
2584/**
Owen Taylor3473f882001-02-23 17:55:21 +00002585 * xmlXPathFunctionLookup:
2586 * @ctxt: the XPath context
2587 * @name: the function name
2588 *
2589 * Search in the Function array of the context for the given
2590 * function.
2591 *
2592 * Returns the xmlXPathFunction or NULL if not found
2593 */
2594xmlXPathFunction
2595xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002596 if (ctxt == NULL)
2597 return (NULL);
2598
2599 if (ctxt->funcLookupFunc != NULL) {
2600 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002601 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002602
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002603 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002604 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002605 if (ret != NULL)
2606 return(ret);
2607 }
Owen Taylor3473f882001-02-23 17:55:21 +00002608 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2609}
2610
2611/**
2612 * xmlXPathFunctionLookupNS:
2613 * @ctxt: the XPath context
2614 * @name: the function name
2615 * @ns_uri: the function namespace URI
2616 *
2617 * Search in the Function array of the context for the given
2618 * function.
2619 *
2620 * Returns the xmlXPathFunction or NULL if not found
2621 */
2622xmlXPathFunction
2623xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2624 const xmlChar *ns_uri) {
2625 if (ctxt == NULL)
2626 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002627 if (name == NULL)
2628 return(NULL);
2629
Thomas Broyerba4ad322001-07-26 16:55:21 +00002630 if (ctxt->funcLookupFunc != NULL) {
2631 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002632 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002633
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002634 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002635 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002636 if (ret != NULL)
2637 return(ret);
2638 }
2639
2640 if (ctxt->funcHash == NULL)
2641 return(NULL);
2642
Owen Taylor3473f882001-02-23 17:55:21 +00002643 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2644}
2645
2646/**
2647 * xmlXPathRegisteredFuncsCleanup:
2648 * @ctxt: the XPath context
2649 *
2650 * Cleanup the XPath context data associated to registered functions
2651 */
2652void
2653xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2654 if (ctxt == NULL)
2655 return;
2656
2657 xmlHashFree(ctxt->funcHash, NULL);
2658 ctxt->funcHash = NULL;
2659}
2660
2661/************************************************************************
2662 * *
2663 * Routines to handle Variable *
2664 * *
2665 ************************************************************************/
2666
2667/**
2668 * xmlXPathRegisterVariable:
2669 * @ctxt: the XPath context
2670 * @name: the variable name
2671 * @value: the variable value or NULL
2672 *
2673 * Register a new variable value. If @value is NULL it unregisters
2674 * the variable
2675 *
2676 * Returns 0 in case of success, -1 in case of error
2677 */
2678int
2679xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2680 xmlXPathObjectPtr value) {
2681 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2682}
2683
2684/**
2685 * xmlXPathRegisterVariableNS:
2686 * @ctxt: the XPath context
2687 * @name: the variable name
2688 * @ns_uri: the variable namespace URI
2689 * @value: the variable value or NULL
2690 *
2691 * Register a new variable value. If @value is NULL it unregisters
2692 * the variable
2693 *
2694 * Returns 0 in case of success, -1 in case of error
2695 */
2696int
2697xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2698 const xmlChar *ns_uri,
2699 xmlXPathObjectPtr value) {
2700 if (ctxt == NULL)
2701 return(-1);
2702 if (name == NULL)
2703 return(-1);
2704
2705 if (ctxt->varHash == NULL)
2706 ctxt->varHash = xmlHashCreate(0);
2707 if (ctxt->varHash == NULL)
2708 return(-1);
2709 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2710 (void *) value,
2711 (xmlHashDeallocator)xmlXPathFreeObject));
2712}
2713
2714/**
2715 * xmlXPathRegisterVariableLookup:
2716 * @ctxt: the XPath context
2717 * @f: the lookup function
2718 * @data: the lookup data
2719 *
2720 * register an external mechanism to do variable lookup
2721 */
2722void
2723xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2724 xmlXPathVariableLookupFunc f, void *data) {
2725 if (ctxt == NULL)
2726 return;
2727 ctxt->varLookupFunc = (void *) f;
2728 ctxt->varLookupData = data;
2729}
2730
2731/**
2732 * xmlXPathVariableLookup:
2733 * @ctxt: the XPath context
2734 * @name: the variable name
2735 *
2736 * Search in the Variable array of the context for the given
2737 * variable value.
2738 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002739 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002740 */
2741xmlXPathObjectPtr
2742xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2743 if (ctxt == NULL)
2744 return(NULL);
2745
2746 if (ctxt->varLookupFunc != NULL) {
2747 xmlXPathObjectPtr ret;
2748
2749 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2750 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002751 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002752 }
2753 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2754}
2755
2756/**
2757 * xmlXPathVariableLookupNS:
2758 * @ctxt: the XPath context
2759 * @name: the variable name
2760 * @ns_uri: the variable namespace URI
2761 *
2762 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002763 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002764 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002765 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002766 */
2767xmlXPathObjectPtr
2768xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2769 const xmlChar *ns_uri) {
2770 if (ctxt == NULL)
2771 return(NULL);
2772
2773 if (ctxt->varLookupFunc != NULL) {
2774 xmlXPathObjectPtr ret;
2775
2776 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2777 (ctxt->varLookupData, name, ns_uri);
2778 if (ret != NULL) return(ret);
2779 }
2780
2781 if (ctxt->varHash == NULL)
2782 return(NULL);
2783 if (name == NULL)
2784 return(NULL);
2785
Daniel Veillard8c357d52001-07-03 23:43:33 +00002786 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2787 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002788}
2789
2790/**
2791 * xmlXPathRegisteredVariablesCleanup:
2792 * @ctxt: the XPath context
2793 *
2794 * Cleanup the XPath context data associated to registered variables
2795 */
2796void
2797xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2798 if (ctxt == NULL)
2799 return;
2800
Daniel Veillard76d66f42001-05-16 21:05:17 +00002801 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002802 ctxt->varHash = NULL;
2803}
2804
2805/**
2806 * xmlXPathRegisterNs:
2807 * @ctxt: the XPath context
2808 * @prefix: the namespace prefix
2809 * @ns_uri: the namespace name
2810 *
2811 * Register a new namespace. If @ns_uri is NULL it unregisters
2812 * the namespace
2813 *
2814 * Returns 0 in case of success, -1 in case of error
2815 */
2816int
2817xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2818 const xmlChar *ns_uri) {
2819 if (ctxt == NULL)
2820 return(-1);
2821 if (prefix == NULL)
2822 return(-1);
2823
2824 if (ctxt->nsHash == NULL)
2825 ctxt->nsHash = xmlHashCreate(10);
2826 if (ctxt->nsHash == NULL)
2827 return(-1);
2828 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2829 (xmlHashDeallocator)xmlFree));
2830}
2831
2832/**
2833 * xmlXPathNsLookup:
2834 * @ctxt: the XPath context
2835 * @prefix: the namespace prefix value
2836 *
2837 * Search in the namespace declaration array of the context for the given
2838 * namespace name associated to the given prefix
2839 *
2840 * Returns the value or NULL if not found
2841 */
2842const xmlChar *
2843xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2844 if (ctxt == NULL)
2845 return(NULL);
2846 if (prefix == NULL)
2847 return(NULL);
2848
2849#ifdef XML_XML_NAMESPACE
2850 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2851 return(XML_XML_NAMESPACE);
2852#endif
2853
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002854 if (ctxt->namespaces != NULL) {
2855 int i;
2856
2857 for (i = 0;i < ctxt->nsNr;i++) {
2858 if ((ctxt->namespaces[i] != NULL) &&
2859 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2860 return(ctxt->namespaces[i]->href);
2861 }
2862 }
Owen Taylor3473f882001-02-23 17:55:21 +00002863
2864 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2865}
2866
2867/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002868 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002869 * @ctxt: the XPath context
2870 *
2871 * Cleanup the XPath context data associated to registered variables
2872 */
2873void
2874xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2875 if (ctxt == NULL)
2876 return;
2877
2878 xmlHashFree(ctxt->nsHash, NULL);
2879 ctxt->nsHash = NULL;
2880}
2881
2882/************************************************************************
2883 * *
2884 * Routines to handle Values *
2885 * *
2886 ************************************************************************/
2887
2888/* Allocations are terrible, one need to optimize all this !!! */
2889
2890/**
2891 * xmlXPathNewFloat:
2892 * @val: the double value
2893 *
2894 * Create a new xmlXPathObjectPtr of type double and of value @val
2895 *
2896 * Returns the newly created object.
2897 */
2898xmlXPathObjectPtr
2899xmlXPathNewFloat(double val) {
2900 xmlXPathObjectPtr ret;
2901
2902 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2903 if (ret == NULL) {
2904 xmlGenericError(xmlGenericErrorContext,
2905 "xmlXPathNewFloat: out of memory\n");
2906 return(NULL);
2907 }
2908 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2909 ret->type = XPATH_NUMBER;
2910 ret->floatval = val;
2911 return(ret);
2912}
2913
2914/**
2915 * xmlXPathNewBoolean:
2916 * @val: the boolean value
2917 *
2918 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2919 *
2920 * Returns the newly created object.
2921 */
2922xmlXPathObjectPtr
2923xmlXPathNewBoolean(int val) {
2924 xmlXPathObjectPtr ret;
2925
2926 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2927 if (ret == NULL) {
2928 xmlGenericError(xmlGenericErrorContext,
2929 "xmlXPathNewBoolean: out of memory\n");
2930 return(NULL);
2931 }
2932 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2933 ret->type = XPATH_BOOLEAN;
2934 ret->boolval = (val != 0);
2935 return(ret);
2936}
2937
2938/**
2939 * xmlXPathNewString:
2940 * @val: the xmlChar * value
2941 *
2942 * Create a new xmlXPathObjectPtr of type string and of value @val
2943 *
2944 * Returns the newly created object.
2945 */
2946xmlXPathObjectPtr
2947xmlXPathNewString(const xmlChar *val) {
2948 xmlXPathObjectPtr ret;
2949
2950 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2951 if (ret == NULL) {
2952 xmlGenericError(xmlGenericErrorContext,
2953 "xmlXPathNewString: out of memory\n");
2954 return(NULL);
2955 }
2956 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2957 ret->type = XPATH_STRING;
2958 if (val != NULL)
2959 ret->stringval = xmlStrdup(val);
2960 else
2961 ret->stringval = xmlStrdup((const xmlChar *)"");
2962 return(ret);
2963}
2964
2965/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002966 * xmlXPathWrapString:
2967 * @val: the xmlChar * value
2968 *
2969 * Wraps the @val string into an XPath object.
2970 *
2971 * Returns the newly created object.
2972 */
2973xmlXPathObjectPtr
2974xmlXPathWrapString (xmlChar *val) {
2975 xmlXPathObjectPtr ret;
2976
2977 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2978 if (ret == NULL) {
2979 xmlGenericError(xmlGenericErrorContext,
2980 "xmlXPathWrapString: out of memory\n");
2981 return(NULL);
2982 }
2983 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2984 ret->type = XPATH_STRING;
2985 ret->stringval = val;
2986 return(ret);
2987}
2988
2989/**
Owen Taylor3473f882001-02-23 17:55:21 +00002990 * xmlXPathNewCString:
2991 * @val: the char * value
2992 *
2993 * Create a new xmlXPathObjectPtr of type string and of value @val
2994 *
2995 * Returns the newly created object.
2996 */
2997xmlXPathObjectPtr
2998xmlXPathNewCString(const char *val) {
2999 xmlXPathObjectPtr ret;
3000
3001 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3002 if (ret == NULL) {
3003 xmlGenericError(xmlGenericErrorContext,
3004 "xmlXPathNewCString: out of memory\n");
3005 return(NULL);
3006 }
3007 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3008 ret->type = XPATH_STRING;
3009 ret->stringval = xmlStrdup(BAD_CAST val);
3010 return(ret);
3011}
3012
3013/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003014 * xmlXPathWrapCString:
3015 * @val: the char * value
3016 *
3017 * Wraps a string into an XPath object.
3018 *
3019 * Returns the newly created object.
3020 */
3021xmlXPathObjectPtr
3022xmlXPathWrapCString (char * val) {
3023 return(xmlXPathWrapString((xmlChar *)(val)));
3024}
3025
3026/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003027 * xmlXPathWrapExternal:
3028 * @val: the user data
3029 *
3030 * Wraps the @val data into an XPath object.
3031 *
3032 * Returns the newly created object.
3033 */
3034xmlXPathObjectPtr
3035xmlXPathWrapExternal (void *val) {
3036 xmlXPathObjectPtr ret;
3037
3038 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3039 if (ret == NULL) {
3040 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003041 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003042 return(NULL);
3043 }
3044 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3045 ret->type = XPATH_USERS;
3046 ret->user = val;
3047 return(ret);
3048}
3049
3050/**
Owen Taylor3473f882001-02-23 17:55:21 +00003051 * xmlXPathObjectCopy:
3052 * @val: the original object
3053 *
3054 * allocate a new copy of a given object
3055 *
3056 * Returns the newly created object.
3057 */
3058xmlXPathObjectPtr
3059xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3060 xmlXPathObjectPtr ret;
3061
3062 if (val == NULL)
3063 return(NULL);
3064
3065 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3066 if (ret == NULL) {
3067 xmlGenericError(xmlGenericErrorContext,
3068 "xmlXPathObjectCopy: out of memory\n");
3069 return(NULL);
3070 }
3071 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3072 switch (val->type) {
3073 case XPATH_BOOLEAN:
3074 case XPATH_NUMBER:
3075 case XPATH_POINT:
3076 case XPATH_RANGE:
3077 break;
3078 case XPATH_STRING:
3079 ret->stringval = xmlStrdup(val->stringval);
3080 break;
3081 case XPATH_XSLT_TREE:
3082 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003083 (val->nodesetval->nodeTab != NULL)) {
3084 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003085 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3086 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003087 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003088 (xmlNodePtr) ret->user);
3089 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003090 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003091 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003092 break;
3093 case XPATH_NODESET:
3094 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003095 /* Do not deallocate the copied tree value */
3096 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003097 break;
3098 case XPATH_LOCATIONSET:
3099#ifdef LIBXML_XPTR_ENABLED
3100 {
3101 xmlLocationSetPtr loc = val->user;
3102 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3103 break;
3104 }
3105#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003106 case XPATH_USERS:
3107 ret->user = val->user;
3108 break;
3109 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003110 xmlGenericError(xmlGenericErrorContext,
3111 "xmlXPathObjectCopy: unsupported type %d\n",
3112 val->type);
3113 break;
3114 }
3115 return(ret);
3116}
3117
3118/**
3119 * xmlXPathFreeObject:
3120 * @obj: the object to free
3121 *
3122 * Free up an xmlXPathObjectPtr object.
3123 */
3124void
3125xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3126 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003127 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003128 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003129 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003130 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003131 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003132 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003133 xmlXPathFreeValueTree(obj->nodesetval);
3134 } else {
3135 if (obj->nodesetval != NULL)
3136 xmlXPathFreeNodeSet(obj->nodesetval);
3137 }
Owen Taylor3473f882001-02-23 17:55:21 +00003138#ifdef LIBXML_XPTR_ENABLED
3139 } else if (obj->type == XPATH_LOCATIONSET) {
3140 if (obj->user != NULL)
3141 xmlXPtrFreeLocationSet(obj->user);
3142#endif
3143 } else if (obj->type == XPATH_STRING) {
3144 if (obj->stringval != NULL)
3145 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003146 }
3147
Owen Taylor3473f882001-02-23 17:55:21 +00003148 xmlFree(obj);
3149}
3150
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003151
3152/************************************************************************
3153 * *
3154 * Type Casting Routines *
3155 * *
3156 ************************************************************************/
3157
3158/**
3159 * xmlXPathCastBooleanToString:
3160 * @val: a boolean
3161 *
3162 * Converts a boolean to its string value.
3163 *
3164 * Returns a newly allocated string.
3165 */
3166xmlChar *
3167xmlXPathCastBooleanToString (int val) {
3168 xmlChar *ret;
3169 if (val)
3170 ret = xmlStrdup((const xmlChar *) "true");
3171 else
3172 ret = xmlStrdup((const xmlChar *) "false");
3173 return(ret);
3174}
3175
3176/**
3177 * xmlXPathCastNumberToString:
3178 * @val: a number
3179 *
3180 * Converts a number to its string value.
3181 *
3182 * Returns a newly allocated string.
3183 */
3184xmlChar *
3185xmlXPathCastNumberToString (double val) {
3186 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003187 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003188 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003189 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003190 break;
3191 case -1:
3192 ret = xmlStrdup((const xmlChar *) "-Infinity");
3193 break;
3194 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003195 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003196 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003197 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3198 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003199 } else {
3200 /* could be improved */
3201 char buf[100];
3202 xmlXPathFormatNumber(val, buf, 100);
3203 ret = xmlStrdup((const xmlChar *) buf);
3204 }
3205 }
3206 return(ret);
3207}
3208
3209/**
3210 * xmlXPathCastNodeToString:
3211 * @node: a node
3212 *
3213 * Converts a node to its string value.
3214 *
3215 * Returns a newly allocated string.
3216 */
3217xmlChar *
3218xmlXPathCastNodeToString (xmlNodePtr node) {
Daniel Veillard23b1f372002-04-18 15:50:05 +00003219 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE))
3220 node = xmlDocGetRootElement((xmlDocPtr) node);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003221 return(xmlNodeGetContent(node));
3222}
3223
3224/**
3225 * xmlXPathCastNodeSetToString:
3226 * @ns: a node-set
3227 *
3228 * Converts a node-set to its string value.
3229 *
3230 * Returns a newly allocated string.
3231 */
3232xmlChar *
3233xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3234 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3235 return(xmlStrdup((const xmlChar *) ""));
3236
3237 xmlXPathNodeSetSort(ns);
3238 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3239}
3240
3241/**
3242 * xmlXPathCastToString:
3243 * @val: an XPath object
3244 *
3245 * Converts an existing object to its string() equivalent
3246 *
3247 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003248 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003249 * string object).
3250 */
3251xmlChar *
3252xmlXPathCastToString(xmlXPathObjectPtr val) {
3253 xmlChar *ret = NULL;
3254
3255 if (val == NULL)
3256 return(xmlStrdup((const xmlChar *) ""));
3257 switch (val->type) {
3258 case XPATH_UNDEFINED:
3259#ifdef DEBUG_EXPR
3260 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3261#endif
3262 ret = xmlStrdup((const xmlChar *) "");
3263 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003264 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003265 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003266 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3267 break;
3268 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003269 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003270 case XPATH_BOOLEAN:
3271 ret = xmlXPathCastBooleanToString(val->boolval);
3272 break;
3273 case XPATH_NUMBER: {
3274 ret = xmlXPathCastNumberToString(val->floatval);
3275 break;
3276 }
3277 case XPATH_USERS:
3278 case XPATH_POINT:
3279 case XPATH_RANGE:
3280 case XPATH_LOCATIONSET:
3281 TODO
3282 ret = xmlStrdup((const xmlChar *) "");
3283 break;
3284 }
3285 return(ret);
3286}
3287
3288/**
3289 * xmlXPathConvertString:
3290 * @val: an XPath object
3291 *
3292 * Converts an existing object to its string() equivalent
3293 *
3294 * Returns the new object, the old one is freed (or the operation
3295 * is done directly on @val)
3296 */
3297xmlXPathObjectPtr
3298xmlXPathConvertString(xmlXPathObjectPtr val) {
3299 xmlChar *res = NULL;
3300
3301 if (val == NULL)
3302 return(xmlXPathNewCString(""));
3303
3304 switch (val->type) {
3305 case XPATH_UNDEFINED:
3306#ifdef DEBUG_EXPR
3307 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3308#endif
3309 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003310 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003311 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003312 res = xmlXPathCastNodeSetToString(val->nodesetval);
3313 break;
3314 case XPATH_STRING:
3315 return(val);
3316 case XPATH_BOOLEAN:
3317 res = xmlXPathCastBooleanToString(val->boolval);
3318 break;
3319 case XPATH_NUMBER:
3320 res = xmlXPathCastNumberToString(val->floatval);
3321 break;
3322 case XPATH_USERS:
3323 case XPATH_POINT:
3324 case XPATH_RANGE:
3325 case XPATH_LOCATIONSET:
3326 TODO;
3327 break;
3328 }
3329 xmlXPathFreeObject(val);
3330 if (res == NULL)
3331 return(xmlXPathNewCString(""));
3332 return(xmlXPathWrapString(res));
3333}
3334
3335/**
3336 * xmlXPathCastBooleanToNumber:
3337 * @val: a boolean
3338 *
3339 * Converts a boolean to its number value
3340 *
3341 * Returns the number value
3342 */
3343double
3344xmlXPathCastBooleanToNumber(int val) {
3345 if (val)
3346 return(1.0);
3347 return(0.0);
3348}
3349
3350/**
3351 * xmlXPathCastStringToNumber:
3352 * @val: a string
3353 *
3354 * Converts a string to its number value
3355 *
3356 * Returns the number value
3357 */
3358double
3359xmlXPathCastStringToNumber(const xmlChar * val) {
3360 return(xmlXPathStringEvalNumber(val));
3361}
3362
3363/**
3364 * xmlXPathCastNodeToNumber:
3365 * @node: a node
3366 *
3367 * Converts a node to its number value
3368 *
3369 * Returns the number value
3370 */
3371double
3372xmlXPathCastNodeToNumber (xmlNodePtr node) {
3373 xmlChar *strval;
3374 double ret;
3375
3376 if (node == NULL)
3377 return(xmlXPathNAN);
3378 strval = xmlXPathCastNodeToString(node);
3379 if (strval == NULL)
3380 return(xmlXPathNAN);
3381 ret = xmlXPathCastStringToNumber(strval);
3382 xmlFree(strval);
3383
3384 return(ret);
3385}
3386
3387/**
3388 * xmlXPathCastNodeSetToNumber:
3389 * @ns: a node-set
3390 *
3391 * Converts a node-set to its number value
3392 *
3393 * Returns the number value
3394 */
3395double
3396xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3397 xmlChar *str;
3398 double ret;
3399
3400 if (ns == NULL)
3401 return(xmlXPathNAN);
3402 str = xmlXPathCastNodeSetToString(ns);
3403 ret = xmlXPathCastStringToNumber(str);
3404 xmlFree(str);
3405 return(ret);
3406}
3407
3408/**
3409 * xmlXPathCastToNumber:
3410 * @val: an XPath object
3411 *
3412 * Converts an XPath object to its number value
3413 *
3414 * Returns the number value
3415 */
3416double
3417xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3418 double ret = 0.0;
3419
3420 if (val == NULL)
3421 return(xmlXPathNAN);
3422 switch (val->type) {
3423 case XPATH_UNDEFINED:
3424#ifdef DEGUB_EXPR
3425 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3426#endif
3427 ret = xmlXPathNAN;
3428 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003429 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003430 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003431 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3432 break;
3433 case XPATH_STRING:
3434 ret = xmlXPathCastStringToNumber(val->stringval);
3435 break;
3436 case XPATH_NUMBER:
3437 ret = val->floatval;
3438 break;
3439 case XPATH_BOOLEAN:
3440 ret = xmlXPathCastBooleanToNumber(val->boolval);
3441 break;
3442 case XPATH_USERS:
3443 case XPATH_POINT:
3444 case XPATH_RANGE:
3445 case XPATH_LOCATIONSET:
3446 TODO;
3447 ret = xmlXPathNAN;
3448 break;
3449 }
3450 return(ret);
3451}
3452
3453/**
3454 * xmlXPathConvertNumber:
3455 * @val: an XPath object
3456 *
3457 * Converts an existing object to its number() equivalent
3458 *
3459 * Returns the new object, the old one is freed (or the operation
3460 * is done directly on @val)
3461 */
3462xmlXPathObjectPtr
3463xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3464 xmlXPathObjectPtr ret;
3465
3466 if (val == NULL)
3467 return(xmlXPathNewFloat(0.0));
3468 if (val->type == XPATH_NUMBER)
3469 return(val);
3470 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3471 xmlXPathFreeObject(val);
3472 return(ret);
3473}
3474
3475/**
3476 * xmlXPathCastNumberToBoolean:
3477 * @val: a number
3478 *
3479 * Converts a number to its boolean value
3480 *
3481 * Returns the boolean value
3482 */
3483int
3484xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003485 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003486 return(0);
3487 return(1);
3488}
3489
3490/**
3491 * xmlXPathCastStringToBoolean:
3492 * @val: a string
3493 *
3494 * Converts a string to its boolean value
3495 *
3496 * Returns the boolean value
3497 */
3498int
3499xmlXPathCastStringToBoolean (const xmlChar *val) {
3500 if ((val == NULL) || (xmlStrlen(val) == 0))
3501 return(0);
3502 return(1);
3503}
3504
3505/**
3506 * xmlXPathCastNodeSetToBoolean:
3507 * @ns: a node-set
3508 *
3509 * Converts a node-set to its boolean value
3510 *
3511 * Returns the boolean value
3512 */
3513int
3514xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3515 if ((ns == NULL) || (ns->nodeNr == 0))
3516 return(0);
3517 return(1);
3518}
3519
3520/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003521 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003522 * @val: an XPath object
3523 *
3524 * Converts an XPath object to its boolean value
3525 *
3526 * Returns the boolean value
3527 */
3528int
3529xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3530 int ret = 0;
3531
3532 if (val == NULL)
3533 return(0);
3534 switch (val->type) {
3535 case XPATH_UNDEFINED:
3536#ifdef DEBUG_EXPR
3537 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3538#endif
3539 ret = 0;
3540 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003541 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003542 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003543 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3544 break;
3545 case XPATH_STRING:
3546 ret = xmlXPathCastStringToBoolean(val->stringval);
3547 break;
3548 case XPATH_NUMBER:
3549 ret = xmlXPathCastNumberToBoolean(val->floatval);
3550 break;
3551 case XPATH_BOOLEAN:
3552 ret = val->boolval;
3553 break;
3554 case XPATH_USERS:
3555 case XPATH_POINT:
3556 case XPATH_RANGE:
3557 case XPATH_LOCATIONSET:
3558 TODO;
3559 ret = 0;
3560 break;
3561 }
3562 return(ret);
3563}
3564
3565
3566/**
3567 * xmlXPathConvertBoolean:
3568 * @val: an XPath object
3569 *
3570 * Converts an existing object to its boolean() equivalent
3571 *
3572 * Returns the new object, the old one is freed (or the operation
3573 * is done directly on @val)
3574 */
3575xmlXPathObjectPtr
3576xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3577 xmlXPathObjectPtr ret;
3578
3579 if (val == NULL)
3580 return(xmlXPathNewBoolean(0));
3581 if (val->type == XPATH_BOOLEAN)
3582 return(val);
3583 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3584 xmlXPathFreeObject(val);
3585 return(ret);
3586}
3587
Owen Taylor3473f882001-02-23 17:55:21 +00003588/************************************************************************
3589 * *
3590 * Routines to handle XPath contexts *
3591 * *
3592 ************************************************************************/
3593
3594/**
3595 * xmlXPathNewContext:
3596 * @doc: the XML document
3597 *
3598 * Create a new xmlXPathContext
3599 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003600 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003601 */
3602xmlXPathContextPtr
3603xmlXPathNewContext(xmlDocPtr doc) {
3604 xmlXPathContextPtr ret;
3605
3606 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3607 if (ret == NULL) {
3608 xmlGenericError(xmlGenericErrorContext,
3609 "xmlXPathNewContext: out of memory\n");
3610 return(NULL);
3611 }
3612 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3613 ret->doc = doc;
3614 ret->node = NULL;
3615
3616 ret->varHash = NULL;
3617
3618 ret->nb_types = 0;
3619 ret->max_types = 0;
3620 ret->types = NULL;
3621
3622 ret->funcHash = xmlHashCreate(0);
3623
3624 ret->nb_axis = 0;
3625 ret->max_axis = 0;
3626 ret->axis = NULL;
3627
3628 ret->nsHash = NULL;
3629 ret->user = NULL;
3630
3631 ret->contextSize = -1;
3632 ret->proximityPosition = -1;
3633
3634 xmlXPathRegisterAllFunctions(ret);
3635
3636 return(ret);
3637}
3638
3639/**
3640 * xmlXPathFreeContext:
3641 * @ctxt: the context to free
3642 *
3643 * Free up an xmlXPathContext
3644 */
3645void
3646xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3647 xmlXPathRegisteredNsCleanup(ctxt);
3648 xmlXPathRegisteredFuncsCleanup(ctxt);
3649 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003650 xmlFree(ctxt);
3651}
3652
3653/************************************************************************
3654 * *
3655 * Routines to handle XPath parser contexts *
3656 * *
3657 ************************************************************************/
3658
3659#define CHECK_CTXT(ctxt) \
3660 if (ctxt == NULL) { \
3661 xmlGenericError(xmlGenericErrorContext, \
3662 "%s:%d Internal error: ctxt == NULL\n", \
3663 __FILE__, __LINE__); \
3664 } \
3665
3666
3667#define CHECK_CONTEXT(ctxt) \
3668 if (ctxt == NULL) { \
3669 xmlGenericError(xmlGenericErrorContext, \
3670 "%s:%d Internal error: no context\n", \
3671 __FILE__, __LINE__); \
3672 } \
3673 else if (ctxt->doc == NULL) { \
3674 xmlGenericError(xmlGenericErrorContext, \
3675 "%s:%d Internal error: no document\n", \
3676 __FILE__, __LINE__); \
3677 } \
3678 else if (ctxt->doc->children == NULL) { \
3679 xmlGenericError(xmlGenericErrorContext, \
3680 "%s:%d Internal error: document without root\n", \
3681 __FILE__, __LINE__); \
3682 } \
3683
3684
3685/**
3686 * xmlXPathNewParserContext:
3687 * @str: the XPath expression
3688 * @ctxt: the XPath context
3689 *
3690 * Create a new xmlXPathParserContext
3691 *
3692 * Returns the xmlXPathParserContext just allocated.
3693 */
3694xmlXPathParserContextPtr
3695xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3696 xmlXPathParserContextPtr ret;
3697
3698 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3699 if (ret == NULL) {
3700 xmlGenericError(xmlGenericErrorContext,
3701 "xmlXPathNewParserContext: out of memory\n");
3702 return(NULL);
3703 }
3704 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3705 ret->cur = ret->base = str;
3706 ret->context = ctxt;
3707
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003708 ret->comp = xmlXPathNewCompExpr();
3709 if (ret->comp == NULL) {
3710 xmlFree(ret->valueTab);
3711 xmlFree(ret);
3712 return(NULL);
3713 }
3714
3715 return(ret);
3716}
3717
3718/**
3719 * xmlXPathCompParserContext:
3720 * @comp: the XPath compiled expression
3721 * @ctxt: the XPath context
3722 *
3723 * Create a new xmlXPathParserContext when processing a compiled expression
3724 *
3725 * Returns the xmlXPathParserContext just allocated.
3726 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003727static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003728xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3729 xmlXPathParserContextPtr ret;
3730
3731 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3732 if (ret == NULL) {
3733 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003734 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003735 return(NULL);
3736 }
3737 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3738
Owen Taylor3473f882001-02-23 17:55:21 +00003739 /* Allocate the value stack */
3740 ret->valueTab = (xmlXPathObjectPtr *)
3741 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003742 if (ret->valueTab == NULL) {
3743 xmlFree(ret);
3744 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003745 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003746 return(NULL);
3747 }
Owen Taylor3473f882001-02-23 17:55:21 +00003748 ret->valueNr = 0;
3749 ret->valueMax = 10;
3750 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003751
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003752 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003753 ret->comp = comp;
3754
Owen Taylor3473f882001-02-23 17:55:21 +00003755 return(ret);
3756}
3757
3758/**
3759 * xmlXPathFreeParserContext:
3760 * @ctxt: the context to free
3761 *
3762 * Free up an xmlXPathParserContext
3763 */
3764void
3765xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3766 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003767 xmlFree(ctxt->valueTab);
3768 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003769 if (ctxt->comp)
3770 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003771 xmlFree(ctxt);
3772}
3773
3774/************************************************************************
3775 * *
3776 * The implicit core function library *
3777 * *
3778 ************************************************************************/
3779
Owen Taylor3473f882001-02-23 17:55:21 +00003780/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003781 * xmlXPathNodeStringHash:
3782 * @node: a node pointer
3783 *
3784 * Function computing the beginning of the string value of the node,
3785 * used to speed up comparisons
3786 *
3787 * Returns an int usable as a hash
3788 */
3789static unsigned int
3790xmlXPathNodeValHash(xmlNodePtr node) {
3791 int len = 2;
3792 const xmlChar * string = NULL;
3793 xmlNodePtr tmp = NULL;
3794 unsigned int ret = 0;
3795
3796 if (node == NULL)
3797 return(0);
3798
3799
3800 switch (node->type) {
3801 case XML_COMMENT_NODE:
3802 case XML_PI_NODE:
3803 case XML_CDATA_SECTION_NODE:
3804 case XML_TEXT_NODE:
3805 string = node->content;
3806 if (string == NULL)
3807 return(0);
3808 if (string[0] == 0)
3809 return(0);
3810 return(((unsigned int) string[0]) +
3811 (((unsigned int) string[1]) << 8));
3812 case XML_NAMESPACE_DECL:
3813 string = ((xmlNsPtr)node)->href;
3814 if (string == NULL)
3815 return(0);
3816 if (string[0] == 0)
3817 return(0);
3818 return(((unsigned int) string[0]) +
3819 (((unsigned int) string[1]) << 8));
3820 case XML_ATTRIBUTE_NODE:
3821 tmp = ((xmlAttrPtr) node)->children;
3822 break;
3823 case XML_ELEMENT_NODE:
3824 tmp = node->children;
3825 break;
3826 default:
3827 return(0);
3828 }
3829 while (tmp != NULL) {
3830 switch (tmp->type) {
3831 case XML_COMMENT_NODE:
3832 case XML_PI_NODE:
3833 case XML_CDATA_SECTION_NODE:
3834 case XML_TEXT_NODE:
3835 string = tmp->content;
3836 break;
3837 case XML_NAMESPACE_DECL:
3838 string = ((xmlNsPtr)tmp)->href;
3839 break;
3840 default:
3841 break;
3842 }
3843 if ((string != NULL) && (string[0] != 0)) {
3844 if (string[0] == 0)
3845 return(0);
3846 if (len == 1) {
3847 return(ret + (((unsigned int) string[0]) << 8));
3848 }
3849 if (string[1] == 0) {
3850 len = 1;
3851 ret = (unsigned int) string[0];
3852 } else {
3853 return(((unsigned int) string[0]) +
3854 (((unsigned int) string[1]) << 8));
3855 }
3856 }
3857 /*
3858 * Skip to next node
3859 */
3860 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3861 if (tmp->children->type != XML_ENTITY_DECL) {
3862 tmp = tmp->children;
3863 continue;
3864 }
3865 }
3866 if (tmp == node)
3867 break;
3868
3869 if (tmp->next != NULL) {
3870 tmp = tmp->next;
3871 continue;
3872 }
3873
3874 do {
3875 tmp = tmp->parent;
3876 if (tmp == NULL)
3877 break;
3878 if (tmp == node) {
3879 tmp = NULL;
3880 break;
3881 }
3882 if (tmp->next != NULL) {
3883 tmp = tmp->next;
3884 break;
3885 }
3886 } while (tmp != NULL);
3887 }
3888 return(ret);
3889}
3890
3891/**
3892 * xmlXPathStringHash:
3893 * @string: a string
3894 *
3895 * Function computing the beginning of the string value of the node,
3896 * used to speed up comparisons
3897 *
3898 * Returns an int usable as a hash
3899 */
3900static unsigned int
3901xmlXPathStringHash(const xmlChar * string) {
3902 if (string == NULL)
3903 return((unsigned int) 0);
3904 if (string[0] == 0)
3905 return(0);
3906 return(((unsigned int) string[0]) +
3907 (((unsigned int) string[1]) << 8));
3908}
3909
3910/**
Owen Taylor3473f882001-02-23 17:55:21 +00003911 * xmlXPathCompareNodeSetFloat:
3912 * @ctxt: the XPath Parser context
3913 * @inf: less than (1) or greater than (0)
3914 * @strict: is the comparison strict
3915 * @arg: the node set
3916 * @f: the value
3917 *
3918 * Implement the compare operation between a nodeset and a number
3919 * @ns < @val (1, 1, ...
3920 * @ns <= @val (1, 0, ...
3921 * @ns > @val (0, 1, ...
3922 * @ns >= @val (0, 0, ...
3923 *
3924 * If one object to be compared is a node-set and the other is a number,
3925 * then the comparison will be true if and only if there is a node in the
3926 * node-set such that the result of performing the comparison on the number
3927 * to be compared and on the result of converting the string-value of that
3928 * node to a number using the number function is true.
3929 *
3930 * Returns 0 or 1 depending on the results of the test.
3931 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003932static int
Owen Taylor3473f882001-02-23 17:55:21 +00003933xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3934 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3935 int i, ret = 0;
3936 xmlNodeSetPtr ns;
3937 xmlChar *str2;
3938
3939 if ((f == NULL) || (arg == NULL) ||
3940 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3941 xmlXPathFreeObject(arg);
3942 xmlXPathFreeObject(f);
3943 return(0);
3944 }
3945 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003946 if (ns != NULL) {
3947 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003948 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003949 if (str2 != NULL) {
3950 valuePush(ctxt,
3951 xmlXPathNewString(str2));
3952 xmlFree(str2);
3953 xmlXPathNumberFunction(ctxt, 1);
3954 valuePush(ctxt, xmlXPathObjectCopy(f));
3955 ret = xmlXPathCompareValues(ctxt, inf, strict);
3956 if (ret)
3957 break;
3958 }
3959 }
Owen Taylor3473f882001-02-23 17:55:21 +00003960 }
3961 xmlXPathFreeObject(arg);
3962 xmlXPathFreeObject(f);
3963 return(ret);
3964}
3965
3966/**
3967 * xmlXPathCompareNodeSetString:
3968 * @ctxt: the XPath Parser context
3969 * @inf: less than (1) or greater than (0)
3970 * @strict: is the comparison strict
3971 * @arg: the node set
3972 * @s: the value
3973 *
3974 * Implement the compare operation between a nodeset and a string
3975 * @ns < @val (1, 1, ...
3976 * @ns <= @val (1, 0, ...
3977 * @ns > @val (0, 1, ...
3978 * @ns >= @val (0, 0, ...
3979 *
3980 * If one object to be compared is a node-set and the other is a string,
3981 * then the comparison will be true if and only if there is a node in
3982 * the node-set such that the result of performing the comparison on the
3983 * string-value of the node and the other string is true.
3984 *
3985 * Returns 0 or 1 depending on the results of the test.
3986 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003987static int
Owen Taylor3473f882001-02-23 17:55:21 +00003988xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3989 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3990 int i, ret = 0;
3991 xmlNodeSetPtr ns;
3992 xmlChar *str2;
3993
3994 if ((s == NULL) || (arg == NULL) ||
3995 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3996 xmlXPathFreeObject(arg);
3997 xmlXPathFreeObject(s);
3998 return(0);
3999 }
4000 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004001 if (ns != NULL) {
4002 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004003 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004004 if (str2 != NULL) {
4005 valuePush(ctxt,
4006 xmlXPathNewString(str2));
4007 xmlFree(str2);
4008 valuePush(ctxt, xmlXPathObjectCopy(s));
4009 ret = xmlXPathCompareValues(ctxt, inf, strict);
4010 if (ret)
4011 break;
4012 }
4013 }
Owen Taylor3473f882001-02-23 17:55:21 +00004014 }
4015 xmlXPathFreeObject(arg);
4016 xmlXPathFreeObject(s);
4017 return(ret);
4018}
4019
4020/**
4021 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004022 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004023 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004024 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004025 * @arg2: the second node set object
4026 *
4027 * Implement the compare operation on nodesets:
4028 *
4029 * If both objects to be compared are node-sets, then the comparison
4030 * will be true if and only if there is a node in the first node-set
4031 * and a node in the second node-set such that the result of performing
4032 * the comparison on the string-values of the two nodes is true.
4033 * ....
4034 * When neither object to be compared is a node-set and the operator
4035 * is <=, <, >= or >, then the objects are compared by converting both
4036 * objects to numbers and comparing the numbers according to IEEE 754.
4037 * ....
4038 * The number function converts its argument to a number as follows:
4039 * - a string that consists of optional whitespace followed by an
4040 * optional minus sign followed by a Number followed by whitespace
4041 * is converted to the IEEE 754 number that is nearest (according
4042 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4043 * represented by the string; any other string is converted to NaN
4044 *
4045 * Conclusion all nodes need to be converted first to their string value
4046 * and then the comparison must be done when possible
4047 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004048static int
4049xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004050 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4051 int i, j, init = 0;
4052 double val1;
4053 double *values2;
4054 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004055 xmlNodeSetPtr ns1;
4056 xmlNodeSetPtr ns2;
4057
4058 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004059 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4060 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004061 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004062 }
Owen Taylor3473f882001-02-23 17:55:21 +00004063 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004064 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4065 xmlXPathFreeObject(arg1);
4066 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004067 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004068 }
Owen Taylor3473f882001-02-23 17:55:21 +00004069
4070 ns1 = arg1->nodesetval;
4071 ns2 = arg2->nodesetval;
4072
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004073 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004074 xmlXPathFreeObject(arg1);
4075 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004076 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004077 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004078 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004079 xmlXPathFreeObject(arg1);
4080 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004081 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004082 }
Owen Taylor3473f882001-02-23 17:55:21 +00004083
4084 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4085 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004086 xmlXPathFreeObject(arg1);
4087 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004088 return(0);
4089 }
4090 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004091 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004092 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004093 continue;
4094 for (j = 0;j < ns2->nodeNr;j++) {
4095 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004096 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004097 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004098 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004099 continue;
4100 if (inf && strict)
4101 ret = (val1 < values2[j]);
4102 else if (inf && !strict)
4103 ret = (val1 <= values2[j]);
4104 else if (!inf && strict)
4105 ret = (val1 > values2[j]);
4106 else if (!inf && !strict)
4107 ret = (val1 >= values2[j]);
4108 if (ret)
4109 break;
4110 }
4111 if (ret)
4112 break;
4113 init = 1;
4114 }
4115 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004116 xmlXPathFreeObject(arg1);
4117 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004118 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004119}
4120
4121/**
4122 * xmlXPathCompareNodeSetValue:
4123 * @ctxt: the XPath Parser context
4124 * @inf: less than (1) or greater than (0)
4125 * @strict: is the comparison strict
4126 * @arg: the node set
4127 * @val: the value
4128 *
4129 * Implement the compare operation between a nodeset and a value
4130 * @ns < @val (1, 1, ...
4131 * @ns <= @val (1, 0, ...
4132 * @ns > @val (0, 1, ...
4133 * @ns >= @val (0, 0, ...
4134 *
4135 * If one object to be compared is a node-set and the other is a boolean,
4136 * then the comparison will be true if and only if the result of performing
4137 * the comparison on the boolean and on the result of converting
4138 * the node-set to a boolean using the boolean function is true.
4139 *
4140 * Returns 0 or 1 depending on the results of the test.
4141 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004142static int
Owen Taylor3473f882001-02-23 17:55:21 +00004143xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4144 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4145 if ((val == NULL) || (arg == NULL) ||
4146 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4147 return(0);
4148
4149 switch(val->type) {
4150 case XPATH_NUMBER:
4151 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4152 case XPATH_NODESET:
4153 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004154 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004155 case XPATH_STRING:
4156 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4157 case XPATH_BOOLEAN:
4158 valuePush(ctxt, arg);
4159 xmlXPathBooleanFunction(ctxt, 1);
4160 valuePush(ctxt, val);
4161 return(xmlXPathCompareValues(ctxt, inf, strict));
4162 default:
4163 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004164 }
4165 return(0);
4166}
4167
4168/**
4169 * xmlXPathEqualNodeSetString
4170 * @arg: the nodeset object argument
4171 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004172 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004173 *
4174 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4175 * If one object to be compared is a node-set and the other is a string,
4176 * then the comparison will be true if and only if there is a node in
4177 * the node-set such that the result of performing the comparison on the
4178 * string-value of the node and the other string is true.
4179 *
4180 * Returns 0 or 1 depending on the results of the test.
4181 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004182static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004183xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004184{
Owen Taylor3473f882001-02-23 17:55:21 +00004185 int i;
4186 xmlNodeSetPtr ns;
4187 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004188 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004189
4190 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004191 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4192 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004193 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004194 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004195 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004196 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004197 if (ns->nodeNr <= 0) {
4198 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004199 return(neq ^ 1);
4200 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004201 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004202 for (i = 0; i < ns->nodeNr; i++) {
4203 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4204 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4205 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4206 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004207 if (neq)
4208 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004209 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004210 } else if (neq) {
4211 if (str2 != NULL)
4212 xmlFree(str2);
4213 return (1);
4214 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004215 if (str2 != NULL)
4216 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004217 } else if (neq)
4218 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004219 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004220 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004221}
4222
4223/**
4224 * xmlXPathEqualNodeSetFloat
4225 * @arg: the nodeset object argument
4226 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004227 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004228 *
4229 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4230 * If one object to be compared is a node-set and the other is a number,
4231 * then the comparison will be true if and only if there is a node in
4232 * the node-set such that the result of performing the comparison on the
4233 * number to be compared and on the result of converting the string-value
4234 * of that node to a number using the number function is true.
4235 *
4236 * Returns 0 or 1 depending on the results of the test.
4237 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004238static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004239xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4240 xmlXPathObjectPtr arg, double f, int neq) {
4241 int i, ret=0;
4242 xmlNodeSetPtr ns;
4243 xmlChar *str2;
4244 xmlXPathObjectPtr val;
4245 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004246
4247 if ((arg == NULL) ||
4248 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4249 return(0);
4250
William M. Brack0c022ad2002-07-12 00:56:01 +00004251 ns = arg->nodesetval;
4252 if (ns != NULL) {
4253 for (i=0;i<ns->nodeNr;i++) {
4254 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4255 if (str2 != NULL) {
4256 valuePush(ctxt, xmlXPathNewString(str2));
4257 xmlFree(str2);
4258 xmlXPathNumberFunction(ctxt, 1);
4259 val = valuePop(ctxt);
4260 v = val->floatval;
4261 xmlXPathFreeObject(val);
4262 if (!xmlXPathIsNaN(v)) {
4263 if ((!neq) && (v==f)) {
4264 ret = 1;
4265 break;
4266 } else if ((neq) && (v!=f)) {
4267 ret = 1;
4268 break;
4269 }
4270 }
4271 }
4272 }
4273 }
4274
4275 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004276}
4277
4278
4279/**
4280 * xmlXPathEqualNodeSets
4281 * @arg1: first nodeset object argument
4282 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004283 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004284 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004285 * Implement the equal / not equal operation on XPath nodesets:
4286 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004287 * If both objects to be compared are node-sets, then the comparison
4288 * will be true if and only if there is a node in the first node-set and
4289 * a node in the second node-set such that the result of performing the
4290 * comparison on the string-values of the two nodes is true.
4291 *
4292 * (needless to say, this is a costly operation)
4293 *
4294 * Returns 0 or 1 depending on the results of the test.
4295 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004296static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004297xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004298 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004299 unsigned int *hashs1;
4300 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004301 xmlChar **values1;
4302 xmlChar **values2;
4303 int ret = 0;
4304 xmlNodeSetPtr ns1;
4305 xmlNodeSetPtr ns2;
4306
4307 if ((arg1 == NULL) ||
4308 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4309 return(0);
4310 if ((arg2 == NULL) ||
4311 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4312 return(0);
4313
4314 ns1 = arg1->nodesetval;
4315 ns2 = arg2->nodesetval;
4316
Daniel Veillard911f49a2001-04-07 15:39:35 +00004317 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004318 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004319 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004320 return(0);
4321
4322 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004323 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004324 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004325 if (neq == 0)
4326 for (i = 0;i < ns1->nodeNr;i++)
4327 for (j = 0;j < ns2->nodeNr;j++)
4328 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4329 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004330
4331 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4332 if (values1 == NULL)
4333 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004334 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4335 if (hashs1 == NULL) {
4336 xmlFree(values1);
4337 return(0);
4338 }
Owen Taylor3473f882001-02-23 17:55:21 +00004339 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4340 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4341 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004342 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004343 xmlFree(values1);
4344 return(0);
4345 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004346 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4347 if (hashs2 == NULL) {
4348 xmlFree(hashs1);
4349 xmlFree(values1);
4350 xmlFree(values2);
4351 return(0);
4352 }
Owen Taylor3473f882001-02-23 17:55:21 +00004353 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4354 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004355 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004356 for (j = 0;j < ns2->nodeNr;j++) {
4357 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004358 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004359 if (hashs1[i] != hashs2[j]) {
4360 if (neq) {
4361 ret = 1;
4362 break;
4363 }
4364 }
4365 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004366 if (values1[i] == NULL)
4367 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4368 if (values2[j] == NULL)
4369 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004370 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004371 if (ret)
4372 break;
4373 }
Owen Taylor3473f882001-02-23 17:55:21 +00004374 }
4375 if (ret)
4376 break;
4377 }
4378 for (i = 0;i < ns1->nodeNr;i++)
4379 if (values1[i] != NULL)
4380 xmlFree(values1[i]);
4381 for (j = 0;j < ns2->nodeNr;j++)
4382 if (values2[j] != NULL)
4383 xmlFree(values2[j]);
4384 xmlFree(values1);
4385 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004386 xmlFree(hashs1);
4387 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004388 return(ret);
4389}
4390
William M. Brack0c022ad2002-07-12 00:56:01 +00004391static int
4392xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4393 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004394 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004395 /*
4396 *At this point we are assured neither arg1 nor arg2
4397 *is a nodeset, so we can just pick the appropriate routine.
4398 */
Owen Taylor3473f882001-02-23 17:55:21 +00004399 switch (arg1->type) {
4400 case XPATH_UNDEFINED:
4401#ifdef DEBUG_EXPR
4402 xmlGenericError(xmlGenericErrorContext,
4403 "Equal: undefined\n");
4404#endif
4405 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004406 case XPATH_BOOLEAN:
4407 switch (arg2->type) {
4408 case XPATH_UNDEFINED:
4409#ifdef DEBUG_EXPR
4410 xmlGenericError(xmlGenericErrorContext,
4411 "Equal: undefined\n");
4412#endif
4413 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004414 case XPATH_BOOLEAN:
4415#ifdef DEBUG_EXPR
4416 xmlGenericError(xmlGenericErrorContext,
4417 "Equal: %d boolean %d \n",
4418 arg1->boolval, arg2->boolval);
4419#endif
4420 ret = (arg1->boolval == arg2->boolval);
4421 break;
4422 case XPATH_NUMBER:
4423 if (arg2->floatval) ret = 1;
4424 else ret = 0;
4425 ret = (arg1->boolval == ret);
4426 break;
4427 case XPATH_STRING:
4428 if ((arg2->stringval == NULL) ||
4429 (arg2->stringval[0] == 0)) ret = 0;
4430 else
4431 ret = 1;
4432 ret = (arg1->boolval == ret);
4433 break;
4434 case XPATH_USERS:
4435 case XPATH_POINT:
4436 case XPATH_RANGE:
4437 case XPATH_LOCATIONSET:
4438 TODO
4439 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004440 case XPATH_NODESET:
4441 case XPATH_XSLT_TREE:
4442 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004443 }
4444 break;
4445 case XPATH_NUMBER:
4446 switch (arg2->type) {
4447 case XPATH_UNDEFINED:
4448#ifdef DEBUG_EXPR
4449 xmlGenericError(xmlGenericErrorContext,
4450 "Equal: undefined\n");
4451#endif
4452 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004453 case XPATH_BOOLEAN:
4454 if (arg1->floatval) ret = 1;
4455 else ret = 0;
4456 ret = (arg2->boolval == ret);
4457 break;
4458 case XPATH_STRING:
4459 valuePush(ctxt, arg2);
4460 xmlXPathNumberFunction(ctxt, 1);
4461 arg2 = valuePop(ctxt);
4462 /* no break on purpose */
4463 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004464 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004465 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4466 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004467 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4468 if (xmlXPathIsInf(arg2->floatval) == 1)
4469 ret = 1;
4470 else
4471 ret = 0;
4472 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4473 if (xmlXPathIsInf(arg2->floatval) == -1)
4474 ret = 1;
4475 else
4476 ret = 0;
4477 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4478 if (xmlXPathIsInf(arg1->floatval) == 1)
4479 ret = 1;
4480 else
4481 ret = 0;
4482 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4483 if (xmlXPathIsInf(arg1->floatval) == -1)
4484 ret = 1;
4485 else
4486 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004487 } else {
4488 ret = (arg1->floatval == arg2->floatval);
4489 }
Owen Taylor3473f882001-02-23 17:55:21 +00004490 break;
4491 case XPATH_USERS:
4492 case XPATH_POINT:
4493 case XPATH_RANGE:
4494 case XPATH_LOCATIONSET:
4495 TODO
4496 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004497 case XPATH_NODESET:
4498 case XPATH_XSLT_TREE:
4499 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004500 }
4501 break;
4502 case XPATH_STRING:
4503 switch (arg2->type) {
4504 case XPATH_UNDEFINED:
4505#ifdef DEBUG_EXPR
4506 xmlGenericError(xmlGenericErrorContext,
4507 "Equal: undefined\n");
4508#endif
4509 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004510 case XPATH_BOOLEAN:
4511 if ((arg1->stringval == NULL) ||
4512 (arg1->stringval[0] == 0)) ret = 0;
4513 else
4514 ret = 1;
4515 ret = (arg2->boolval == ret);
4516 break;
4517 case XPATH_STRING:
4518 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4519 break;
4520 case XPATH_NUMBER:
4521 valuePush(ctxt, arg1);
4522 xmlXPathNumberFunction(ctxt, 1);
4523 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004524 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004525 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4526 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004527 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4528 if (xmlXPathIsInf(arg2->floatval) == 1)
4529 ret = 1;
4530 else
4531 ret = 0;
4532 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4533 if (xmlXPathIsInf(arg2->floatval) == -1)
4534 ret = 1;
4535 else
4536 ret = 0;
4537 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4538 if (xmlXPathIsInf(arg1->floatval) == 1)
4539 ret = 1;
4540 else
4541 ret = 0;
4542 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4543 if (xmlXPathIsInf(arg1->floatval) == -1)
4544 ret = 1;
4545 else
4546 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004547 } else {
4548 ret = (arg1->floatval == arg2->floatval);
4549 }
Owen Taylor3473f882001-02-23 17:55:21 +00004550 break;
4551 case XPATH_USERS:
4552 case XPATH_POINT:
4553 case XPATH_RANGE:
4554 case XPATH_LOCATIONSET:
4555 TODO
4556 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004557 case XPATH_NODESET:
4558 case XPATH_XSLT_TREE:
4559 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004560 }
4561 break;
4562 case XPATH_USERS:
4563 case XPATH_POINT:
4564 case XPATH_RANGE:
4565 case XPATH_LOCATIONSET:
4566 TODO
4567 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004568 case XPATH_NODESET:
4569 case XPATH_XSLT_TREE:
4570 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004571 }
4572 xmlXPathFreeObject(arg1);
4573 xmlXPathFreeObject(arg2);
4574 return(ret);
4575}
4576
William M. Brack0c022ad2002-07-12 00:56:01 +00004577/**
4578 * xmlXPathEqualValues:
4579 * @ctxt: the XPath Parser context
4580 *
4581 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4582 *
4583 * Returns 0 or 1 depending on the results of the test.
4584 */
4585int
4586xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4587 xmlXPathObjectPtr arg1, arg2, argtmp;
4588 int ret = 0;
4589
4590 arg2 = valuePop(ctxt);
4591 arg1 = valuePop(ctxt);
4592 if ((arg1 == NULL) || (arg2 == NULL)) {
4593 if (arg1 != NULL)
4594 xmlXPathFreeObject(arg1);
4595 else
4596 xmlXPathFreeObject(arg2);
4597 XP_ERROR0(XPATH_INVALID_OPERAND);
4598 }
4599
4600 if (arg1 == arg2) {
4601#ifdef DEBUG_EXPR
4602 xmlGenericError(xmlGenericErrorContext,
4603 "Equal: by pointer\n");
4604#endif
4605 return(1);
4606 }
4607
4608 /*
4609 *If either argument is a nodeset, it's a 'special case'
4610 */
4611 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4612 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4613 /*
4614 *Hack it to assure arg1 is the nodeset
4615 */
4616 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4617 argtmp = arg2;
4618 arg2 = arg1;
4619 arg1 = argtmp;
4620 }
4621 switch (arg2->type) {
4622 case XPATH_UNDEFINED:
4623#ifdef DEBUG_EXPR
4624 xmlGenericError(xmlGenericErrorContext,
4625 "Equal: undefined\n");
4626#endif
4627 break;
4628 case XPATH_NODESET:
4629 case XPATH_XSLT_TREE:
4630 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4631 break;
4632 case XPATH_BOOLEAN:
4633 if ((arg1->nodesetval == NULL) ||
4634 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4635 else
4636 ret = 1;
4637 ret = (ret == arg2->boolval);
4638 break;
4639 case XPATH_NUMBER:
4640 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4641 break;
4642 case XPATH_STRING:
4643 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4644 break;
4645 case XPATH_USERS:
4646 case XPATH_POINT:
4647 case XPATH_RANGE:
4648 case XPATH_LOCATIONSET:
4649 TODO
4650 break;
4651 }
4652 xmlXPathFreeObject(arg1);
4653 xmlXPathFreeObject(arg2);
4654 return(ret);
4655 }
4656
4657 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4658}
4659
4660/**
4661 * xmlXPathNotEqualValues:
4662 * @ctxt: the XPath Parser context
4663 *
4664 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4665 *
4666 * Returns 0 or 1 depending on the results of the test.
4667 */
4668int
4669xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4670 xmlXPathObjectPtr arg1, arg2, argtmp;
4671 int ret = 0;
4672
4673 arg2 = valuePop(ctxt);
4674 arg1 = valuePop(ctxt);
4675 if ((arg1 == NULL) || (arg2 == NULL)) {
4676 if (arg1 != NULL)
4677 xmlXPathFreeObject(arg1);
4678 else
4679 xmlXPathFreeObject(arg2);
4680 XP_ERROR0(XPATH_INVALID_OPERAND);
4681 }
4682
4683 if (arg1 == arg2) {
4684#ifdef DEBUG_EXPR
4685 xmlGenericError(xmlGenericErrorContext,
4686 "NotEqual: by pointer\n");
4687#endif
4688 return(0);
4689 }
4690
4691 /*
4692 *If either argument is a nodeset, it's a 'special case'
4693 */
4694 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4695 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4696 /*
4697 *Hack it to assure arg1 is the nodeset
4698 */
4699 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4700 argtmp = arg2;
4701 arg2 = arg1;
4702 arg1 = argtmp;
4703 }
4704 switch (arg2->type) {
4705 case XPATH_UNDEFINED:
4706#ifdef DEBUG_EXPR
4707 xmlGenericError(xmlGenericErrorContext,
4708 "NotEqual: undefined\n");
4709#endif
4710 break;
4711 case XPATH_NODESET:
4712 case XPATH_XSLT_TREE:
4713 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4714 break;
4715 case XPATH_BOOLEAN:
4716 if ((arg1->nodesetval == NULL) ||
4717 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4718 else
4719 ret = 1;
4720 ret = (ret == arg2->boolval);
4721 break;
4722 case XPATH_NUMBER:
4723 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4724 break;
4725 case XPATH_STRING:
4726 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4727 break;
4728 case XPATH_USERS:
4729 case XPATH_POINT:
4730 case XPATH_RANGE:
4731 case XPATH_LOCATIONSET:
4732 TODO
4733 break;
4734 }
4735 xmlXPathFreeObject(arg1);
4736 xmlXPathFreeObject(arg2);
4737 return(ret);
4738 }
4739
4740 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4741}
Owen Taylor3473f882001-02-23 17:55:21 +00004742
4743/**
4744 * xmlXPathCompareValues:
4745 * @ctxt: the XPath Parser context
4746 * @inf: less than (1) or greater than (0)
4747 * @strict: is the comparison strict
4748 *
4749 * Implement the compare operation on XPath objects:
4750 * @arg1 < @arg2 (1, 1, ...
4751 * @arg1 <= @arg2 (1, 0, ...
4752 * @arg1 > @arg2 (0, 1, ...
4753 * @arg1 >= @arg2 (0, 0, ...
4754 *
4755 * When neither object to be compared is a node-set and the operator is
4756 * <=, <, >=, >, then the objects are compared by converted both objects
4757 * to numbers and comparing the numbers according to IEEE 754. The <
4758 * comparison will be true if and only if the first number is less than the
4759 * second number. The <= comparison will be true if and only if the first
4760 * number is less than or equal to the second number. The > comparison
4761 * will be true if and only if the first number is greater than the second
4762 * number. The >= comparison will be true if and only if the first number
4763 * is greater than or equal to the second number.
4764 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004765 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004766 */
4767int
4768xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004769 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004770 xmlXPathObjectPtr arg1, arg2;
4771
William M. Brack0c022ad2002-07-12 00:56:01 +00004772 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004773 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004774 if ((arg1 == NULL) || (arg2 == NULL)) {
4775 if (arg1 != NULL)
4776 xmlXPathFreeObject(arg1);
4777 else
4778 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004779 XP_ERROR0(XPATH_INVALID_OPERAND);
4780 }
4781
William M. Brack0c022ad2002-07-12 00:56:01 +00004782 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4783 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4784 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4785 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004786 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004787 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004788 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004789 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4790 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004791 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004792 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4793 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004794 }
4795 }
4796 return(ret);
4797 }
4798
4799 if (arg1->type != XPATH_NUMBER) {
4800 valuePush(ctxt, arg1);
4801 xmlXPathNumberFunction(ctxt, 1);
4802 arg1 = valuePop(ctxt);
4803 }
4804 if (arg1->type != XPATH_NUMBER) {
4805 xmlXPathFreeObject(arg1);
4806 xmlXPathFreeObject(arg2);
4807 XP_ERROR0(XPATH_INVALID_OPERAND);
4808 }
4809 if (arg2->type != XPATH_NUMBER) {
4810 valuePush(ctxt, arg2);
4811 xmlXPathNumberFunction(ctxt, 1);
4812 arg2 = valuePop(ctxt);
4813 }
4814 if (arg2->type != XPATH_NUMBER) {
4815 xmlXPathFreeObject(arg1);
4816 xmlXPathFreeObject(arg2);
4817 XP_ERROR0(XPATH_INVALID_OPERAND);
4818 }
4819 /*
4820 * Add tests for infinity and nan
4821 * => feedback on 3.4 for Inf and NaN
4822 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004823 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004824 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004825 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004826 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004827 arg1i=xmlXPathIsInf(arg1->floatval);
4828 arg2i=xmlXPathIsInf(arg2->floatval);
4829 if (inf && strict) {
4830 if ((arg1i == -1 && arg2i != -1) ||
4831 (arg2i == 1 && arg1i != 1)) {
4832 ret = 1;
4833 } else if (arg1i == 0 && arg2i == 0) {
4834 ret = (arg1->floatval < arg2->floatval);
4835 } else {
4836 ret = 0;
4837 }
4838 }
4839 else if (inf && !strict) {
4840 if (arg1i == -1 || arg2i == 1) {
4841 ret = 1;
4842 } else if (arg1i == 0 && arg2i == 0) {
4843 ret = (arg1->floatval <= arg2->floatval);
4844 } else {
4845 ret = 0;
4846 }
4847 }
4848 else if (!inf && strict) {
4849 if ((arg1i == 1 && arg2i != 1) ||
4850 (arg2i == -1 && arg1i != -1)) {
4851 ret = 1;
4852 } else if (arg1i == 0 && arg2i == 0) {
4853 ret = (arg1->floatval > arg2->floatval);
4854 } else {
4855 ret = 0;
4856 }
4857 }
4858 else if (!inf && !strict) {
4859 if (arg1i == 1 || arg2i == -1) {
4860 ret = 1;
4861 } else if (arg1i == 0 && arg2i == 0) {
4862 ret = (arg1->floatval >= arg2->floatval);
4863 } else {
4864 ret = 0;
4865 }
4866 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004867 }
Owen Taylor3473f882001-02-23 17:55:21 +00004868 xmlXPathFreeObject(arg1);
4869 xmlXPathFreeObject(arg2);
4870 return(ret);
4871}
4872
4873/**
4874 * xmlXPathValueFlipSign:
4875 * @ctxt: the XPath Parser context
4876 *
4877 * Implement the unary - operation on an XPath object
4878 * The numeric operators convert their operands to numbers as if
4879 * by calling the number function.
4880 */
4881void
4882xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004883 CAST_TO_NUMBER;
4884 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004885 if (xmlXPathIsNaN(ctxt->value->floatval))
4886 ctxt->value->floatval=xmlXPathNAN;
4887 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4888 ctxt->value->floatval=xmlXPathNINF;
4889 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4890 ctxt->value->floatval=xmlXPathPINF;
4891 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004892 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4893 ctxt->value->floatval = xmlXPathNZERO;
4894 else
4895 ctxt->value->floatval = 0;
4896 }
4897 else
4898 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004899}
4900
4901/**
4902 * xmlXPathAddValues:
4903 * @ctxt: the XPath Parser context
4904 *
4905 * Implement the add operation on XPath objects:
4906 * The numeric operators convert their operands to numbers as if
4907 * by calling the number function.
4908 */
4909void
4910xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4911 xmlXPathObjectPtr arg;
4912 double val;
4913
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004914 arg = valuePop(ctxt);
4915 if (arg == NULL)
4916 XP_ERROR(XPATH_INVALID_OPERAND);
4917 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004918 xmlXPathFreeObject(arg);
4919
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004920 CAST_TO_NUMBER;
4921 CHECK_TYPE(XPATH_NUMBER);
4922 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004923}
4924
4925/**
4926 * xmlXPathSubValues:
4927 * @ctxt: the XPath Parser context
4928 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004929 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004930 * The numeric operators convert their operands to numbers as if
4931 * by calling the number function.
4932 */
4933void
4934xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4935 xmlXPathObjectPtr arg;
4936 double val;
4937
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004938 arg = valuePop(ctxt);
4939 if (arg == NULL)
4940 XP_ERROR(XPATH_INVALID_OPERAND);
4941 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004942 xmlXPathFreeObject(arg);
4943
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004944 CAST_TO_NUMBER;
4945 CHECK_TYPE(XPATH_NUMBER);
4946 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004947}
4948
4949/**
4950 * xmlXPathMultValues:
4951 * @ctxt: the XPath Parser context
4952 *
4953 * Implement the multiply operation on XPath objects:
4954 * The numeric operators convert their operands to numbers as if
4955 * by calling the number function.
4956 */
4957void
4958xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4959 xmlXPathObjectPtr arg;
4960 double val;
4961
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004962 arg = valuePop(ctxt);
4963 if (arg == NULL)
4964 XP_ERROR(XPATH_INVALID_OPERAND);
4965 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004966 xmlXPathFreeObject(arg);
4967
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004968 CAST_TO_NUMBER;
4969 CHECK_TYPE(XPATH_NUMBER);
4970 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004971}
4972
4973/**
4974 * xmlXPathDivValues:
4975 * @ctxt: the XPath Parser context
4976 *
4977 * Implement the div operation on XPath objects @arg1 / @arg2:
4978 * The numeric operators convert their operands to numbers as if
4979 * by calling the number function.
4980 */
4981void
4982xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4983 xmlXPathObjectPtr arg;
4984 double val;
4985
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004986 arg = valuePop(ctxt);
4987 if (arg == NULL)
4988 XP_ERROR(XPATH_INVALID_OPERAND);
4989 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004990 xmlXPathFreeObject(arg);
4991
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004992 CAST_TO_NUMBER;
4993 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004994 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
4995 ctxt->value->floatval = xmlXPathNAN;
4996 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004997 if (ctxt->value->floatval == 0)
4998 ctxt->value->floatval = xmlXPathNAN;
4999 else if (ctxt->value->floatval > 0)
5000 ctxt->value->floatval = xmlXPathNINF;
5001 else if (ctxt->value->floatval < 0)
5002 ctxt->value->floatval = xmlXPathPINF;
5003 }
5004 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005005 if (ctxt->value->floatval == 0)
5006 ctxt->value->floatval = xmlXPathNAN;
5007 else if (ctxt->value->floatval > 0)
5008 ctxt->value->floatval = xmlXPathPINF;
5009 else if (ctxt->value->floatval < 0)
5010 ctxt->value->floatval = xmlXPathNINF;
5011 } else
5012 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005013}
5014
5015/**
5016 * xmlXPathModValues:
5017 * @ctxt: the XPath Parser context
5018 *
5019 * Implement the mod operation on XPath objects: @arg1 / @arg2
5020 * The numeric operators convert their operands to numbers as if
5021 * by calling the number function.
5022 */
5023void
5024xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5025 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005026 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005027
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005028 arg = valuePop(ctxt);
5029 if (arg == NULL)
5030 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005031 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005032 xmlXPathFreeObject(arg);
5033
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005034 CAST_TO_NUMBER;
5035 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005036 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005037 if (arg2 == 0)
5038 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005039 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005040 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005041 }
Owen Taylor3473f882001-02-23 17:55:21 +00005042}
5043
5044/************************************************************************
5045 * *
5046 * The traversal functions *
5047 * *
5048 ************************************************************************/
5049
Owen Taylor3473f882001-02-23 17:55:21 +00005050/*
5051 * A traversal function enumerates nodes along an axis.
5052 * Initially it must be called with NULL, and it indicates
5053 * termination on the axis by returning NULL.
5054 */
5055typedef xmlNodePtr (*xmlXPathTraversalFunction)
5056 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5057
5058/**
5059 * xmlXPathNextSelf:
5060 * @ctxt: the XPath Parser context
5061 * @cur: the current node in the traversal
5062 *
5063 * Traversal function for the "self" direction
5064 * The self axis contains just the context node itself
5065 *
5066 * Returns the next element following that axis
5067 */
5068xmlNodePtr
5069xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5070 if (cur == NULL)
5071 return(ctxt->context->node);
5072 return(NULL);
5073}
5074
5075/**
5076 * xmlXPathNextChild:
5077 * @ctxt: the XPath Parser context
5078 * @cur: the current node in the traversal
5079 *
5080 * Traversal function for the "child" direction
5081 * The child axis contains the children of the context node in document order.
5082 *
5083 * Returns the next element following that axis
5084 */
5085xmlNodePtr
5086xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5087 if (cur == NULL) {
5088 if (ctxt->context->node == NULL) return(NULL);
5089 switch (ctxt->context->node->type) {
5090 case XML_ELEMENT_NODE:
5091 case XML_TEXT_NODE:
5092 case XML_CDATA_SECTION_NODE:
5093 case XML_ENTITY_REF_NODE:
5094 case XML_ENTITY_NODE:
5095 case XML_PI_NODE:
5096 case XML_COMMENT_NODE:
5097 case XML_NOTATION_NODE:
5098 case XML_DTD_NODE:
5099 return(ctxt->context->node->children);
5100 case XML_DOCUMENT_NODE:
5101 case XML_DOCUMENT_TYPE_NODE:
5102 case XML_DOCUMENT_FRAG_NODE:
5103 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005104#ifdef LIBXML_DOCB_ENABLED
5105 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005106#endif
5107 return(((xmlDocPtr) ctxt->context->node)->children);
5108 case XML_ELEMENT_DECL:
5109 case XML_ATTRIBUTE_DECL:
5110 case XML_ENTITY_DECL:
5111 case XML_ATTRIBUTE_NODE:
5112 case XML_NAMESPACE_DECL:
5113 case XML_XINCLUDE_START:
5114 case XML_XINCLUDE_END:
5115 return(NULL);
5116 }
5117 return(NULL);
5118 }
5119 if ((cur->type == XML_DOCUMENT_NODE) ||
5120 (cur->type == XML_HTML_DOCUMENT_NODE))
5121 return(NULL);
5122 return(cur->next);
5123}
5124
5125/**
5126 * xmlXPathNextDescendant:
5127 * @ctxt: the XPath Parser context
5128 * @cur: the current node in the traversal
5129 *
5130 * Traversal function for the "descendant" direction
5131 * the descendant axis contains the descendants of the context node in document
5132 * order; a descendant is a child or a child of a child and so on.
5133 *
5134 * Returns the next element following that axis
5135 */
5136xmlNodePtr
5137xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5138 if (cur == NULL) {
5139 if (ctxt->context->node == NULL)
5140 return(NULL);
5141 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5142 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5143 return(NULL);
5144
5145 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5146 return(ctxt->context->doc->children);
5147 return(ctxt->context->node->children);
5148 }
5149
Daniel Veillard567e1b42001-08-01 15:53:47 +00005150 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005151 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00005152 return(cur->children);
5153 }
5154
5155 if (cur == ctxt->context->node) return(NULL);
5156
Owen Taylor3473f882001-02-23 17:55:21 +00005157 if (cur->next != NULL) return(cur->next);
5158
5159 do {
5160 cur = cur->parent;
5161 if (cur == NULL) return(NULL);
5162 if (cur == ctxt->context->node) return(NULL);
5163 if (cur->next != NULL) {
5164 cur = cur->next;
5165 return(cur);
5166 }
5167 } while (cur != NULL);
5168 return(cur);
5169}
5170
5171/**
5172 * xmlXPathNextDescendantOrSelf:
5173 * @ctxt: the XPath Parser context
5174 * @cur: the current node in the traversal
5175 *
5176 * Traversal function for the "descendant-or-self" direction
5177 * the descendant-or-self axis contains the context node and the descendants
5178 * of the context node in document order; thus the context node is the first
5179 * node on the axis, and the first child of the context node is the second node
5180 * on the axis
5181 *
5182 * Returns the next element following that axis
5183 */
5184xmlNodePtr
5185xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5186 if (cur == NULL) {
5187 if (ctxt->context->node == NULL)
5188 return(NULL);
5189 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5190 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5191 return(NULL);
5192 return(ctxt->context->node);
5193 }
5194
5195 return(xmlXPathNextDescendant(ctxt, cur));
5196}
5197
5198/**
5199 * xmlXPathNextParent:
5200 * @ctxt: the XPath Parser context
5201 * @cur: the current node in the traversal
5202 *
5203 * Traversal function for the "parent" direction
5204 * The parent axis contains the parent of the context node, if there is one.
5205 *
5206 * Returns the next element following that axis
5207 */
5208xmlNodePtr
5209xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5210 /*
5211 * the parent of an attribute or namespace node is the element
5212 * to which the attribute or namespace node is attached
5213 * Namespace handling !!!
5214 */
5215 if (cur == NULL) {
5216 if (ctxt->context->node == NULL) return(NULL);
5217 switch (ctxt->context->node->type) {
5218 case XML_ELEMENT_NODE:
5219 case XML_TEXT_NODE:
5220 case XML_CDATA_SECTION_NODE:
5221 case XML_ENTITY_REF_NODE:
5222 case XML_ENTITY_NODE:
5223 case XML_PI_NODE:
5224 case XML_COMMENT_NODE:
5225 case XML_NOTATION_NODE:
5226 case XML_DTD_NODE:
5227 case XML_ELEMENT_DECL:
5228 case XML_ATTRIBUTE_DECL:
5229 case XML_XINCLUDE_START:
5230 case XML_XINCLUDE_END:
5231 case XML_ENTITY_DECL:
5232 if (ctxt->context->node->parent == NULL)
5233 return((xmlNodePtr) ctxt->context->doc);
5234 return(ctxt->context->node->parent);
5235 case XML_ATTRIBUTE_NODE: {
5236 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5237
5238 return(att->parent);
5239 }
5240 case XML_DOCUMENT_NODE:
5241 case XML_DOCUMENT_TYPE_NODE:
5242 case XML_DOCUMENT_FRAG_NODE:
5243 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005244#ifdef LIBXML_DOCB_ENABLED
5245 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005246#endif
5247 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005248 case XML_NAMESPACE_DECL: {
5249 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5250
5251 if ((ns->next != NULL) &&
5252 (ns->next->type != XML_NAMESPACE_DECL))
5253 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005254 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005255 }
Owen Taylor3473f882001-02-23 17:55:21 +00005256 }
5257 }
5258 return(NULL);
5259}
5260
5261/**
5262 * xmlXPathNextAncestor:
5263 * @ctxt: the XPath Parser context
5264 * @cur: the current node in the traversal
5265 *
5266 * Traversal function for the "ancestor" direction
5267 * the ancestor axis contains the ancestors of the context node; the ancestors
5268 * of the context node consist of the parent of context node and the parent's
5269 * parent and so on; the nodes are ordered in reverse document order; thus the
5270 * parent is the first node on the axis, and the parent's parent is the second
5271 * node on the axis
5272 *
5273 * Returns the next element following that axis
5274 */
5275xmlNodePtr
5276xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5277 /*
5278 * the parent of an attribute or namespace node is the element
5279 * to which the attribute or namespace node is attached
5280 * !!!!!!!!!!!!!
5281 */
5282 if (cur == NULL) {
5283 if (ctxt->context->node == NULL) return(NULL);
5284 switch (ctxt->context->node->type) {
5285 case XML_ELEMENT_NODE:
5286 case XML_TEXT_NODE:
5287 case XML_CDATA_SECTION_NODE:
5288 case XML_ENTITY_REF_NODE:
5289 case XML_ENTITY_NODE:
5290 case XML_PI_NODE:
5291 case XML_COMMENT_NODE:
5292 case XML_DTD_NODE:
5293 case XML_ELEMENT_DECL:
5294 case XML_ATTRIBUTE_DECL:
5295 case XML_ENTITY_DECL:
5296 case XML_NOTATION_NODE:
5297 case XML_XINCLUDE_START:
5298 case XML_XINCLUDE_END:
5299 if (ctxt->context->node->parent == NULL)
5300 return((xmlNodePtr) ctxt->context->doc);
5301 return(ctxt->context->node->parent);
5302 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005303 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005304
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005305 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005306 }
5307 case XML_DOCUMENT_NODE:
5308 case XML_DOCUMENT_TYPE_NODE:
5309 case XML_DOCUMENT_FRAG_NODE:
5310 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005311#ifdef LIBXML_DOCB_ENABLED
5312 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005313#endif
5314 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005315 case XML_NAMESPACE_DECL: {
5316 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5317
5318 if ((ns->next != NULL) &&
5319 (ns->next->type != XML_NAMESPACE_DECL))
5320 return((xmlNodePtr) ns->next);
5321 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005322 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005323 }
Owen Taylor3473f882001-02-23 17:55:21 +00005324 }
5325 return(NULL);
5326 }
5327 if (cur == ctxt->context->doc->children)
5328 return((xmlNodePtr) ctxt->context->doc);
5329 if (cur == (xmlNodePtr) ctxt->context->doc)
5330 return(NULL);
5331 switch (cur->type) {
5332 case XML_ELEMENT_NODE:
5333 case XML_TEXT_NODE:
5334 case XML_CDATA_SECTION_NODE:
5335 case XML_ENTITY_REF_NODE:
5336 case XML_ENTITY_NODE:
5337 case XML_PI_NODE:
5338 case XML_COMMENT_NODE:
5339 case XML_NOTATION_NODE:
5340 case XML_DTD_NODE:
5341 case XML_ELEMENT_DECL:
5342 case XML_ATTRIBUTE_DECL:
5343 case XML_ENTITY_DECL:
5344 case XML_XINCLUDE_START:
5345 case XML_XINCLUDE_END:
5346 return(cur->parent);
5347 case XML_ATTRIBUTE_NODE: {
5348 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5349
5350 return(att->parent);
5351 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005352 case XML_NAMESPACE_DECL: {
5353 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5354
5355 if ((ns->next != NULL) &&
5356 (ns->next->type != XML_NAMESPACE_DECL))
5357 return((xmlNodePtr) ns->next);
5358 /* Bad, how did that namespace ended-up there ? */
5359 return(NULL);
5360 }
Owen Taylor3473f882001-02-23 17:55:21 +00005361 case XML_DOCUMENT_NODE:
5362 case XML_DOCUMENT_TYPE_NODE:
5363 case XML_DOCUMENT_FRAG_NODE:
5364 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005365#ifdef LIBXML_DOCB_ENABLED
5366 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005367#endif
5368 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005369 }
5370 return(NULL);
5371}
5372
5373/**
5374 * xmlXPathNextAncestorOrSelf:
5375 * @ctxt: the XPath Parser context
5376 * @cur: the current node in the traversal
5377 *
5378 * Traversal function for the "ancestor-or-self" direction
5379 * he ancestor-or-self axis contains the context node and ancestors of
5380 * the context node in reverse document order; thus the context node is
5381 * the first node on the axis, and the context node's parent the second;
5382 * parent here is defined the same as with the parent axis.
5383 *
5384 * Returns the next element following that axis
5385 */
5386xmlNodePtr
5387xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5388 if (cur == NULL)
5389 return(ctxt->context->node);
5390 return(xmlXPathNextAncestor(ctxt, cur));
5391}
5392
5393/**
5394 * xmlXPathNextFollowingSibling:
5395 * @ctxt: the XPath Parser context
5396 * @cur: the current node in the traversal
5397 *
5398 * Traversal function for the "following-sibling" direction
5399 * The following-sibling axis contains the following siblings of the context
5400 * node in document order.
5401 *
5402 * Returns the next element following that axis
5403 */
5404xmlNodePtr
5405xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5406 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5407 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5408 return(NULL);
5409 if (cur == (xmlNodePtr) ctxt->context->doc)
5410 return(NULL);
5411 if (cur == NULL)
5412 return(ctxt->context->node->next);
5413 return(cur->next);
5414}
5415
5416/**
5417 * xmlXPathNextPrecedingSibling:
5418 * @ctxt: the XPath Parser context
5419 * @cur: the current node in the traversal
5420 *
5421 * Traversal function for the "preceding-sibling" direction
5422 * The preceding-sibling axis contains the preceding siblings of the context
5423 * node in reverse document order; the first preceding sibling is first on the
5424 * axis; the sibling preceding that node is the second on the axis and so on.
5425 *
5426 * Returns the next element following that axis
5427 */
5428xmlNodePtr
5429xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5430 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5431 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5432 return(NULL);
5433 if (cur == (xmlNodePtr) ctxt->context->doc)
5434 return(NULL);
5435 if (cur == NULL)
5436 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005437 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5438 cur = cur->prev;
5439 if (cur == NULL)
5440 return(ctxt->context->node->prev);
5441 }
Owen Taylor3473f882001-02-23 17:55:21 +00005442 return(cur->prev);
5443}
5444
5445/**
5446 * xmlXPathNextFollowing:
5447 * @ctxt: the XPath Parser context
5448 * @cur: the current node in the traversal
5449 *
5450 * Traversal function for the "following" direction
5451 * The following axis contains all nodes in the same document as the context
5452 * node that are after the context node in document order, excluding any
5453 * descendants and excluding attribute nodes and namespace nodes; the nodes
5454 * are ordered in document order
5455 *
5456 * Returns the next element following that axis
5457 */
5458xmlNodePtr
5459xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5460 if (cur != NULL && cur->children != NULL)
5461 return cur->children ;
5462 if (cur == NULL) cur = ctxt->context->node;
5463 if (cur == NULL) return(NULL) ; /* ERROR */
5464 if (cur->next != NULL) return(cur->next) ;
5465 do {
5466 cur = cur->parent;
5467 if (cur == NULL) return(NULL);
5468 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5469 if (cur->next != NULL) return(cur->next);
5470 } while (cur != NULL);
5471 return(cur);
5472}
5473
5474/*
5475 * xmlXPathIsAncestor:
5476 * @ancestor: the ancestor node
5477 * @node: the current node
5478 *
5479 * Check that @ancestor is a @node's ancestor
5480 *
5481 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5482 */
5483static int
5484xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5485 if ((ancestor == NULL) || (node == NULL)) return(0);
5486 /* nodes need to be in the same document */
5487 if (ancestor->doc != node->doc) return(0);
5488 /* avoid searching if ancestor or node is the root node */
5489 if (ancestor == (xmlNodePtr) node->doc) return(1);
5490 if (node == (xmlNodePtr) ancestor->doc) return(0);
5491 while (node->parent != NULL) {
5492 if (node->parent == ancestor)
5493 return(1);
5494 node = node->parent;
5495 }
5496 return(0);
5497}
5498
5499/**
5500 * xmlXPathNextPreceding:
5501 * @ctxt: the XPath Parser context
5502 * @cur: the current node in the traversal
5503 *
5504 * Traversal function for the "preceding" direction
5505 * the preceding axis contains all nodes in the same document as the context
5506 * node that are before the context node in document order, excluding any
5507 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5508 * ordered in reverse document order
5509 *
5510 * Returns the next element following that axis
5511 */
5512xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005513xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5514{
Owen Taylor3473f882001-02-23 17:55:21 +00005515 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005516 cur = ctxt->context->node;
5517 if (cur == NULL)
5518 return (NULL);
5519 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5520 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005521 do {
5522 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005523 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5524 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005525 }
5526
5527 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005528 if (cur == NULL)
5529 return (NULL);
5530 if (cur == ctxt->context->doc->children)
5531 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005532 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005533 return (cur);
5534}
5535
5536/**
5537 * xmlXPathNextPrecedingInternal:
5538 * @ctxt: the XPath Parser context
5539 * @cur: the current node in the traversal
5540 *
5541 * Traversal function for the "preceding" direction
5542 * the preceding axis contains all nodes in the same document as the context
5543 * node that are before the context node in document order, excluding any
5544 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5545 * ordered in reverse document order
5546 * This is a faster implementation but internal only since it requires a
5547 * state kept in the parser context: ctxt->ancestor.
5548 *
5549 * Returns the next element following that axis
5550 */
5551static xmlNodePtr
5552xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5553 xmlNodePtr cur)
5554{
5555 if (cur == NULL) {
5556 cur = ctxt->context->node;
5557 if (cur == NULL)
5558 return (NULL);
5559 ctxt->ancestor = cur->parent;
5560 }
5561 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5562 cur = cur->prev;
5563 while (cur->prev == NULL) {
5564 cur = cur->parent;
5565 if (cur == NULL)
5566 return (NULL);
5567 if (cur == ctxt->context->doc->children)
5568 return (NULL);
5569 if (cur != ctxt->ancestor)
5570 return (cur);
5571 ctxt->ancestor = cur->parent;
5572 }
5573 cur = cur->prev;
5574 while (cur->last != NULL)
5575 cur = cur->last;
5576 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005577}
5578
5579/**
5580 * xmlXPathNextNamespace:
5581 * @ctxt: the XPath Parser context
5582 * @cur: the current attribute in the traversal
5583 *
5584 * Traversal function for the "namespace" direction
5585 * the namespace axis contains the namespace nodes of the context node;
5586 * the order of nodes on this axis is implementation-defined; the axis will
5587 * be empty unless the context node is an element
5588 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005589 * We keep the XML namespace node at the end of the list.
5590 *
Owen Taylor3473f882001-02-23 17:55:21 +00005591 * Returns the next element following that axis
5592 */
5593xmlNodePtr
5594xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5595 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005596 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005597 if (ctxt->context->tmpNsList != NULL)
5598 xmlFree(ctxt->context->tmpNsList);
5599 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005600 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005601 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005602 if (ctxt->context->tmpNsList != NULL) {
5603 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5604 ctxt->context->tmpNsNr++;
5605 }
5606 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005607 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005608 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005609 if (ctxt->context->tmpNsNr > 0) {
5610 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5611 } else {
5612 if (ctxt->context->tmpNsList != NULL)
5613 xmlFree(ctxt->context->tmpNsList);
5614 ctxt->context->tmpNsList = NULL;
5615 return(NULL);
5616 }
Owen Taylor3473f882001-02-23 17:55:21 +00005617}
5618
5619/**
5620 * xmlXPathNextAttribute:
5621 * @ctxt: the XPath Parser context
5622 * @cur: the current attribute in the traversal
5623 *
5624 * Traversal function for the "attribute" direction
5625 * TODO: support DTD inherited default attributes
5626 *
5627 * Returns the next element following that axis
5628 */
5629xmlNodePtr
5630xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005631 if (ctxt->context->node == NULL)
5632 return(NULL);
5633 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5634 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005635 if (cur == NULL) {
5636 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5637 return(NULL);
5638 return((xmlNodePtr)ctxt->context->node->properties);
5639 }
5640 return((xmlNodePtr)cur->next);
5641}
5642
5643/************************************************************************
5644 * *
5645 * NodeTest Functions *
5646 * *
5647 ************************************************************************/
5648
Owen Taylor3473f882001-02-23 17:55:21 +00005649#define IS_FUNCTION 200
5650
Owen Taylor3473f882001-02-23 17:55:21 +00005651
5652/************************************************************************
5653 * *
5654 * Implicit tree core function library *
5655 * *
5656 ************************************************************************/
5657
5658/**
5659 * xmlXPathRoot:
5660 * @ctxt: the XPath Parser context
5661 *
5662 * Initialize the context to the root of the document
5663 */
5664void
5665xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5666 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5667 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5668}
5669
5670/************************************************************************
5671 * *
5672 * The explicit core function library *
5673 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5674 * *
5675 ************************************************************************/
5676
5677
5678/**
5679 * xmlXPathLastFunction:
5680 * @ctxt: the XPath Parser context
5681 * @nargs: the number of arguments
5682 *
5683 * Implement the last() XPath function
5684 * number last()
5685 * The last function returns the number of nodes in the context node list.
5686 */
5687void
5688xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5689 CHECK_ARITY(0);
5690 if (ctxt->context->contextSize >= 0) {
5691 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5692#ifdef DEBUG_EXPR
5693 xmlGenericError(xmlGenericErrorContext,
5694 "last() : %d\n", ctxt->context->contextSize);
5695#endif
5696 } else {
5697 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5698 }
5699}
5700
5701/**
5702 * xmlXPathPositionFunction:
5703 * @ctxt: the XPath Parser context
5704 * @nargs: the number of arguments
5705 *
5706 * Implement the position() XPath function
5707 * number position()
5708 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005709 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005710 * will be equal to last().
5711 */
5712void
5713xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5714 CHECK_ARITY(0);
5715 if (ctxt->context->proximityPosition >= 0) {
5716 valuePush(ctxt,
5717 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5718#ifdef DEBUG_EXPR
5719 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5720 ctxt->context->proximityPosition);
5721#endif
5722 } else {
5723 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5724 }
5725}
5726
5727/**
5728 * xmlXPathCountFunction:
5729 * @ctxt: the XPath Parser context
5730 * @nargs: the number of arguments
5731 *
5732 * Implement the count() XPath function
5733 * number count(node-set)
5734 */
5735void
5736xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5737 xmlXPathObjectPtr cur;
5738
5739 CHECK_ARITY(1);
5740 if ((ctxt->value == NULL) ||
5741 ((ctxt->value->type != XPATH_NODESET) &&
5742 (ctxt->value->type != XPATH_XSLT_TREE)))
5743 XP_ERROR(XPATH_INVALID_TYPE);
5744 cur = valuePop(ctxt);
5745
Daniel Veillard911f49a2001-04-07 15:39:35 +00005746 if ((cur == NULL) || (cur->nodesetval == NULL))
5747 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005748 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005749 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005750 } else {
5751 if ((cur->nodesetval->nodeNr != 1) ||
5752 (cur->nodesetval->nodeTab == NULL)) {
5753 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5754 } else {
5755 xmlNodePtr tmp;
5756 int i = 0;
5757
5758 tmp = cur->nodesetval->nodeTab[0];
5759 if (tmp != NULL) {
5760 tmp = tmp->children;
5761 while (tmp != NULL) {
5762 tmp = tmp->next;
5763 i++;
5764 }
5765 }
5766 valuePush(ctxt, xmlXPathNewFloat((double) i));
5767 }
5768 }
Owen Taylor3473f882001-02-23 17:55:21 +00005769 xmlXPathFreeObject(cur);
5770}
5771
5772/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005773 * xmlXPathGetElementsByIds:
5774 * @doc: the document
5775 * @ids: a whitespace separated list of IDs
5776 *
5777 * Selects elements by their unique ID.
5778 *
5779 * Returns a node-set of selected elements.
5780 */
5781static xmlNodeSetPtr
5782xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5783 xmlNodeSetPtr ret;
5784 const xmlChar *cur = ids;
5785 xmlChar *ID;
5786 xmlAttrPtr attr;
5787 xmlNodePtr elem = NULL;
5788
5789 ret = xmlXPathNodeSetCreate(NULL);
5790
5791 while (IS_BLANK(*cur)) cur++;
5792 while (*cur != 0) {
5793 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5794 (*cur == '.') || (*cur == '-') ||
5795 (*cur == '_') || (*cur == ':') ||
5796 (IS_COMBINING(*cur)) ||
5797 (IS_EXTENDER(*cur)))
5798 cur++;
5799
5800 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5801
5802 ID = xmlStrndup(ids, cur - ids);
5803 attr = xmlGetID(doc, ID);
5804 if (attr != NULL) {
5805 elem = attr->parent;
5806 xmlXPathNodeSetAdd(ret, elem);
5807 }
5808 if (ID != NULL)
5809 xmlFree(ID);
5810
5811 while (IS_BLANK(*cur)) cur++;
5812 ids = cur;
5813 }
5814 return(ret);
5815}
5816
5817/**
Owen Taylor3473f882001-02-23 17:55:21 +00005818 * xmlXPathIdFunction:
5819 * @ctxt: the XPath Parser context
5820 * @nargs: the number of arguments
5821 *
5822 * Implement the id() XPath function
5823 * node-set id(object)
5824 * The id function selects elements by their unique ID
5825 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5826 * then the result is the union of the result of applying id to the
5827 * string value of each of the nodes in the argument node-set. When the
5828 * argument to id is of any other type, the argument is converted to a
5829 * string as if by a call to the string function; the string is split
5830 * into a whitespace-separated list of tokens (whitespace is any sequence
5831 * of characters matching the production S); the result is a node-set
5832 * containing the elements in the same document as the context node that
5833 * have a unique ID equal to any of the tokens in the list.
5834 */
5835void
5836xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005837 xmlChar *tokens;
5838 xmlNodeSetPtr ret;
5839 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005840
5841 CHECK_ARITY(1);
5842 obj = valuePop(ctxt);
5843 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005844 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005845 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005846 int i;
5847
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005848 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005849
Daniel Veillard911f49a2001-04-07 15:39:35 +00005850 if (obj->nodesetval != NULL) {
5851 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005852 tokens =
5853 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5854 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5855 ret = xmlXPathNodeSetMerge(ret, ns);
5856 xmlXPathFreeNodeSet(ns);
5857 if (tokens != NULL)
5858 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005859 }
Owen Taylor3473f882001-02-23 17:55:21 +00005860 }
5861
5862 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005863 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005864 return;
5865 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005866 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005867
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005868 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5869 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005870
Owen Taylor3473f882001-02-23 17:55:21 +00005871 xmlXPathFreeObject(obj);
5872 return;
5873}
5874
5875/**
5876 * xmlXPathLocalNameFunction:
5877 * @ctxt: the XPath Parser context
5878 * @nargs: the number of arguments
5879 *
5880 * Implement the local-name() XPath function
5881 * string local-name(node-set?)
5882 * The local-name function returns a string containing the local part
5883 * of the name of the node in the argument node-set that is first in
5884 * document order. If the node-set is empty or the first node has no
5885 * name, an empty string is returned. If the argument is omitted it
5886 * defaults to the context node.
5887 */
5888void
5889xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5890 xmlXPathObjectPtr cur;
5891
5892 if (nargs == 0) {
5893 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5894 nargs = 1;
5895 }
5896
5897 CHECK_ARITY(1);
5898 if ((ctxt->value == NULL) ||
5899 ((ctxt->value->type != XPATH_NODESET) &&
5900 (ctxt->value->type != XPATH_XSLT_TREE)))
5901 XP_ERROR(XPATH_INVALID_TYPE);
5902 cur = valuePop(ctxt);
5903
Daniel Veillard911f49a2001-04-07 15:39:35 +00005904 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005905 valuePush(ctxt, xmlXPathNewCString(""));
5906 } else {
5907 int i = 0; /* Should be first in document order !!!!! */
5908 switch (cur->nodesetval->nodeTab[i]->type) {
5909 case XML_ELEMENT_NODE:
5910 case XML_ATTRIBUTE_NODE:
5911 case XML_PI_NODE:
5912 valuePush(ctxt,
5913 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5914 break;
5915 case XML_NAMESPACE_DECL:
5916 valuePush(ctxt, xmlXPathNewString(
5917 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5918 break;
5919 default:
5920 valuePush(ctxt, xmlXPathNewCString(""));
5921 }
5922 }
5923 xmlXPathFreeObject(cur);
5924}
5925
5926/**
5927 * xmlXPathNamespaceURIFunction:
5928 * @ctxt: the XPath Parser context
5929 * @nargs: the number of arguments
5930 *
5931 * Implement the namespace-uri() XPath function
5932 * string namespace-uri(node-set?)
5933 * The namespace-uri function returns a string containing the
5934 * namespace URI of the expanded name of the node in the argument
5935 * node-set that is first in document order. If the node-set is empty,
5936 * the first node has no name, or the expanded name has no namespace
5937 * URI, an empty string is returned. If the argument is omitted it
5938 * defaults to the context node.
5939 */
5940void
5941xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5942 xmlXPathObjectPtr cur;
5943
5944 if (nargs == 0) {
5945 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5946 nargs = 1;
5947 }
5948 CHECK_ARITY(1);
5949 if ((ctxt->value == NULL) ||
5950 ((ctxt->value->type != XPATH_NODESET) &&
5951 (ctxt->value->type != XPATH_XSLT_TREE)))
5952 XP_ERROR(XPATH_INVALID_TYPE);
5953 cur = valuePop(ctxt);
5954
Daniel Veillard911f49a2001-04-07 15:39:35 +00005955 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005956 valuePush(ctxt, xmlXPathNewCString(""));
5957 } else {
5958 int i = 0; /* Should be first in document order !!!!! */
5959 switch (cur->nodesetval->nodeTab[i]->type) {
5960 case XML_ELEMENT_NODE:
5961 case XML_ATTRIBUTE_NODE:
5962 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5963 valuePush(ctxt, xmlXPathNewCString(""));
5964 else
5965 valuePush(ctxt, xmlXPathNewString(
5966 cur->nodesetval->nodeTab[i]->ns->href));
5967 break;
5968 default:
5969 valuePush(ctxt, xmlXPathNewCString(""));
5970 }
5971 }
5972 xmlXPathFreeObject(cur);
5973}
5974
5975/**
5976 * xmlXPathNameFunction:
5977 * @ctxt: the XPath Parser context
5978 * @nargs: the number of arguments
5979 *
5980 * Implement the name() XPath function
5981 * string name(node-set?)
5982 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005983 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005984 * order. The QName must represent the name with respect to the namespace
5985 * declarations in effect on the node whose name is being represented.
5986 * Typically, this will be the form in which the name occurred in the XML
5987 * source. This need not be the case if there are namespace declarations
5988 * in effect on the node that associate multiple prefixes with the same
5989 * namespace. However, an implementation may include information about
5990 * the original prefix in its representation of nodes; in this case, an
5991 * implementation can ensure that the returned string is always the same
5992 * as the QName used in the XML source. If the argument it omitted it
5993 * defaults to the context node.
5994 * Libxml keep the original prefix so the "real qualified name" used is
5995 * returned.
5996 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005997static void
Daniel Veillard04383752001-07-08 14:27:15 +00005998xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5999{
Owen Taylor3473f882001-02-23 17:55:21 +00006000 xmlXPathObjectPtr cur;
6001
6002 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006003 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6004 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006005 }
6006
6007 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006008 if ((ctxt->value == NULL) ||
6009 ((ctxt->value->type != XPATH_NODESET) &&
6010 (ctxt->value->type != XPATH_XSLT_TREE)))
6011 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006012 cur = valuePop(ctxt);
6013
Daniel Veillard911f49a2001-04-07 15:39:35 +00006014 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006015 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006016 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006017 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006018
Daniel Veillard04383752001-07-08 14:27:15 +00006019 switch (cur->nodesetval->nodeTab[i]->type) {
6020 case XML_ELEMENT_NODE:
6021 case XML_ATTRIBUTE_NODE:
6022 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6023 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
6024 valuePush(ctxt,
6025 xmlXPathNewString(cur->nodesetval->
6026 nodeTab[i]->name));
6027
6028 else {
6029 char name[2000];
6030
6031 snprintf(name, sizeof(name), "%s:%s",
6032 (char *) cur->nodesetval->nodeTab[i]->ns->
6033 prefix,
6034 (char *) cur->nodesetval->nodeTab[i]->name);
6035 name[sizeof(name) - 1] = 0;
6036 valuePush(ctxt, xmlXPathNewCString(name));
6037 }
6038 break;
6039 default:
6040 valuePush(ctxt,
6041 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6042 xmlXPathLocalNameFunction(ctxt, 1);
6043 }
Owen Taylor3473f882001-02-23 17:55:21 +00006044 }
6045 xmlXPathFreeObject(cur);
6046}
6047
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006048
6049/**
Owen Taylor3473f882001-02-23 17:55:21 +00006050 * xmlXPathStringFunction:
6051 * @ctxt: the XPath Parser context
6052 * @nargs: the number of arguments
6053 *
6054 * Implement the string() XPath function
6055 * string string(object?)
6056 * he string function converts an object to a string as follows:
6057 * - A node-set is converted to a string by returning the value of
6058 * the node in the node-set that is first in document order.
6059 * If the node-set is empty, an empty string is returned.
6060 * - A number is converted to a string as follows
6061 * + NaN is converted to the string NaN
6062 * + positive zero is converted to the string 0
6063 * + negative zero is converted to the string 0
6064 * + positive infinity is converted to the string Infinity
6065 * + negative infinity is converted to the string -Infinity
6066 * + if the number is an integer, the number is represented in
6067 * decimal form as a Number with no decimal point and no leading
6068 * zeros, preceded by a minus sign (-) if the number is negative
6069 * + otherwise, the number is represented in decimal form as a
6070 * Number including a decimal point with at least one digit
6071 * before the decimal point and at least one digit after the
6072 * decimal point, preceded by a minus sign (-) if the number
6073 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006074 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006075 * before the decimal point; beyond the one required digit
6076 * after the decimal point there must be as many, but only as
6077 * many, more digits as are needed to uniquely distinguish the
6078 * number from all other IEEE 754 numeric values.
6079 * - The boolean false value is converted to the string false.
6080 * The boolean true value is converted to the string true.
6081 *
6082 * If the argument is omitted, it defaults to a node-set with the
6083 * context node as its only member.
6084 */
6085void
6086xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6087 xmlXPathObjectPtr cur;
6088
6089 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006090 valuePush(ctxt,
6091 xmlXPathWrapString(
6092 xmlXPathCastNodeToString(ctxt->context->node)));
6093 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006094 }
6095
6096 CHECK_ARITY(1);
6097 cur = valuePop(ctxt);
6098 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006099 cur = xmlXPathConvertString(cur);
6100 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006101}
6102
6103/**
6104 * xmlXPathStringLengthFunction:
6105 * @ctxt: the XPath Parser context
6106 * @nargs: the number of arguments
6107 *
6108 * Implement the string-length() XPath function
6109 * number string-length(string?)
6110 * The string-length returns the number of characters in the string
6111 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6112 * the context node converted to a string, in other words the value
6113 * of the context node.
6114 */
6115void
6116xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6117 xmlXPathObjectPtr cur;
6118
6119 if (nargs == 0) {
6120 if (ctxt->context->node == NULL) {
6121 valuePush(ctxt, xmlXPathNewFloat(0));
6122 } else {
6123 xmlChar *content;
6124
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006125 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006126 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006127 xmlFree(content);
6128 }
6129 return;
6130 }
6131 CHECK_ARITY(1);
6132 CAST_TO_STRING;
6133 CHECK_TYPE(XPATH_STRING);
6134 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006135 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006136 xmlXPathFreeObject(cur);
6137}
6138
6139/**
6140 * xmlXPathConcatFunction:
6141 * @ctxt: the XPath Parser context
6142 * @nargs: the number of arguments
6143 *
6144 * Implement the concat() XPath function
6145 * string concat(string, string, string*)
6146 * The concat function returns the concatenation of its arguments.
6147 */
6148void
6149xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6150 xmlXPathObjectPtr cur, newobj;
6151 xmlChar *tmp;
6152
6153 if (nargs < 2) {
6154 CHECK_ARITY(2);
6155 }
6156
6157 CAST_TO_STRING;
6158 cur = valuePop(ctxt);
6159 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6160 xmlXPathFreeObject(cur);
6161 return;
6162 }
6163 nargs--;
6164
6165 while (nargs > 0) {
6166 CAST_TO_STRING;
6167 newobj = valuePop(ctxt);
6168 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6169 xmlXPathFreeObject(newobj);
6170 xmlXPathFreeObject(cur);
6171 XP_ERROR(XPATH_INVALID_TYPE);
6172 }
6173 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6174 newobj->stringval = cur->stringval;
6175 cur->stringval = tmp;
6176
6177 xmlXPathFreeObject(newobj);
6178 nargs--;
6179 }
6180 valuePush(ctxt, cur);
6181}
6182
6183/**
6184 * xmlXPathContainsFunction:
6185 * @ctxt: the XPath Parser context
6186 * @nargs: the number of arguments
6187 *
6188 * Implement the contains() XPath function
6189 * boolean contains(string, string)
6190 * The contains function returns true if the first argument string
6191 * contains the second argument string, and otherwise returns false.
6192 */
6193void
6194xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6195 xmlXPathObjectPtr hay, needle;
6196
6197 CHECK_ARITY(2);
6198 CAST_TO_STRING;
6199 CHECK_TYPE(XPATH_STRING);
6200 needle = valuePop(ctxt);
6201 CAST_TO_STRING;
6202 hay = valuePop(ctxt);
6203 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6204 xmlXPathFreeObject(hay);
6205 xmlXPathFreeObject(needle);
6206 XP_ERROR(XPATH_INVALID_TYPE);
6207 }
6208 if (xmlStrstr(hay->stringval, needle->stringval))
6209 valuePush(ctxt, xmlXPathNewBoolean(1));
6210 else
6211 valuePush(ctxt, xmlXPathNewBoolean(0));
6212 xmlXPathFreeObject(hay);
6213 xmlXPathFreeObject(needle);
6214}
6215
6216/**
6217 * xmlXPathStartsWithFunction:
6218 * @ctxt: the XPath Parser context
6219 * @nargs: the number of arguments
6220 *
6221 * Implement the starts-with() XPath function
6222 * boolean starts-with(string, string)
6223 * The starts-with function returns true if the first argument string
6224 * starts with the second argument string, and otherwise returns false.
6225 */
6226void
6227xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6228 xmlXPathObjectPtr hay, needle;
6229 int n;
6230
6231 CHECK_ARITY(2);
6232 CAST_TO_STRING;
6233 CHECK_TYPE(XPATH_STRING);
6234 needle = valuePop(ctxt);
6235 CAST_TO_STRING;
6236 hay = valuePop(ctxt);
6237 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6238 xmlXPathFreeObject(hay);
6239 xmlXPathFreeObject(needle);
6240 XP_ERROR(XPATH_INVALID_TYPE);
6241 }
6242 n = xmlStrlen(needle->stringval);
6243 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6244 valuePush(ctxt, xmlXPathNewBoolean(0));
6245 else
6246 valuePush(ctxt, xmlXPathNewBoolean(1));
6247 xmlXPathFreeObject(hay);
6248 xmlXPathFreeObject(needle);
6249}
6250
6251/**
6252 * xmlXPathSubstringFunction:
6253 * @ctxt: the XPath Parser context
6254 * @nargs: the number of arguments
6255 *
6256 * Implement the substring() XPath function
6257 * string substring(string, number, number?)
6258 * The substring function returns the substring of the first argument
6259 * starting at the position specified in the second argument with
6260 * length specified in the third argument. For example,
6261 * substring("12345",2,3) returns "234". If the third argument is not
6262 * specified, it returns the substring starting at the position specified
6263 * in the second argument and continuing to the end of the string. For
6264 * example, substring("12345",2) returns "2345". More precisely, each
6265 * character in the string (see [3.6 Strings]) is considered to have a
6266 * numeric position: the position of the first character is 1, the position
6267 * of the second character is 2 and so on. The returned substring contains
6268 * those characters for which the position of the character is greater than
6269 * or equal to the second argument and, if the third argument is specified,
6270 * less than the sum of the second and third arguments; the comparisons
6271 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6272 * - substring("12345", 1.5, 2.6) returns "234"
6273 * - substring("12345", 0, 3) returns "12"
6274 * - substring("12345", 0 div 0, 3) returns ""
6275 * - substring("12345", 1, 0 div 0) returns ""
6276 * - substring("12345", -42, 1 div 0) returns "12345"
6277 * - substring("12345", -1 div 0, 1 div 0) returns ""
6278 */
6279void
6280xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6281 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006282 double le=0, in;
6283 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006284 xmlChar *ret;
6285
Owen Taylor3473f882001-02-23 17:55:21 +00006286 if (nargs < 2) {
6287 CHECK_ARITY(2);
6288 }
6289 if (nargs > 3) {
6290 CHECK_ARITY(3);
6291 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006292 /*
6293 * take care of possible last (position) argument
6294 */
Owen Taylor3473f882001-02-23 17:55:21 +00006295 if (nargs == 3) {
6296 CAST_TO_NUMBER;
6297 CHECK_TYPE(XPATH_NUMBER);
6298 len = valuePop(ctxt);
6299 le = len->floatval;
6300 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006301 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006302
Owen Taylor3473f882001-02-23 17:55:21 +00006303 CAST_TO_NUMBER;
6304 CHECK_TYPE(XPATH_NUMBER);
6305 start = valuePop(ctxt);
6306 in = start->floatval;
6307 xmlXPathFreeObject(start);
6308 CAST_TO_STRING;
6309 CHECK_TYPE(XPATH_STRING);
6310 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006311 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006312
Daniel Veillard97ac1312001-05-30 19:14:17 +00006313 /*
6314 * If last pos not present, calculate last position
6315 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006316 if (nargs != 3) {
6317 le = (double)m;
6318 if (in < 1.0)
6319 in = 1.0;
6320 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006321
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006322 /* Need to check for the special cases where either
6323 * the index is NaN, the length is NaN, or both
6324 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006325 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006326 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006327 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006328 * To meet the requirements of the spec, the arguments
6329 * must be converted to integer format before
6330 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006331 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006332 * First we go to integer form, rounding up
6333 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006334 */
6335 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006336 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006337
Daniel Veillard9e412302002-06-10 15:59:44 +00006338 if (xmlXPathIsInf(le) == 1) {
6339 l = m;
6340 if (i < 1)
6341 i = 1;
6342 }
6343 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6344 l = 0;
6345 else {
6346 l = (int) le;
6347 if (((double)l)+0.5 <= le) l++;
6348 }
6349
6350 /* Now we normalize inidices */
6351 i -= 1;
6352 l += i;
6353 if (i < 0)
6354 i = 0;
6355 if (l > m)
6356 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006357
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006358 /* number of chars to copy */
6359 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006360
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006361 ret = xmlUTF8Strsub(str->stringval, i, l);
6362 }
6363 else {
6364 ret = NULL;
6365 }
6366
Owen Taylor3473f882001-02-23 17:55:21 +00006367 if (ret == NULL)
6368 valuePush(ctxt, xmlXPathNewCString(""));
6369 else {
6370 valuePush(ctxt, xmlXPathNewString(ret));
6371 xmlFree(ret);
6372 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006373
Owen Taylor3473f882001-02-23 17:55:21 +00006374 xmlXPathFreeObject(str);
6375}
6376
6377/**
6378 * xmlXPathSubstringBeforeFunction:
6379 * @ctxt: the XPath Parser context
6380 * @nargs: the number of arguments
6381 *
6382 * Implement the substring-before() XPath function
6383 * string substring-before(string, string)
6384 * The substring-before function returns the substring of the first
6385 * argument string that precedes the first occurrence of the second
6386 * argument string in the first argument string, or the empty string
6387 * if the first argument string does not contain the second argument
6388 * string. For example, substring-before("1999/04/01","/") returns 1999.
6389 */
6390void
6391xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6392 xmlXPathObjectPtr str;
6393 xmlXPathObjectPtr find;
6394 xmlBufferPtr target;
6395 const xmlChar *point;
6396 int offset;
6397
6398 CHECK_ARITY(2);
6399 CAST_TO_STRING;
6400 find = valuePop(ctxt);
6401 CAST_TO_STRING;
6402 str = valuePop(ctxt);
6403
6404 target = xmlBufferCreate();
6405 if (target) {
6406 point = xmlStrstr(str->stringval, find->stringval);
6407 if (point) {
6408 offset = (int)(point - str->stringval);
6409 xmlBufferAdd(target, str->stringval, offset);
6410 }
6411 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6412 xmlBufferFree(target);
6413 }
6414
6415 xmlXPathFreeObject(str);
6416 xmlXPathFreeObject(find);
6417}
6418
6419/**
6420 * xmlXPathSubstringAfterFunction:
6421 * @ctxt: the XPath Parser context
6422 * @nargs: the number of arguments
6423 *
6424 * Implement the substring-after() XPath function
6425 * string substring-after(string, string)
6426 * The substring-after function returns the substring of the first
6427 * argument string that follows the first occurrence of the second
6428 * argument string in the first argument string, or the empty stringi
6429 * if the first argument string does not contain the second argument
6430 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6431 * and substring-after("1999/04/01","19") returns 99/04/01.
6432 */
6433void
6434xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6435 xmlXPathObjectPtr str;
6436 xmlXPathObjectPtr find;
6437 xmlBufferPtr target;
6438 const xmlChar *point;
6439 int offset;
6440
6441 CHECK_ARITY(2);
6442 CAST_TO_STRING;
6443 find = valuePop(ctxt);
6444 CAST_TO_STRING;
6445 str = valuePop(ctxt);
6446
6447 target = xmlBufferCreate();
6448 if (target) {
6449 point = xmlStrstr(str->stringval, find->stringval);
6450 if (point) {
6451 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6452 xmlBufferAdd(target, &str->stringval[offset],
6453 xmlStrlen(str->stringval) - offset);
6454 }
6455 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6456 xmlBufferFree(target);
6457 }
6458
6459 xmlXPathFreeObject(str);
6460 xmlXPathFreeObject(find);
6461}
6462
6463/**
6464 * xmlXPathNormalizeFunction:
6465 * @ctxt: the XPath Parser context
6466 * @nargs: the number of arguments
6467 *
6468 * Implement the normalize-space() XPath function
6469 * string normalize-space(string?)
6470 * The normalize-space function returns the argument string with white
6471 * space normalized by stripping leading and trailing whitespace
6472 * and replacing sequences of whitespace characters by a single
6473 * space. Whitespace characters are the same allowed by the S production
6474 * in XML. If the argument is omitted, it defaults to the context
6475 * node converted to a string, in other words the value of the context node.
6476 */
6477void
6478xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6479 xmlXPathObjectPtr obj = NULL;
6480 xmlChar *source = NULL;
6481 xmlBufferPtr target;
6482 xmlChar blank;
6483
6484 if (nargs == 0) {
6485 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006486 valuePush(ctxt,
6487 xmlXPathWrapString(
6488 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006489 nargs = 1;
6490 }
6491
6492 CHECK_ARITY(1);
6493 CAST_TO_STRING;
6494 CHECK_TYPE(XPATH_STRING);
6495 obj = valuePop(ctxt);
6496 source = obj->stringval;
6497
6498 target = xmlBufferCreate();
6499 if (target && source) {
6500
6501 /* Skip leading whitespaces */
6502 while (IS_BLANK(*source))
6503 source++;
6504
6505 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6506 blank = 0;
6507 while (*source) {
6508 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006509 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006510 } else {
6511 if (blank) {
6512 xmlBufferAdd(target, &blank, 1);
6513 blank = 0;
6514 }
6515 xmlBufferAdd(target, source, 1);
6516 }
6517 source++;
6518 }
6519
6520 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6521 xmlBufferFree(target);
6522 }
6523 xmlXPathFreeObject(obj);
6524}
6525
6526/**
6527 * xmlXPathTranslateFunction:
6528 * @ctxt: the XPath Parser context
6529 * @nargs: the number of arguments
6530 *
6531 * Implement the translate() XPath function
6532 * string translate(string, string, string)
6533 * The translate function returns the first argument string with
6534 * occurrences of characters in the second argument string replaced
6535 * by the character at the corresponding position in the third argument
6536 * string. For example, translate("bar","abc","ABC") returns the string
6537 * BAr. If there is a character in the second argument string with no
6538 * character at a corresponding position in the third argument string
6539 * (because the second argument string is longer than the third argument
6540 * string), then occurrences of that character in the first argument
6541 * string are removed. For example, translate("--aaa--","abc-","ABC")
6542 * returns "AAA". If a character occurs more than once in second
6543 * argument string, then the first occurrence determines the replacement
6544 * character. If the third argument string is longer than the second
6545 * argument string, then excess characters are ignored.
6546 */
6547void
6548xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006549 xmlXPathObjectPtr str;
6550 xmlXPathObjectPtr from;
6551 xmlXPathObjectPtr to;
6552 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006553 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006554 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006555 xmlChar *point;
6556 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006557
Daniel Veillarde043ee12001-04-16 14:08:07 +00006558 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006559
Daniel Veillarde043ee12001-04-16 14:08:07 +00006560 CAST_TO_STRING;
6561 to = valuePop(ctxt);
6562 CAST_TO_STRING;
6563 from = valuePop(ctxt);
6564 CAST_TO_STRING;
6565 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006566
Daniel Veillarde043ee12001-04-16 14:08:07 +00006567 target = xmlBufferCreate();
6568 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006569 max = xmlUTF8Strlen(to->stringval);
6570 for (cptr = str->stringval; (ch=*cptr); ) {
6571 offset = xmlUTF8Strloc(from->stringval, cptr);
6572 if (offset >= 0) {
6573 if (offset < max) {
6574 point = xmlUTF8Strpos(to->stringval, offset);
6575 if (point)
6576 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6577 }
6578 } else
6579 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6580
6581 /* Step to next character in input */
6582 cptr++;
6583 if ( ch & 0x80 ) {
6584 /* if not simple ascii, verify proper format */
6585 if ( (ch & 0xc0) != 0xc0 ) {
6586 xmlGenericError(xmlGenericErrorContext,
6587 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6588 break;
6589 }
6590 /* then skip over remaining bytes for this char */
6591 while ( (ch <<= 1) & 0x80 )
6592 if ( (*cptr++ & 0xc0) != 0x80 ) {
6593 xmlGenericError(xmlGenericErrorContext,
6594 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6595 break;
6596 }
6597 if (ch & 0x80) /* must have had error encountered */
6598 break;
6599 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006600 }
Owen Taylor3473f882001-02-23 17:55:21 +00006601 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006602 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6603 xmlBufferFree(target);
6604 xmlXPathFreeObject(str);
6605 xmlXPathFreeObject(from);
6606 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006607}
6608
6609/**
6610 * xmlXPathBooleanFunction:
6611 * @ctxt: the XPath Parser context
6612 * @nargs: the number of arguments
6613 *
6614 * Implement the boolean() XPath function
6615 * boolean boolean(object)
6616 * he boolean function converts its argument to a boolean as follows:
6617 * - a number is true if and only if it is neither positive or
6618 * negative zero nor NaN
6619 * - a node-set is true if and only if it is non-empty
6620 * - a string is true if and only if its length is non-zero
6621 */
6622void
6623xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6624 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006625
6626 CHECK_ARITY(1);
6627 cur = valuePop(ctxt);
6628 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006629 cur = xmlXPathConvertBoolean(cur);
6630 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006631}
6632
6633/**
6634 * xmlXPathNotFunction:
6635 * @ctxt: the XPath Parser context
6636 * @nargs: the number of arguments
6637 *
6638 * Implement the not() XPath function
6639 * boolean not(boolean)
6640 * The not function returns true if its argument is false,
6641 * and false otherwise.
6642 */
6643void
6644xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6645 CHECK_ARITY(1);
6646 CAST_TO_BOOLEAN;
6647 CHECK_TYPE(XPATH_BOOLEAN);
6648 ctxt->value->boolval = ! ctxt->value->boolval;
6649}
6650
6651/**
6652 * xmlXPathTrueFunction:
6653 * @ctxt: the XPath Parser context
6654 * @nargs: the number of arguments
6655 *
6656 * Implement the true() XPath function
6657 * boolean true()
6658 */
6659void
6660xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6661 CHECK_ARITY(0);
6662 valuePush(ctxt, xmlXPathNewBoolean(1));
6663}
6664
6665/**
6666 * xmlXPathFalseFunction:
6667 * @ctxt: the XPath Parser context
6668 * @nargs: the number of arguments
6669 *
6670 * Implement the false() XPath function
6671 * boolean false()
6672 */
6673void
6674xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6675 CHECK_ARITY(0);
6676 valuePush(ctxt, xmlXPathNewBoolean(0));
6677}
6678
6679/**
6680 * xmlXPathLangFunction:
6681 * @ctxt: the XPath Parser context
6682 * @nargs: the number of arguments
6683 *
6684 * Implement the lang() XPath function
6685 * boolean lang(string)
6686 * The lang function returns true or false depending on whether the
6687 * language of the context node as specified by xml:lang attributes
6688 * is the same as or is a sublanguage of the language specified by
6689 * the argument string. The language of the context node is determined
6690 * by the value of the xml:lang attribute on the context node, or, if
6691 * the context node has no xml:lang attribute, by the value of the
6692 * xml:lang attribute on the nearest ancestor of the context node that
6693 * has an xml:lang attribute. If there is no such attribute, then lang
6694 * returns false. If there is such an attribute, then lang returns
6695 * true if the attribute value is equal to the argument ignoring case,
6696 * or if there is some suffix starting with - such that the attribute
6697 * value is equal to the argument ignoring that suffix of the attribute
6698 * value and ignoring case.
6699 */
6700void
6701xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6702 xmlXPathObjectPtr val;
6703 const xmlChar *theLang;
6704 const xmlChar *lang;
6705 int ret = 0;
6706 int i;
6707
6708 CHECK_ARITY(1);
6709 CAST_TO_STRING;
6710 CHECK_TYPE(XPATH_STRING);
6711 val = valuePop(ctxt);
6712 lang = val->stringval;
6713 theLang = xmlNodeGetLang(ctxt->context->node);
6714 if ((theLang != NULL) && (lang != NULL)) {
6715 for (i = 0;lang[i] != 0;i++)
6716 if (toupper(lang[i]) != toupper(theLang[i]))
6717 goto not_equal;
6718 ret = 1;
6719 }
6720not_equal:
6721 xmlXPathFreeObject(val);
6722 valuePush(ctxt, xmlXPathNewBoolean(ret));
6723}
6724
6725/**
6726 * xmlXPathNumberFunction:
6727 * @ctxt: the XPath Parser context
6728 * @nargs: the number of arguments
6729 *
6730 * Implement the number() XPath function
6731 * number number(object?)
6732 */
6733void
6734xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6735 xmlXPathObjectPtr cur;
6736 double res;
6737
6738 if (nargs == 0) {
6739 if (ctxt->context->node == NULL) {
6740 valuePush(ctxt, xmlXPathNewFloat(0.0));
6741 } else {
6742 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6743
6744 res = xmlXPathStringEvalNumber(content);
6745 valuePush(ctxt, xmlXPathNewFloat(res));
6746 xmlFree(content);
6747 }
6748 return;
6749 }
6750
6751 CHECK_ARITY(1);
6752 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006753 cur = xmlXPathConvertNumber(cur);
6754 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006755}
6756
6757/**
6758 * xmlXPathSumFunction:
6759 * @ctxt: the XPath Parser context
6760 * @nargs: the number of arguments
6761 *
6762 * Implement the sum() XPath function
6763 * number sum(node-set)
6764 * The sum function returns the sum of the values of the nodes in
6765 * the argument node-set.
6766 */
6767void
6768xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6769 xmlXPathObjectPtr cur;
6770 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006771 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006772
6773 CHECK_ARITY(1);
6774 if ((ctxt->value == NULL) ||
6775 ((ctxt->value->type != XPATH_NODESET) &&
6776 (ctxt->value->type != XPATH_XSLT_TREE)))
6777 XP_ERROR(XPATH_INVALID_TYPE);
6778 cur = valuePop(ctxt);
6779
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006780 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006781 valuePush(ctxt, xmlXPathNewFloat(0.0));
6782 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006783 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6784 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006785 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006786 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006787 }
6788 xmlXPathFreeObject(cur);
6789}
6790
6791/**
6792 * xmlXPathFloorFunction:
6793 * @ctxt: the XPath Parser context
6794 * @nargs: the number of arguments
6795 *
6796 * Implement the floor() XPath function
6797 * number floor(number)
6798 * The floor function returns the largest (closest to positive infinity)
6799 * number that is not greater than the argument and that is an integer.
6800 */
6801void
6802xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006803 double f;
6804
Owen Taylor3473f882001-02-23 17:55:21 +00006805 CHECK_ARITY(1);
6806 CAST_TO_NUMBER;
6807 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006808
6809 f = (double)((int) ctxt->value->floatval);
6810 if (f != ctxt->value->floatval) {
6811 if (ctxt->value->floatval > 0)
6812 ctxt->value->floatval = f;
6813 else
6814 ctxt->value->floatval = f - 1;
6815 }
Owen Taylor3473f882001-02-23 17:55:21 +00006816}
6817
6818/**
6819 * xmlXPathCeilingFunction:
6820 * @ctxt: the XPath Parser context
6821 * @nargs: the number of arguments
6822 *
6823 * Implement the ceiling() XPath function
6824 * number ceiling(number)
6825 * The ceiling function returns the smallest (closest to negative infinity)
6826 * number that is not less than the argument and that is an integer.
6827 */
6828void
6829xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6830 double f;
6831
6832 CHECK_ARITY(1);
6833 CAST_TO_NUMBER;
6834 CHECK_TYPE(XPATH_NUMBER);
6835
6836#if 0
6837 ctxt->value->floatval = ceil(ctxt->value->floatval);
6838#else
6839 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006840 if (f != ctxt->value->floatval) {
6841 if (ctxt->value->floatval > 0)
6842 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006843 else {
6844 if (ctxt->value->floatval < 0 && f == 0)
6845 ctxt->value->floatval = xmlXPathNZERO;
6846 else
6847 ctxt->value->floatval = f;
6848 }
6849
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006850 }
Owen Taylor3473f882001-02-23 17:55:21 +00006851#endif
6852}
6853
6854/**
6855 * xmlXPathRoundFunction:
6856 * @ctxt: the XPath Parser context
6857 * @nargs: the number of arguments
6858 *
6859 * Implement the round() XPath function
6860 * number round(number)
6861 * The round function returns the number that is closest to the
6862 * argument and that is an integer. If there are two such numbers,
6863 * then the one that is even is returned.
6864 */
6865void
6866xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6867 double f;
6868
6869 CHECK_ARITY(1);
6870 CAST_TO_NUMBER;
6871 CHECK_TYPE(XPATH_NUMBER);
6872
Daniel Veillardcda96922001-08-21 10:56:31 +00006873 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6874 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6875 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006876 (ctxt->value->floatval == 0.0))
6877 return;
6878
Owen Taylor3473f882001-02-23 17:55:21 +00006879 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006880 if (ctxt->value->floatval < 0) {
6881 if (ctxt->value->floatval < f - 0.5)
6882 ctxt->value->floatval = f - 1;
6883 else
6884 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006885 if (ctxt->value->floatval == 0)
6886 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006887 } else {
6888 if (ctxt->value->floatval < f + 0.5)
6889 ctxt->value->floatval = f;
6890 else
6891 ctxt->value->floatval = f + 1;
6892 }
Owen Taylor3473f882001-02-23 17:55:21 +00006893}
6894
6895/************************************************************************
6896 * *
6897 * The Parser *
6898 * *
6899 ************************************************************************/
6900
6901/*
6902 * a couple of forward declarations since we use a recursive call based
6903 * implementation.
6904 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006905static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006906static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006907static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006908#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006909static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6910#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006911#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006912static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006913#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006914static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6915 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006916
6917/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006918 * xmlXPathCurrentChar:
6919 * @ctxt: the XPath parser context
6920 * @cur: pointer to the beginning of the char
6921 * @len: pointer to the length of the char read
6922 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006923 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006924 * bytes in the input buffer.
6925 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006926 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006927 */
6928
6929static int
6930xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6931 unsigned char c;
6932 unsigned int val;
6933 const xmlChar *cur;
6934
6935 if (ctxt == NULL)
6936 return(0);
6937 cur = ctxt->cur;
6938
6939 /*
6940 * We are supposed to handle UTF8, check it's valid
6941 * From rfc2044: encoding of the Unicode values on UTF-8:
6942 *
6943 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6944 * 0000 0000-0000 007F 0xxxxxxx
6945 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6946 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6947 *
6948 * Check for the 0x110000 limit too
6949 */
6950 c = *cur;
6951 if (c & 0x80) {
6952 if ((cur[1] & 0xc0) != 0x80)
6953 goto encoding_error;
6954 if ((c & 0xe0) == 0xe0) {
6955
6956 if ((cur[2] & 0xc0) != 0x80)
6957 goto encoding_error;
6958 if ((c & 0xf0) == 0xf0) {
6959 if (((c & 0xf8) != 0xf0) ||
6960 ((cur[3] & 0xc0) != 0x80))
6961 goto encoding_error;
6962 /* 4-byte code */
6963 *len = 4;
6964 val = (cur[0] & 0x7) << 18;
6965 val |= (cur[1] & 0x3f) << 12;
6966 val |= (cur[2] & 0x3f) << 6;
6967 val |= cur[3] & 0x3f;
6968 } else {
6969 /* 3-byte code */
6970 *len = 3;
6971 val = (cur[0] & 0xf) << 12;
6972 val |= (cur[1] & 0x3f) << 6;
6973 val |= cur[2] & 0x3f;
6974 }
6975 } else {
6976 /* 2-byte code */
6977 *len = 2;
6978 val = (cur[0] & 0x1f) << 6;
6979 val |= cur[1] & 0x3f;
6980 }
6981 if (!IS_CHAR(val)) {
6982 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6983 }
6984 return(val);
6985 } else {
6986 /* 1-byte code */
6987 *len = 1;
6988 return((int) *cur);
6989 }
6990encoding_error:
6991 /*
6992 * If we detect an UTF8 error that probably mean that the
6993 * input encoding didn't get properly advertized in the
6994 * declaration header. Report the error and switch the encoding
6995 * to ISO-Latin-1 (if you don't like this policy, just declare the
6996 * encoding !)
6997 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006998 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006999 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007000}
7001
7002/**
Owen Taylor3473f882001-02-23 17:55:21 +00007003 * xmlXPathParseNCName:
7004 * @ctxt: the XPath Parser context
7005 *
7006 * parse an XML namespace non qualified name.
7007 *
7008 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7009 *
7010 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7011 * CombiningChar | Extender
7012 *
7013 * Returns the namespace name or NULL
7014 */
7015
7016xmlChar *
7017xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007018 const xmlChar *in;
7019 xmlChar *ret;
7020 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007021
Daniel Veillard2156a562001-04-28 12:24:34 +00007022 /*
7023 * Accelerator for simple ASCII names
7024 */
7025 in = ctxt->cur;
7026 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7027 ((*in >= 0x41) && (*in <= 0x5A)) ||
7028 (*in == '_')) {
7029 in++;
7030 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7031 ((*in >= 0x41) && (*in <= 0x5A)) ||
7032 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007033 (*in == '_') || (*in == '.') ||
7034 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007035 in++;
7036 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7037 (*in == '[') || (*in == ']') || (*in == ':') ||
7038 (*in == '@') || (*in == '*')) {
7039 count = in - ctxt->cur;
7040 if (count == 0)
7041 return(NULL);
7042 ret = xmlStrndup(ctxt->cur, count);
7043 ctxt->cur = in;
7044 return(ret);
7045 }
7046 }
7047 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007048}
7049
Daniel Veillard2156a562001-04-28 12:24:34 +00007050
Owen Taylor3473f882001-02-23 17:55:21 +00007051/**
7052 * xmlXPathParseQName:
7053 * @ctxt: the XPath Parser context
7054 * @prefix: a xmlChar **
7055 *
7056 * parse an XML qualified name
7057 *
7058 * [NS 5] QName ::= (Prefix ':')? LocalPart
7059 *
7060 * [NS 6] Prefix ::= NCName
7061 *
7062 * [NS 7] LocalPart ::= NCName
7063 *
7064 * Returns the function returns the local part, and prefix is updated
7065 * to get the Prefix if any.
7066 */
7067
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007068static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007069xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7070 xmlChar *ret = NULL;
7071
7072 *prefix = NULL;
7073 ret = xmlXPathParseNCName(ctxt);
7074 if (CUR == ':') {
7075 *prefix = ret;
7076 NEXT;
7077 ret = xmlXPathParseNCName(ctxt);
7078 }
7079 return(ret);
7080}
7081
7082/**
7083 * xmlXPathParseName:
7084 * @ctxt: the XPath Parser context
7085 *
7086 * parse an XML name
7087 *
7088 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7089 * CombiningChar | Extender
7090 *
7091 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7092 *
7093 * Returns the namespace name or NULL
7094 */
7095
7096xmlChar *
7097xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007098 const xmlChar *in;
7099 xmlChar *ret;
7100 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007101
Daniel Veillard61d80a22001-04-27 17:13:01 +00007102 /*
7103 * Accelerator for simple ASCII names
7104 */
7105 in = ctxt->cur;
7106 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7107 ((*in >= 0x41) && (*in <= 0x5A)) ||
7108 (*in == '_') || (*in == ':')) {
7109 in++;
7110 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7111 ((*in >= 0x41) && (*in <= 0x5A)) ||
7112 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007113 (*in == '_') || (*in == '-') ||
7114 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007115 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007116 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007117 count = in - ctxt->cur;
7118 ret = xmlStrndup(ctxt->cur, count);
7119 ctxt->cur = in;
7120 return(ret);
7121 }
7122 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007123 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007124}
7125
Daniel Veillard61d80a22001-04-27 17:13:01 +00007126static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007127xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007128 xmlChar buf[XML_MAX_NAMELEN + 5];
7129 int len = 0, l;
7130 int c;
7131
7132 /*
7133 * Handler for more complex cases
7134 */
7135 c = CUR_CHAR(l);
7136 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007137 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7138 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007139 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007140 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007141 return(NULL);
7142 }
7143
7144 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7145 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7146 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007147 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007148 (IS_COMBINING(c)) ||
7149 (IS_EXTENDER(c)))) {
7150 COPY_BUF(l,buf,len,c);
7151 NEXTL(l);
7152 c = CUR_CHAR(l);
7153 if (len >= XML_MAX_NAMELEN) {
7154 /*
7155 * Okay someone managed to make a huge name, so he's ready to pay
7156 * for the processing speed.
7157 */
7158 xmlChar *buffer;
7159 int max = len * 2;
7160
7161 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7162 if (buffer == NULL) {
7163 XP_ERROR0(XPATH_MEMORY_ERROR);
7164 }
7165 memcpy(buffer, buf, len);
7166 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7167 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007168 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007169 (IS_COMBINING(c)) ||
7170 (IS_EXTENDER(c))) {
7171 if (len + 10 > max) {
7172 max *= 2;
7173 buffer = (xmlChar *) xmlRealloc(buffer,
7174 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007175 if (buffer == NULL) {
7176 XP_ERROR0(XPATH_MEMORY_ERROR);
7177 }
7178 }
7179 COPY_BUF(l,buffer,len,c);
7180 NEXTL(l);
7181 c = CUR_CHAR(l);
7182 }
7183 buffer[len] = 0;
7184 return(buffer);
7185 }
7186 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007187 if (len == 0)
7188 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007189 return(xmlStrndup(buf, len));
7190}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007191
7192#define MAX_FRAC 20
7193
7194static double my_pow10[MAX_FRAC] = {
7195 1.0, 10.0, 100.0, 1000.0, 10000.0,
7196 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7197 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7198 100000000000000.0,
7199 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7200 1000000000000000000.0, 10000000000000000000.0
7201};
7202
Owen Taylor3473f882001-02-23 17:55:21 +00007203/**
7204 * xmlXPathStringEvalNumber:
7205 * @str: A string to scan
7206 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007207 * [30a] Float ::= Number ('e' Digits?)?
7208 *
Owen Taylor3473f882001-02-23 17:55:21 +00007209 * [30] Number ::= Digits ('.' Digits?)?
7210 * | '.' Digits
7211 * [31] Digits ::= [0-9]+
7212 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007213 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007214 * In complement of the Number expression, this function also handles
7215 * negative values : '-' Number.
7216 *
7217 * Returns the double value.
7218 */
7219double
7220xmlXPathStringEvalNumber(const xmlChar *str) {
7221 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007222 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007223 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007224 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007225 int exponent = 0;
7226 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007227#ifdef __GNUC__
7228 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007229 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007230#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007231 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007232 while (IS_BLANK(*cur)) cur++;
7233 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7234 return(xmlXPathNAN);
7235 }
7236 if (*cur == '-') {
7237 isneg = 1;
7238 cur++;
7239 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007240
7241#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007242 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007243 * tmp/temp is a workaround against a gcc compiler bug
7244 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007245 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007246 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007247 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007248 ret = ret * 10;
7249 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007250 ok = 1;
7251 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007252 temp = (double) tmp;
7253 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007254 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007255#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007256 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007257 while ((*cur >= '0') && (*cur <= '9')) {
7258 ret = ret * 10 + (*cur - '0');
7259 ok = 1;
7260 cur++;
7261 }
7262#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007263
Owen Taylor3473f882001-02-23 17:55:21 +00007264 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007265 int v, frac = 0;
7266 double fraction = 0;
7267
Owen Taylor3473f882001-02-23 17:55:21 +00007268 cur++;
7269 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7270 return(xmlXPathNAN);
7271 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007272 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7273 v = (*cur - '0');
7274 fraction = fraction * 10 + v;
7275 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007276 cur++;
7277 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007278 fraction /= my_pow10[frac];
7279 ret = ret + fraction;
7280 while ((*cur >= '0') && (*cur <= '9'))
7281 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007282 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007283 if ((*cur == 'e') || (*cur == 'E')) {
7284 cur++;
7285 if (*cur == '-') {
7286 is_exponent_negative = 1;
7287 cur++;
7288 }
7289 while ((*cur >= '0') && (*cur <= '9')) {
7290 exponent = exponent * 10 + (*cur - '0');
7291 cur++;
7292 }
7293 }
Owen Taylor3473f882001-02-23 17:55:21 +00007294 while (IS_BLANK(*cur)) cur++;
7295 if (*cur != 0) return(xmlXPathNAN);
7296 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007297 if (is_exponent_negative) exponent = -exponent;
7298 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007299 return(ret);
7300}
7301
7302/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007303 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007304 * @ctxt: the XPath Parser context
7305 *
7306 * [30] Number ::= Digits ('.' Digits?)?
7307 * | '.' Digits
7308 * [31] Digits ::= [0-9]+
7309 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007310 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007311 *
7312 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007313static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007314xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7315{
Owen Taylor3473f882001-02-23 17:55:21 +00007316 double ret = 0.0;
7317 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007318 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007319 int exponent = 0;
7320 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007321#ifdef __GNUC__
7322 unsigned long tmp = 0;
7323 double temp;
7324#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007325
7326 CHECK_ERROR;
7327 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7328 XP_ERROR(XPATH_NUMBER_ERROR);
7329 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007330#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007331 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007332 * tmp/temp is a workaround against a gcc compiler bug
7333 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007334 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007335 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007336 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007337 ret = ret * 10;
7338 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007339 ok = 1;
7340 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007341 temp = (double) tmp;
7342 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007343 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007344#else
7345 ret = 0;
7346 while ((CUR >= '0') && (CUR <= '9')) {
7347 ret = ret * 10 + (CUR - '0');
7348 ok = 1;
7349 NEXT;
7350 }
7351#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007352 if (CUR == '.') {
7353 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007354 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7355 XP_ERROR(XPATH_NUMBER_ERROR);
7356 }
7357 while ((CUR >= '0') && (CUR <= '9')) {
7358 mult /= 10;
7359 ret = ret + (CUR - '0') * mult;
7360 NEXT;
7361 }
Owen Taylor3473f882001-02-23 17:55:21 +00007362 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007363 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007364 NEXT;
7365 if (CUR == '-') {
7366 is_exponent_negative = 1;
7367 NEXT;
7368 }
7369 while ((CUR >= '0') && (CUR <= '9')) {
7370 exponent = exponent * 10 + (CUR - '0');
7371 NEXT;
7372 }
7373 if (is_exponent_negative)
7374 exponent = -exponent;
7375 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007376 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007377 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007378 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007379}
7380
7381/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007382 * xmlXPathParseLiteral:
7383 * @ctxt: the XPath Parser context
7384 *
7385 * Parse a Literal
7386 *
7387 * [29] Literal ::= '"' [^"]* '"'
7388 * | "'" [^']* "'"
7389 *
7390 * Returns the value found or NULL in case of error
7391 */
7392static xmlChar *
7393xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7394 const xmlChar *q;
7395 xmlChar *ret = NULL;
7396
7397 if (CUR == '"') {
7398 NEXT;
7399 q = CUR_PTR;
7400 while ((IS_CHAR(CUR)) && (CUR != '"'))
7401 NEXT;
7402 if (!IS_CHAR(CUR)) {
7403 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7404 } else {
7405 ret = xmlStrndup(q, CUR_PTR - q);
7406 NEXT;
7407 }
7408 } else if (CUR == '\'') {
7409 NEXT;
7410 q = CUR_PTR;
7411 while ((IS_CHAR(CUR)) && (CUR != '\''))
7412 NEXT;
7413 if (!IS_CHAR(CUR)) {
7414 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7415 } else {
7416 ret = xmlStrndup(q, CUR_PTR - q);
7417 NEXT;
7418 }
7419 } else {
7420 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7421 }
7422 return(ret);
7423}
7424
7425/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007426 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007427 * @ctxt: the XPath Parser context
7428 *
7429 * Parse a Literal and push it on the stack.
7430 *
7431 * [29] Literal ::= '"' [^"]* '"'
7432 * | "'" [^']* "'"
7433 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007434 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007435 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007436static void
7437xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007438 const xmlChar *q;
7439 xmlChar *ret = NULL;
7440
7441 if (CUR == '"') {
7442 NEXT;
7443 q = CUR_PTR;
7444 while ((IS_CHAR(CUR)) && (CUR != '"'))
7445 NEXT;
7446 if (!IS_CHAR(CUR)) {
7447 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7448 } else {
7449 ret = xmlStrndup(q, CUR_PTR - q);
7450 NEXT;
7451 }
7452 } else if (CUR == '\'') {
7453 NEXT;
7454 q = CUR_PTR;
7455 while ((IS_CHAR(CUR)) && (CUR != '\''))
7456 NEXT;
7457 if (!IS_CHAR(CUR)) {
7458 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7459 } else {
7460 ret = xmlStrndup(q, CUR_PTR - q);
7461 NEXT;
7462 }
7463 } else {
7464 XP_ERROR(XPATH_START_LITERAL_ERROR);
7465 }
7466 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007467 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7468 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007469 xmlFree(ret);
7470}
7471
7472/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007473 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007474 * @ctxt: the XPath Parser context
7475 *
7476 * Parse a VariableReference, evaluate it and push it on the stack.
7477 *
7478 * The variable bindings consist of a mapping from variable names
7479 * to variable values. The value of a variable is an object, which
7480 * of any of the types that are possible for the value of an expression,
7481 * and may also be of additional types not specified here.
7482 *
7483 * Early evaluation is possible since:
7484 * The variable bindings [...] used to evaluate a subexpression are
7485 * always the same as those used to evaluate the containing expression.
7486 *
7487 * [36] VariableReference ::= '$' QName
7488 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007489static void
7490xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007491 xmlChar *name;
7492 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007493
7494 SKIP_BLANKS;
7495 if (CUR != '$') {
7496 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7497 }
7498 NEXT;
7499 name = xmlXPathParseQName(ctxt, &prefix);
7500 if (name == NULL) {
7501 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7502 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007503 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007504 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7505 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007506 SKIP_BLANKS;
7507}
7508
7509/**
7510 * xmlXPathIsNodeType:
7511 * @ctxt: the XPath Parser context
7512 * @name: a name string
7513 *
7514 * Is the name given a NodeType one.
7515 *
7516 * [38] NodeType ::= 'comment'
7517 * | 'text'
7518 * | 'processing-instruction'
7519 * | 'node'
7520 *
7521 * Returns 1 if true 0 otherwise
7522 */
7523int
7524xmlXPathIsNodeType(const xmlChar *name) {
7525 if (name == NULL)
7526 return(0);
7527
Daniel Veillard1971ee22002-01-31 20:29:19 +00007528 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007529 return(1);
7530 if (xmlStrEqual(name, BAD_CAST "text"))
7531 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007532 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007533 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007534 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007535 return(1);
7536 return(0);
7537}
7538
7539/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007540 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007541 * @ctxt: the XPath Parser context
7542 *
7543 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7544 * [17] Argument ::= Expr
7545 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007546 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007547 * pushed on the stack
7548 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007549static void
7550xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007551 xmlChar *name;
7552 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007553 int nbargs = 0;
7554
7555 name = xmlXPathParseQName(ctxt, &prefix);
7556 if (name == NULL) {
7557 XP_ERROR(XPATH_EXPR_ERROR);
7558 }
7559 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007560#ifdef DEBUG_EXPR
7561 if (prefix == NULL)
7562 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7563 name);
7564 else
7565 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7566 prefix, name);
7567#endif
7568
Owen Taylor3473f882001-02-23 17:55:21 +00007569 if (CUR != '(') {
7570 XP_ERROR(XPATH_EXPR_ERROR);
7571 }
7572 NEXT;
7573 SKIP_BLANKS;
7574
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007575 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007576 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007577 int op1 = ctxt->comp->last;
7578 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007579 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007580 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007581 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007582 nbargs++;
7583 if (CUR == ')') break;
7584 if (CUR != ',') {
7585 XP_ERROR(XPATH_EXPR_ERROR);
7586 }
7587 NEXT;
7588 SKIP_BLANKS;
7589 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007590 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7591 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007592 NEXT;
7593 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007594}
7595
7596/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007597 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007598 * @ctxt: the XPath Parser context
7599 *
7600 * [15] PrimaryExpr ::= VariableReference
7601 * | '(' Expr ')'
7602 * | Literal
7603 * | Number
7604 * | FunctionCall
7605 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007606 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007607 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007608static void
7609xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007610 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007611 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007612 else if (CUR == '(') {
7613 NEXT;
7614 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007615 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007616 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007617 if (CUR != ')') {
7618 XP_ERROR(XPATH_EXPR_ERROR);
7619 }
7620 NEXT;
7621 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007622 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007623 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007624 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007625 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007626 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007627 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007628 }
7629 SKIP_BLANKS;
7630}
7631
7632/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007633 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007634 * @ctxt: the XPath Parser context
7635 *
7636 * [20] FilterExpr ::= PrimaryExpr
7637 * | FilterExpr Predicate
7638 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007639 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007640 * Square brackets are used to filter expressions in the same way that
7641 * they are used in location paths. It is an error if the expression to
7642 * be filtered does not evaluate to a node-set. The context node list
7643 * used for evaluating the expression in square brackets is the node-set
7644 * to be filtered listed in document order.
7645 */
7646
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007647static void
7648xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7649 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007650 CHECK_ERROR;
7651 SKIP_BLANKS;
7652
7653 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007654 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007655 SKIP_BLANKS;
7656 }
7657
7658
7659}
7660
7661/**
7662 * xmlXPathScanName:
7663 * @ctxt: the XPath Parser context
7664 *
7665 * Trickery: parse an XML name but without consuming the input flow
7666 * Needed to avoid insanity in the parser state.
7667 *
7668 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7669 * CombiningChar | Extender
7670 *
7671 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7672 *
7673 * [6] Names ::= Name (S Name)*
7674 *
7675 * Returns the Name parsed or NULL
7676 */
7677
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007678static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007679xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7680 xmlChar buf[XML_MAX_NAMELEN];
7681 int len = 0;
7682
7683 SKIP_BLANKS;
7684 if (!IS_LETTER(CUR) && (CUR != '_') &&
7685 (CUR != ':')) {
7686 return(NULL);
7687 }
7688
7689 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7690 (NXT(len) == '.') || (NXT(len) == '-') ||
7691 (NXT(len) == '_') || (NXT(len) == ':') ||
7692 (IS_COMBINING(NXT(len))) ||
7693 (IS_EXTENDER(NXT(len)))) {
7694 buf[len] = NXT(len);
7695 len++;
7696 if (len >= XML_MAX_NAMELEN) {
7697 xmlGenericError(xmlGenericErrorContext,
7698 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7699 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7700 (NXT(len) == '.') || (NXT(len) == '-') ||
7701 (NXT(len) == '_') || (NXT(len) == ':') ||
7702 (IS_COMBINING(NXT(len))) ||
7703 (IS_EXTENDER(NXT(len))))
7704 len++;
7705 break;
7706 }
7707 }
7708 return(xmlStrndup(buf, len));
7709}
7710
7711/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007712 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007713 * @ctxt: the XPath Parser context
7714 *
7715 * [19] PathExpr ::= LocationPath
7716 * | FilterExpr
7717 * | FilterExpr '/' RelativeLocationPath
7718 * | FilterExpr '//' RelativeLocationPath
7719 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007720 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007721 * The / operator and // operators combine an arbitrary expression
7722 * and a relative location path. It is an error if the expression
7723 * does not evaluate to a node-set.
7724 * The / operator does composition in the same way as when / is
7725 * used in a location path. As in location paths, // is short for
7726 * /descendant-or-self::node()/.
7727 */
7728
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007729static void
7730xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007731 int lc = 1; /* Should we branch to LocationPath ? */
7732 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7733
7734 SKIP_BLANKS;
7735 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007736 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007737 lc = 0;
7738 } else if (CUR == '*') {
7739 /* relative or absolute location path */
7740 lc = 1;
7741 } else if (CUR == '/') {
7742 /* relative or absolute location path */
7743 lc = 1;
7744 } else if (CUR == '@') {
7745 /* relative abbreviated attribute location path */
7746 lc = 1;
7747 } else if (CUR == '.') {
7748 /* relative abbreviated attribute location path */
7749 lc = 1;
7750 } else {
7751 /*
7752 * Problem is finding if we have a name here whether it's:
7753 * - a nodetype
7754 * - a function call in which case it's followed by '('
7755 * - an axis in which case it's followed by ':'
7756 * - a element name
7757 * We do an a priori analysis here rather than having to
7758 * maintain parsed token content through the recursive function
7759 * calls. This looks uglier but makes the code quite easier to
7760 * read/write/debug.
7761 */
7762 SKIP_BLANKS;
7763 name = xmlXPathScanName(ctxt);
7764 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7765#ifdef DEBUG_STEP
7766 xmlGenericError(xmlGenericErrorContext,
7767 "PathExpr: Axis\n");
7768#endif
7769 lc = 1;
7770 xmlFree(name);
7771 } else if (name != NULL) {
7772 int len =xmlStrlen(name);
7773 int blank = 0;
7774
7775
7776 while (NXT(len) != 0) {
7777 if (NXT(len) == '/') {
7778 /* element name */
7779#ifdef DEBUG_STEP
7780 xmlGenericError(xmlGenericErrorContext,
7781 "PathExpr: AbbrRelLocation\n");
7782#endif
7783 lc = 1;
7784 break;
7785 } else if (IS_BLANK(NXT(len))) {
7786 /* skip to next */
7787 blank = 1;
7788 } else if (NXT(len) == ':') {
7789#ifdef DEBUG_STEP
7790 xmlGenericError(xmlGenericErrorContext,
7791 "PathExpr: AbbrRelLocation\n");
7792#endif
7793 lc = 1;
7794 break;
7795 } else if ((NXT(len) == '(')) {
7796 /* Note Type or Function */
7797 if (xmlXPathIsNodeType(name)) {
7798#ifdef DEBUG_STEP
7799 xmlGenericError(xmlGenericErrorContext,
7800 "PathExpr: Type search\n");
7801#endif
7802 lc = 1;
7803 } else {
7804#ifdef DEBUG_STEP
7805 xmlGenericError(xmlGenericErrorContext,
7806 "PathExpr: function call\n");
7807#endif
7808 lc = 0;
7809 }
7810 break;
7811 } else if ((NXT(len) == '[')) {
7812 /* element name */
7813#ifdef DEBUG_STEP
7814 xmlGenericError(xmlGenericErrorContext,
7815 "PathExpr: AbbrRelLocation\n");
7816#endif
7817 lc = 1;
7818 break;
7819 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7820 (NXT(len) == '=')) {
7821 lc = 1;
7822 break;
7823 } else {
7824 lc = 1;
7825 break;
7826 }
7827 len++;
7828 }
7829 if (NXT(len) == 0) {
7830#ifdef DEBUG_STEP
7831 xmlGenericError(xmlGenericErrorContext,
7832 "PathExpr: AbbrRelLocation\n");
7833#endif
7834 /* element name */
7835 lc = 1;
7836 }
7837 xmlFree(name);
7838 } else {
7839 /* make sure all cases are covered explicitely */
7840 XP_ERROR(XPATH_EXPR_ERROR);
7841 }
7842 }
7843
7844 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007845 if (CUR == '/') {
7846 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7847 } else {
7848 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007849 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007850 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007851 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007852 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007853 CHECK_ERROR;
7854 if ((CUR == '/') && (NXT(1) == '/')) {
7855 SKIP(2);
7856 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007857
7858 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7859 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7860 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7861
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007862 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007863 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007864 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007865 }
7866 }
7867 SKIP_BLANKS;
7868}
7869
7870/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007871 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007872 * @ctxt: the XPath Parser context
7873 *
7874 * [18] UnionExpr ::= PathExpr
7875 * | UnionExpr '|' PathExpr
7876 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007877 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007878 */
7879
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007880static void
7881xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7882 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007883 CHECK_ERROR;
7884 SKIP_BLANKS;
7885 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007886 int op1 = ctxt->comp->last;
7887 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007888
7889 NEXT;
7890 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007891 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007892
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007893 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7894
Owen Taylor3473f882001-02-23 17:55:21 +00007895 SKIP_BLANKS;
7896 }
Owen Taylor3473f882001-02-23 17:55:21 +00007897}
7898
7899/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007900 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007901 * @ctxt: the XPath Parser context
7902 *
7903 * [27] UnaryExpr ::= UnionExpr
7904 * | '-' UnaryExpr
7905 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007906 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007907 */
7908
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007909static void
7910xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007911 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007912 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007913
7914 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007915 while (CUR == '-') {
7916 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007917 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007918 NEXT;
7919 SKIP_BLANKS;
7920 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007921
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007922 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007923 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007924 if (found) {
7925 if (minus)
7926 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7927 else
7928 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007929 }
7930}
7931
7932/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007933 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007934 * @ctxt: the XPath Parser context
7935 *
7936 * [26] MultiplicativeExpr ::= UnaryExpr
7937 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7938 * | MultiplicativeExpr 'div' UnaryExpr
7939 * | MultiplicativeExpr 'mod' UnaryExpr
7940 * [34] MultiplyOperator ::= '*'
7941 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007942 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007943 */
7944
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007945static void
7946xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7947 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007948 CHECK_ERROR;
7949 SKIP_BLANKS;
7950 while ((CUR == '*') ||
7951 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7952 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7953 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007954 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007955
7956 if (CUR == '*') {
7957 op = 0;
7958 NEXT;
7959 } else if (CUR == 'd') {
7960 op = 1;
7961 SKIP(3);
7962 } else if (CUR == 'm') {
7963 op = 2;
7964 SKIP(3);
7965 }
7966 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007967 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007968 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007969 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007970 SKIP_BLANKS;
7971 }
7972}
7973
7974/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007975 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007976 * @ctxt: the XPath Parser context
7977 *
7978 * [25] AdditiveExpr ::= MultiplicativeExpr
7979 * | AdditiveExpr '+' MultiplicativeExpr
7980 * | AdditiveExpr '-' MultiplicativeExpr
7981 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007982 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007983 */
7984
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007985static void
7986xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007987
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007988 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007989 CHECK_ERROR;
7990 SKIP_BLANKS;
7991 while ((CUR == '+') || (CUR == '-')) {
7992 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007993 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007994
7995 if (CUR == '+') plus = 1;
7996 else plus = 0;
7997 NEXT;
7998 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007999 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008000 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008001 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008002 SKIP_BLANKS;
8003 }
8004}
8005
8006/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008007 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008008 * @ctxt: the XPath Parser context
8009 *
8010 * [24] RelationalExpr ::= AdditiveExpr
8011 * | RelationalExpr '<' AdditiveExpr
8012 * | RelationalExpr '>' AdditiveExpr
8013 * | RelationalExpr '<=' AdditiveExpr
8014 * | RelationalExpr '>=' AdditiveExpr
8015 *
8016 * A <= B > C is allowed ? Answer from James, yes with
8017 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8018 * which is basically what got implemented.
8019 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008020 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008021 * on the stack
8022 */
8023
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008024static void
8025xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8026 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008027 CHECK_ERROR;
8028 SKIP_BLANKS;
8029 while ((CUR == '<') ||
8030 (CUR == '>') ||
8031 ((CUR == '<') && (NXT(1) == '=')) ||
8032 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008033 int inf, strict;
8034 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008035
8036 if (CUR == '<') inf = 1;
8037 else inf = 0;
8038 if (NXT(1) == '=') strict = 0;
8039 else strict = 1;
8040 NEXT;
8041 if (!strict) NEXT;
8042 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008043 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008044 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008045 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008046 SKIP_BLANKS;
8047 }
8048}
8049
8050/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008051 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008052 * @ctxt: the XPath Parser context
8053 *
8054 * [23] EqualityExpr ::= RelationalExpr
8055 * | EqualityExpr '=' RelationalExpr
8056 * | EqualityExpr '!=' RelationalExpr
8057 *
8058 * A != B != C is allowed ? Answer from James, yes with
8059 * (RelationalExpr = RelationalExpr) = RelationalExpr
8060 * (RelationalExpr != RelationalExpr) != RelationalExpr
8061 * which is basically what got implemented.
8062 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008063 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008064 *
8065 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008066static void
8067xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8068 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008069 CHECK_ERROR;
8070 SKIP_BLANKS;
8071 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008072 int eq;
8073 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008074
8075 if (CUR == '=') eq = 1;
8076 else eq = 0;
8077 NEXT;
8078 if (!eq) NEXT;
8079 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008080 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008081 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008082 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008083 SKIP_BLANKS;
8084 }
8085}
8086
8087/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008088 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008089 * @ctxt: the XPath Parser context
8090 *
8091 * [22] AndExpr ::= EqualityExpr
8092 * | AndExpr 'and' EqualityExpr
8093 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008094 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008095 *
8096 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008097static void
8098xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8099 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008100 CHECK_ERROR;
8101 SKIP_BLANKS;
8102 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008103 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008104 SKIP(3);
8105 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008106 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008107 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008108 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008109 SKIP_BLANKS;
8110 }
8111}
8112
8113/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008114 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008115 * @ctxt: the XPath Parser context
8116 *
8117 * [14] Expr ::= OrExpr
8118 * [21] OrExpr ::= AndExpr
8119 * | OrExpr 'or' AndExpr
8120 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008121 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008122 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008123static void
8124xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8125 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008126 CHECK_ERROR;
8127 SKIP_BLANKS;
8128 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008129 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008130 SKIP(2);
8131 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008132 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008133 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008134 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8135 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008136 SKIP_BLANKS;
8137 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008138 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8139 /* more ops could be optimized too */
8140 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8141 }
Owen Taylor3473f882001-02-23 17:55:21 +00008142}
8143
8144/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008145 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008146 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008147 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008148 *
8149 * [8] Predicate ::= '[' PredicateExpr ']'
8150 * [9] PredicateExpr ::= Expr
8151 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008152 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008153 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008154static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008155xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008156 int op1 = ctxt->comp->last;
8157
8158 SKIP_BLANKS;
8159 if (CUR != '[') {
8160 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8161 }
8162 NEXT;
8163 SKIP_BLANKS;
8164
8165 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008166 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008167 CHECK_ERROR;
8168
8169 if (CUR != ']') {
8170 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8171 }
8172
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008173 if (filter)
8174 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8175 else
8176 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008177
8178 NEXT;
8179 SKIP_BLANKS;
8180}
8181
8182/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008183 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008184 * @ctxt: the XPath Parser context
8185 * @test: pointer to a xmlXPathTestVal
8186 * @type: pointer to a xmlXPathTypeVal
8187 * @prefix: placeholder for a possible name prefix
8188 *
8189 * [7] NodeTest ::= NameTest
8190 * | NodeType '(' ')'
8191 * | 'processing-instruction' '(' Literal ')'
8192 *
8193 * [37] NameTest ::= '*'
8194 * | NCName ':' '*'
8195 * | QName
8196 * [38] NodeType ::= 'comment'
8197 * | 'text'
8198 * | 'processing-instruction'
8199 * | 'node'
8200 *
8201 * Returns the name found and update @test, @type and @prefix appropriately
8202 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008203static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008204xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8205 xmlXPathTypeVal *type, const xmlChar **prefix,
8206 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008207 int blanks;
8208
8209 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8210 STRANGE;
8211 return(NULL);
8212 }
8213 *type = 0;
8214 *test = 0;
8215 *prefix = NULL;
8216 SKIP_BLANKS;
8217
8218 if ((name == NULL) && (CUR == '*')) {
8219 /*
8220 * All elements
8221 */
8222 NEXT;
8223 *test = NODE_TEST_ALL;
8224 return(NULL);
8225 }
8226
8227 if (name == NULL)
8228 name = xmlXPathParseNCName(ctxt);
8229 if (name == NULL) {
8230 XP_ERROR0(XPATH_EXPR_ERROR);
8231 }
8232
8233 blanks = IS_BLANK(CUR);
8234 SKIP_BLANKS;
8235 if (CUR == '(') {
8236 NEXT;
8237 /*
8238 * NodeType or PI search
8239 */
8240 if (xmlStrEqual(name, BAD_CAST "comment"))
8241 *type = NODE_TYPE_COMMENT;
8242 else if (xmlStrEqual(name, BAD_CAST "node"))
8243 *type = NODE_TYPE_NODE;
8244 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8245 *type = NODE_TYPE_PI;
8246 else if (xmlStrEqual(name, BAD_CAST "text"))
8247 *type = NODE_TYPE_TEXT;
8248 else {
8249 if (name != NULL)
8250 xmlFree(name);
8251 XP_ERROR0(XPATH_EXPR_ERROR);
8252 }
8253
8254 *test = NODE_TEST_TYPE;
8255
8256 SKIP_BLANKS;
8257 if (*type == NODE_TYPE_PI) {
8258 /*
8259 * Specific case: search a PI by name.
8260 */
Owen Taylor3473f882001-02-23 17:55:21 +00008261 if (name != NULL)
8262 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008263 name = NULL;
8264 if (CUR != ')') {
8265 name = xmlXPathParseLiteral(ctxt);
8266 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008267 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008268 SKIP_BLANKS;
8269 }
Owen Taylor3473f882001-02-23 17:55:21 +00008270 }
8271 if (CUR != ')') {
8272 if (name != NULL)
8273 xmlFree(name);
8274 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8275 }
8276 NEXT;
8277 return(name);
8278 }
8279 *test = NODE_TEST_NAME;
8280 if ((!blanks) && (CUR == ':')) {
8281 NEXT;
8282
8283 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008284 * Since currently the parser context don't have a
8285 * namespace list associated:
8286 * The namespace name for this prefix can be computed
8287 * only at evaluation time. The compilation is done
8288 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008289 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008290#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008291 *prefix = xmlXPathNsLookup(ctxt->context, name);
8292 if (name != NULL)
8293 xmlFree(name);
8294 if (*prefix == NULL) {
8295 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8296 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008297#else
8298 *prefix = name;
8299#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008300
8301 if (CUR == '*') {
8302 /*
8303 * All elements
8304 */
8305 NEXT;
8306 *test = NODE_TEST_ALL;
8307 return(NULL);
8308 }
8309
8310 name = xmlXPathParseNCName(ctxt);
8311 if (name == NULL) {
8312 XP_ERROR0(XPATH_EXPR_ERROR);
8313 }
8314 }
8315 return(name);
8316}
8317
8318/**
8319 * xmlXPathIsAxisName:
8320 * @name: a preparsed name token
8321 *
8322 * [6] AxisName ::= 'ancestor'
8323 * | 'ancestor-or-self'
8324 * | 'attribute'
8325 * | 'child'
8326 * | 'descendant'
8327 * | 'descendant-or-self'
8328 * | 'following'
8329 * | 'following-sibling'
8330 * | 'namespace'
8331 * | 'parent'
8332 * | 'preceding'
8333 * | 'preceding-sibling'
8334 * | 'self'
8335 *
8336 * Returns the axis or 0
8337 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008338static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008339xmlXPathIsAxisName(const xmlChar *name) {
8340 xmlXPathAxisVal ret = 0;
8341 switch (name[0]) {
8342 case 'a':
8343 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8344 ret = AXIS_ANCESTOR;
8345 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8346 ret = AXIS_ANCESTOR_OR_SELF;
8347 if (xmlStrEqual(name, BAD_CAST "attribute"))
8348 ret = AXIS_ATTRIBUTE;
8349 break;
8350 case 'c':
8351 if (xmlStrEqual(name, BAD_CAST "child"))
8352 ret = AXIS_CHILD;
8353 break;
8354 case 'd':
8355 if (xmlStrEqual(name, BAD_CAST "descendant"))
8356 ret = AXIS_DESCENDANT;
8357 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8358 ret = AXIS_DESCENDANT_OR_SELF;
8359 break;
8360 case 'f':
8361 if (xmlStrEqual(name, BAD_CAST "following"))
8362 ret = AXIS_FOLLOWING;
8363 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8364 ret = AXIS_FOLLOWING_SIBLING;
8365 break;
8366 case 'n':
8367 if (xmlStrEqual(name, BAD_CAST "namespace"))
8368 ret = AXIS_NAMESPACE;
8369 break;
8370 case 'p':
8371 if (xmlStrEqual(name, BAD_CAST "parent"))
8372 ret = AXIS_PARENT;
8373 if (xmlStrEqual(name, BAD_CAST "preceding"))
8374 ret = AXIS_PRECEDING;
8375 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8376 ret = AXIS_PRECEDING_SIBLING;
8377 break;
8378 case 's':
8379 if (xmlStrEqual(name, BAD_CAST "self"))
8380 ret = AXIS_SELF;
8381 break;
8382 }
8383 return(ret);
8384}
8385
8386/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008387 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008388 * @ctxt: the XPath Parser context
8389 *
8390 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8391 * | AbbreviatedStep
8392 *
8393 * [12] AbbreviatedStep ::= '.' | '..'
8394 *
8395 * [5] AxisSpecifier ::= AxisName '::'
8396 * | AbbreviatedAxisSpecifier
8397 *
8398 * [13] AbbreviatedAxisSpecifier ::= '@'?
8399 *
8400 * Modified for XPtr range support as:
8401 *
8402 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8403 * | AbbreviatedStep
8404 * | 'range-to' '(' Expr ')' Predicate*
8405 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008406 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008407 * A location step of . is short for self::node(). This is
8408 * particularly useful in conjunction with //. For example, the
8409 * location path .//para is short for
8410 * self::node()/descendant-or-self::node()/child::para
8411 * and so will select all para descendant elements of the context
8412 * node.
8413 * Similarly, a location step of .. is short for parent::node().
8414 * For example, ../title is short for parent::node()/child::title
8415 * and so will select the title children of the parent of the context
8416 * node.
8417 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008418static void
8419xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008420#ifdef LIBXML_XPTR_ENABLED
8421 int rangeto = 0;
8422 int op2 = -1;
8423#endif
8424
Owen Taylor3473f882001-02-23 17:55:21 +00008425 SKIP_BLANKS;
8426 if ((CUR == '.') && (NXT(1) == '.')) {
8427 SKIP(2);
8428 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008429 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8430 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008431 } else if (CUR == '.') {
8432 NEXT;
8433 SKIP_BLANKS;
8434 } else {
8435 xmlChar *name = NULL;
8436 const xmlChar *prefix = NULL;
8437 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008438 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008439 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008440 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008441
8442 /*
8443 * The modification needed for XPointer change to the production
8444 */
8445#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008446 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008447 name = xmlXPathParseNCName(ctxt);
8448 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008449 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008450 xmlFree(name);
8451 SKIP_BLANKS;
8452 if (CUR != '(') {
8453 XP_ERROR(XPATH_EXPR_ERROR);
8454 }
8455 NEXT;
8456 SKIP_BLANKS;
8457
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008458 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008459 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008460 CHECK_ERROR;
8461
8462 SKIP_BLANKS;
8463 if (CUR != ')') {
8464 XP_ERROR(XPATH_EXPR_ERROR);
8465 }
8466 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008467 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008468 goto eval_predicates;
8469 }
8470 }
8471#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008472 if (CUR == '*') {
8473 axis = AXIS_CHILD;
8474 } else {
8475 if (name == NULL)
8476 name = xmlXPathParseNCName(ctxt);
8477 if (name != NULL) {
8478 axis = xmlXPathIsAxisName(name);
8479 if (axis != 0) {
8480 SKIP_BLANKS;
8481 if ((CUR == ':') && (NXT(1) == ':')) {
8482 SKIP(2);
8483 xmlFree(name);
8484 name = NULL;
8485 } else {
8486 /* an element name can conflict with an axis one :-\ */
8487 axis = AXIS_CHILD;
8488 }
Owen Taylor3473f882001-02-23 17:55:21 +00008489 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008490 axis = AXIS_CHILD;
8491 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008492 } else if (CUR == '@') {
8493 NEXT;
8494 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008495 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008496 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008497 }
Owen Taylor3473f882001-02-23 17:55:21 +00008498 }
8499
8500 CHECK_ERROR;
8501
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008502 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008503 if (test == 0)
8504 return;
8505
8506#ifdef DEBUG_STEP
8507 xmlGenericError(xmlGenericErrorContext,
8508 "Basis : computing new set\n");
8509#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008510
Owen Taylor3473f882001-02-23 17:55:21 +00008511#ifdef DEBUG_STEP
8512 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008513 if (ctxt->value == NULL)
8514 xmlGenericError(xmlGenericErrorContext, "no value\n");
8515 else if (ctxt->value->nodesetval == NULL)
8516 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8517 else
8518 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008519#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008520
8521eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008522 op1 = ctxt->comp->last;
8523 ctxt->comp->last = -1;
8524
Owen Taylor3473f882001-02-23 17:55:21 +00008525 SKIP_BLANKS;
8526 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008527 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008528 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008529
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008530#ifdef LIBXML_XPTR_ENABLED
8531 if (rangeto) {
8532 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8533 } else
8534#endif
8535 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8536 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008537
Owen Taylor3473f882001-02-23 17:55:21 +00008538 }
8539#ifdef DEBUG_STEP
8540 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008541 if (ctxt->value == NULL)
8542 xmlGenericError(xmlGenericErrorContext, "no value\n");
8543 else if (ctxt->value->nodesetval == NULL)
8544 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8545 else
8546 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8547 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008548#endif
8549}
8550
8551/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008552 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008553 * @ctxt: the XPath Parser context
8554 *
8555 * [3] RelativeLocationPath ::= Step
8556 * | RelativeLocationPath '/' Step
8557 * | AbbreviatedRelativeLocationPath
8558 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8559 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008560 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008561 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008562static void
Owen Taylor3473f882001-02-23 17:55:21 +00008563#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008564xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008565#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008566xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008567#endif
8568(xmlXPathParserContextPtr ctxt) {
8569 SKIP_BLANKS;
8570 if ((CUR == '/') && (NXT(1) == '/')) {
8571 SKIP(2);
8572 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008573 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8574 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008575 } else if (CUR == '/') {
8576 NEXT;
8577 SKIP_BLANKS;
8578 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008579 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008580 SKIP_BLANKS;
8581 while (CUR == '/') {
8582 if ((CUR == '/') && (NXT(1) == '/')) {
8583 SKIP(2);
8584 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008585 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008586 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008587 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008588 } else if (CUR == '/') {
8589 NEXT;
8590 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008591 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008592 }
8593 SKIP_BLANKS;
8594 }
8595}
8596
8597/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008598 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008599 * @ctxt: the XPath Parser context
8600 *
8601 * [1] LocationPath ::= RelativeLocationPath
8602 * | AbsoluteLocationPath
8603 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8604 * | AbbreviatedAbsoluteLocationPath
8605 * [10] AbbreviatedAbsoluteLocationPath ::=
8606 * '//' RelativeLocationPath
8607 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008608 * Compile a location path
8609 *
Owen Taylor3473f882001-02-23 17:55:21 +00008610 * // is short for /descendant-or-self::node()/. For example,
8611 * //para is short for /descendant-or-self::node()/child::para and
8612 * so will select any para element in the document (even a para element
8613 * that is a document element will be selected by //para since the
8614 * document element node is a child of the root node); div//para is
8615 * short for div/descendant-or-self::node()/child::para and so will
8616 * select all para descendants of div children.
8617 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008618static void
8619xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008620 SKIP_BLANKS;
8621 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008622 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008623 } else {
8624 while (CUR == '/') {
8625 if ((CUR == '/') && (NXT(1) == '/')) {
8626 SKIP(2);
8627 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008628 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8629 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008630 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008631 } else if (CUR == '/') {
8632 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008633 SKIP_BLANKS;
8634 if ((CUR != 0 ) &&
8635 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8636 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008637 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008638 }
8639 }
8640 }
8641}
8642
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008643/************************************************************************
8644 * *
8645 * XPath precompiled expression evaluation *
8646 * *
8647 ************************************************************************/
8648
Daniel Veillardf06307e2001-07-03 10:35:50 +00008649static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008650xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8651
8652/**
8653 * xmlXPathNodeCollectAndTest:
8654 * @ctxt: the XPath Parser context
8655 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008656 * @first: pointer to the first element in document order
8657 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008658 *
8659 * This is the function implementing a step: based on the current list
8660 * of nodes, it builds up a new list, looking at all nodes under that
8661 * axis and selecting them it also do the predicate filtering
8662 *
8663 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008664 *
8665 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008666 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008667static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008668xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008669 xmlXPathStepOpPtr op,
8670 xmlNodePtr * first, xmlNodePtr * last)
8671{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008672 xmlXPathAxisVal axis = op->value;
8673 xmlXPathTestVal test = op->value2;
8674 xmlXPathTypeVal type = op->value3;
8675 const xmlChar *prefix = op->value4;
8676 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008677 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008678
8679#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008680 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008681#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008682 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008683 xmlNodeSetPtr ret, list;
8684 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008685 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008686 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008687 xmlNodePtr cur = NULL;
8688 xmlXPathObjectPtr obj;
8689 xmlNodeSetPtr nodelist;
8690 xmlNodePtr tmp;
8691
Daniel Veillardf06307e2001-07-03 10:35:50 +00008692 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008693 obj = valuePop(ctxt);
8694 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008695 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008696 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008697 URI = xmlXPathNsLookup(ctxt->context, prefix);
8698 if (URI == NULL)
8699 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008700 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008701#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008702 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008703#endif
8704 switch (axis) {
8705 case AXIS_ANCESTOR:
8706#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008707 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008708#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008709 first = NULL;
8710 next = xmlXPathNextAncestor;
8711 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008712 case AXIS_ANCESTOR_OR_SELF:
8713#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008714 xmlGenericError(xmlGenericErrorContext,
8715 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008716#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008717 first = NULL;
8718 next = xmlXPathNextAncestorOrSelf;
8719 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008720 case AXIS_ATTRIBUTE:
8721#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008722 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008723#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008724 first = NULL;
8725 last = NULL;
8726 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008727 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008728 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008729 case AXIS_CHILD:
8730#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008731 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008732#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008733 last = NULL;
8734 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008735 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008736 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008737 case AXIS_DESCENDANT:
8738#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008739 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008740#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008741 last = NULL;
8742 next = xmlXPathNextDescendant;
8743 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008744 case AXIS_DESCENDANT_OR_SELF:
8745#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008746 xmlGenericError(xmlGenericErrorContext,
8747 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008748#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008749 last = NULL;
8750 next = xmlXPathNextDescendantOrSelf;
8751 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008752 case AXIS_FOLLOWING:
8753#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008754 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008755#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008756 last = NULL;
8757 next = xmlXPathNextFollowing;
8758 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008759 case AXIS_FOLLOWING_SIBLING:
8760#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008761 xmlGenericError(xmlGenericErrorContext,
8762 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008763#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008764 last = NULL;
8765 next = xmlXPathNextFollowingSibling;
8766 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008767 case AXIS_NAMESPACE:
8768#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008769 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008770#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008771 first = NULL;
8772 last = NULL;
8773 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008774 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008775 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008776 case AXIS_PARENT:
8777#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008778 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008779#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008780 first = NULL;
8781 next = xmlXPathNextParent;
8782 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008783 case AXIS_PRECEDING:
8784#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008785 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008786#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008787 first = NULL;
8788 next = xmlXPathNextPrecedingInternal;
8789 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008790 case AXIS_PRECEDING_SIBLING:
8791#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008792 xmlGenericError(xmlGenericErrorContext,
8793 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008794#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008795 first = NULL;
8796 next = xmlXPathNextPrecedingSibling;
8797 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008798 case AXIS_SELF:
8799#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008800 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008801#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008802 first = NULL;
8803 last = NULL;
8804 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008805 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008806 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008807 }
8808 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008809 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008810
8811 nodelist = obj->nodesetval;
8812 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008813 xmlXPathFreeObject(obj);
8814 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8815 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008816 }
8817 addNode = xmlXPathNodeSetAddUnique;
8818 ret = NULL;
8819#ifdef DEBUG_STEP
8820 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008821 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008822 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008823 case NODE_TEST_NONE:
8824 xmlGenericError(xmlGenericErrorContext,
8825 " searching for none !!!\n");
8826 break;
8827 case NODE_TEST_TYPE:
8828 xmlGenericError(xmlGenericErrorContext,
8829 " searching for type %d\n", type);
8830 break;
8831 case NODE_TEST_PI:
8832 xmlGenericError(xmlGenericErrorContext,
8833 " searching for PI !!!\n");
8834 break;
8835 case NODE_TEST_ALL:
8836 xmlGenericError(xmlGenericErrorContext,
8837 " searching for *\n");
8838 break;
8839 case NODE_TEST_NS:
8840 xmlGenericError(xmlGenericErrorContext,
8841 " searching for namespace %s\n",
8842 prefix);
8843 break;
8844 case NODE_TEST_NAME:
8845 xmlGenericError(xmlGenericErrorContext,
8846 " searching for name %s\n", name);
8847 if (prefix != NULL)
8848 xmlGenericError(xmlGenericErrorContext,
8849 " with namespace %s\n", prefix);
8850 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008851 }
8852 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8853#endif
8854 /*
8855 * 2.3 Node Tests
8856 * - For the attribute axis, the principal node type is attribute.
8857 * - For the namespace axis, the principal node type is namespace.
8858 * - For other axes, the principal node type is element.
8859 *
8860 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008861 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008862 * select all element children of the context node
8863 */
8864 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008865 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008866 ctxt->context->node = nodelist->nodeTab[i];
8867
Daniel Veillardf06307e2001-07-03 10:35:50 +00008868 cur = NULL;
8869 list = xmlXPathNodeSetCreate(NULL);
8870 do {
8871 cur = next(ctxt, cur);
8872 if (cur == NULL)
8873 break;
8874 if ((first != NULL) && (*first == cur))
8875 break;
8876 if (((t % 256) == 0) &&
8877 (first != NULL) && (*first != NULL) &&
8878 (xmlXPathCmpNodes(*first, cur) >= 0))
8879 break;
8880 if ((last != NULL) && (*last == cur))
8881 break;
8882 if (((t % 256) == 0) &&
8883 (last != NULL) && (*last != NULL) &&
8884 (xmlXPathCmpNodes(cur, *last) >= 0))
8885 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008886 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008887#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008888 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8889#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008890 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008891 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008892 ctxt->context->node = tmp;
8893 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008894 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008895 if ((cur->type == type) ||
8896 ((type == NODE_TYPE_NODE) &&
8897 ((cur->type == XML_DOCUMENT_NODE) ||
8898 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8899 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008900 (cur->type == XML_NAMESPACE_DECL) ||
8901 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 (cur->type == XML_PI_NODE) ||
8903 (cur->type == XML_COMMENT_NODE) ||
8904 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008905 (cur->type == XML_TEXT_NODE))) ||
8906 ((type == NODE_TYPE_TEXT) &&
8907 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008908#ifdef DEBUG_STEP
8909 n++;
8910#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008911 addNode(list, cur);
8912 }
8913 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008914 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008915 if (cur->type == XML_PI_NODE) {
8916 if ((name != NULL) &&
8917 (!xmlStrEqual(name, cur->name)))
8918 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008919#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008920 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008921#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008922 addNode(list, cur);
8923 }
8924 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008925 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008926 if (axis == AXIS_ATTRIBUTE) {
8927 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008928#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008930#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008931 addNode(list, cur);
8932 }
8933 } else if (axis == AXIS_NAMESPACE) {
8934 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008935#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008936 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008937#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008938 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8939 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008940 }
8941 } else {
8942 if (cur->type == XML_ELEMENT_NODE) {
8943 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008944#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008945 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008946#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008947 addNode(list, cur);
8948 } else if ((cur->ns != NULL) &&
8949 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008950#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008951 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008952#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008953 addNode(list, cur);
8954 }
8955 }
8956 }
8957 break;
8958 case NODE_TEST_NS:{
8959 TODO;
8960 break;
8961 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008962 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008963 switch (cur->type) {
8964 case XML_ELEMENT_NODE:
8965 if (xmlStrEqual(name, cur->name)) {
8966 if (prefix == NULL) {
8967 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008968#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008971 addNode(list, cur);
8972 }
8973 } else {
8974 if ((cur->ns != NULL) &&
8975 (xmlStrEqual(URI,
8976 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008978 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008979#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 addNode(list, cur);
8981 }
8982 }
8983 }
8984 break;
8985 case XML_ATTRIBUTE_NODE:{
8986 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008987
Daniel Veillardf06307e2001-07-03 10:35:50 +00008988 if (xmlStrEqual(name, attr->name)) {
8989 if (prefix == NULL) {
8990 if ((attr->ns == NULL) ||
8991 (attr->ns->prefix == NULL)) {
8992#ifdef DEBUG_STEP
8993 n++;
8994#endif
8995 addNode(list,
8996 (xmlNodePtr) attr);
8997 }
8998 } else {
8999 if ((attr->ns != NULL) &&
9000 (xmlStrEqual(URI,
9001 attr->ns->
9002 href))) {
9003#ifdef DEBUG_STEP
9004 n++;
9005#endif
9006 addNode(list,
9007 (xmlNodePtr) attr);
9008 }
9009 }
9010 }
9011 break;
9012 }
9013 case XML_NAMESPACE_DECL:
9014 if (cur->type == XML_NAMESPACE_DECL) {
9015 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009016
Daniel Veillardf06307e2001-07-03 10:35:50 +00009017 if ((ns->prefix != NULL) && (name != NULL)
9018 && (xmlStrEqual(ns->prefix, name))) {
9019#ifdef DEBUG_STEP
9020 n++;
9021#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009022 xmlXPathNodeSetAddNs(list,
9023 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009024 }
9025 }
9026 break;
9027 default:
9028 break;
9029 }
9030 break;
9031 break;
9032 }
9033 } while (cur != NULL);
9034
9035 /*
9036 * If there is some predicate filtering do it now
9037 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009038 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009039 xmlXPathObjectPtr obj2;
9040
9041 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9042 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9043 CHECK_TYPE0(XPATH_NODESET);
9044 obj2 = valuePop(ctxt);
9045 list = obj2->nodesetval;
9046 obj2->nodesetval = NULL;
9047 xmlXPathFreeObject(obj2);
9048 }
9049 if (ret == NULL) {
9050 ret = list;
9051 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009052 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 xmlXPathFreeNodeSet(list);
9054 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009055 }
9056 ctxt->context->node = tmp;
9057#ifdef DEBUG_STEP
9058 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009059 "\nExamined %d nodes, found %d nodes at that step\n",
9060 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009061#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009062 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009063 if ((obj->boolval) && (obj->user != NULL)) {
9064 ctxt->value->boolval = 1;
9065 ctxt->value->user = obj->user;
9066 obj->user = NULL;
9067 obj->boolval = 0;
9068 }
9069 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009070 return(t);
9071}
9072
9073/**
9074 * xmlXPathNodeCollectAndTestNth:
9075 * @ctxt: the XPath Parser context
9076 * @op: the XPath precompiled step operation
9077 * @indx: the index to collect
9078 * @first: pointer to the first element in document order
9079 * @last: pointer to the last element in document order
9080 *
9081 * This is the function implementing a step: based on the current list
9082 * of nodes, it builds up a new list, looking at all nodes under that
9083 * axis and selecting them it also do the predicate filtering
9084 *
9085 * Pushes the new NodeSet resulting from the search.
9086 * Returns the number of node traversed
9087 */
9088static int
9089xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9090 xmlXPathStepOpPtr op, int indx,
9091 xmlNodePtr * first, xmlNodePtr * last)
9092{
9093 xmlXPathAxisVal axis = op->value;
9094 xmlXPathTestVal test = op->value2;
9095 xmlXPathTypeVal type = op->value3;
9096 const xmlChar *prefix = op->value4;
9097 const xmlChar *name = op->value5;
9098 const xmlChar *URI = NULL;
9099 int n = 0, t = 0;
9100
9101 int i;
9102 xmlNodeSetPtr list;
9103 xmlXPathTraversalFunction next = NULL;
9104 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9105 xmlNodePtr cur = NULL;
9106 xmlXPathObjectPtr obj;
9107 xmlNodeSetPtr nodelist;
9108 xmlNodePtr tmp;
9109
9110 CHECK_TYPE0(XPATH_NODESET);
9111 obj = valuePop(ctxt);
9112 addNode = xmlXPathNodeSetAdd;
9113 if (prefix != NULL) {
9114 URI = xmlXPathNsLookup(ctxt->context, prefix);
9115 if (URI == NULL)
9116 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9117 }
9118#ifdef DEBUG_STEP_NTH
9119 xmlGenericError(xmlGenericErrorContext, "new step : ");
9120 if (first != NULL) {
9121 if (*first != NULL)
9122 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9123 (*first)->name);
9124 else
9125 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9126 }
9127 if (last != NULL) {
9128 if (*last != NULL)
9129 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9130 (*last)->name);
9131 else
9132 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9133 }
9134#endif
9135 switch (axis) {
9136 case AXIS_ANCESTOR:
9137#ifdef DEBUG_STEP_NTH
9138 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9139#endif
9140 first = NULL;
9141 next = xmlXPathNextAncestor;
9142 break;
9143 case AXIS_ANCESTOR_OR_SELF:
9144#ifdef DEBUG_STEP_NTH
9145 xmlGenericError(xmlGenericErrorContext,
9146 "axis 'ancestors-or-self' ");
9147#endif
9148 first = NULL;
9149 next = xmlXPathNextAncestorOrSelf;
9150 break;
9151 case AXIS_ATTRIBUTE:
9152#ifdef DEBUG_STEP_NTH
9153 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9154#endif
9155 first = NULL;
9156 last = NULL;
9157 next = xmlXPathNextAttribute;
9158 break;
9159 case AXIS_CHILD:
9160#ifdef DEBUG_STEP_NTH
9161 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9162#endif
9163 last = NULL;
9164 next = xmlXPathNextChild;
9165 break;
9166 case AXIS_DESCENDANT:
9167#ifdef DEBUG_STEP_NTH
9168 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9169#endif
9170 last = NULL;
9171 next = xmlXPathNextDescendant;
9172 break;
9173 case AXIS_DESCENDANT_OR_SELF:
9174#ifdef DEBUG_STEP_NTH
9175 xmlGenericError(xmlGenericErrorContext,
9176 "axis 'descendant-or-self' ");
9177#endif
9178 last = NULL;
9179 next = xmlXPathNextDescendantOrSelf;
9180 break;
9181 case AXIS_FOLLOWING:
9182#ifdef DEBUG_STEP_NTH
9183 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9184#endif
9185 last = NULL;
9186 next = xmlXPathNextFollowing;
9187 break;
9188 case AXIS_FOLLOWING_SIBLING:
9189#ifdef DEBUG_STEP_NTH
9190 xmlGenericError(xmlGenericErrorContext,
9191 "axis 'following-siblings' ");
9192#endif
9193 last = NULL;
9194 next = xmlXPathNextFollowingSibling;
9195 break;
9196 case AXIS_NAMESPACE:
9197#ifdef DEBUG_STEP_NTH
9198 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9199#endif
9200 last = NULL;
9201 first = NULL;
9202 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9203 break;
9204 case AXIS_PARENT:
9205#ifdef DEBUG_STEP_NTH
9206 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9207#endif
9208 first = NULL;
9209 next = xmlXPathNextParent;
9210 break;
9211 case AXIS_PRECEDING:
9212#ifdef DEBUG_STEP_NTH
9213 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9214#endif
9215 first = NULL;
9216 next = xmlXPathNextPrecedingInternal;
9217 break;
9218 case AXIS_PRECEDING_SIBLING:
9219#ifdef DEBUG_STEP_NTH
9220 xmlGenericError(xmlGenericErrorContext,
9221 "axis 'preceding-sibling' ");
9222#endif
9223 first = NULL;
9224 next = xmlXPathNextPrecedingSibling;
9225 break;
9226 case AXIS_SELF:
9227#ifdef DEBUG_STEP_NTH
9228 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9229#endif
9230 first = NULL;
9231 last = NULL;
9232 next = xmlXPathNextSelf;
9233 break;
9234 }
9235 if (next == NULL)
9236 return(0);
9237
9238 nodelist = obj->nodesetval;
9239 if (nodelist == NULL) {
9240 xmlXPathFreeObject(obj);
9241 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9242 return(0);
9243 }
9244 addNode = xmlXPathNodeSetAddUnique;
9245#ifdef DEBUG_STEP_NTH
9246 xmlGenericError(xmlGenericErrorContext,
9247 " context contains %d nodes\n", nodelist->nodeNr);
9248 switch (test) {
9249 case NODE_TEST_NONE:
9250 xmlGenericError(xmlGenericErrorContext,
9251 " searching for none !!!\n");
9252 break;
9253 case NODE_TEST_TYPE:
9254 xmlGenericError(xmlGenericErrorContext,
9255 " searching for type %d\n", type);
9256 break;
9257 case NODE_TEST_PI:
9258 xmlGenericError(xmlGenericErrorContext,
9259 " searching for PI !!!\n");
9260 break;
9261 case NODE_TEST_ALL:
9262 xmlGenericError(xmlGenericErrorContext,
9263 " searching for *\n");
9264 break;
9265 case NODE_TEST_NS:
9266 xmlGenericError(xmlGenericErrorContext,
9267 " searching for namespace %s\n",
9268 prefix);
9269 break;
9270 case NODE_TEST_NAME:
9271 xmlGenericError(xmlGenericErrorContext,
9272 " searching for name %s\n", name);
9273 if (prefix != NULL)
9274 xmlGenericError(xmlGenericErrorContext,
9275 " with namespace %s\n", prefix);
9276 break;
9277 }
9278 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9279#endif
9280 /*
9281 * 2.3 Node Tests
9282 * - For the attribute axis, the principal node type is attribute.
9283 * - For the namespace axis, the principal node type is namespace.
9284 * - For other axes, the principal node type is element.
9285 *
9286 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009287 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009288 * select all element children of the context node
9289 */
9290 tmp = ctxt->context->node;
9291 list = xmlXPathNodeSetCreate(NULL);
9292 for (i = 0; i < nodelist->nodeNr; i++) {
9293 ctxt->context->node = nodelist->nodeTab[i];
9294
9295 cur = NULL;
9296 n = 0;
9297 do {
9298 cur = next(ctxt, cur);
9299 if (cur == NULL)
9300 break;
9301 if ((first != NULL) && (*first == cur))
9302 break;
9303 if (((t % 256) == 0) &&
9304 (first != NULL) && (*first != NULL) &&
9305 (xmlXPathCmpNodes(*first, cur) >= 0))
9306 break;
9307 if ((last != NULL) && (*last == cur))
9308 break;
9309 if (((t % 256) == 0) &&
9310 (last != NULL) && (*last != NULL) &&
9311 (xmlXPathCmpNodes(cur, *last) >= 0))
9312 break;
9313 t++;
9314 switch (test) {
9315 case NODE_TEST_NONE:
9316 ctxt->context->node = tmp;
9317 STRANGE return(0);
9318 case NODE_TEST_TYPE:
9319 if ((cur->type == type) ||
9320 ((type == NODE_TYPE_NODE) &&
9321 ((cur->type == XML_DOCUMENT_NODE) ||
9322 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9323 (cur->type == XML_ELEMENT_NODE) ||
9324 (cur->type == XML_PI_NODE) ||
9325 (cur->type == XML_COMMENT_NODE) ||
9326 (cur->type == XML_CDATA_SECTION_NODE) ||
9327 (cur->type == XML_TEXT_NODE)))) {
9328 n++;
9329 if (n == indx)
9330 addNode(list, cur);
9331 }
9332 break;
9333 case NODE_TEST_PI:
9334 if (cur->type == XML_PI_NODE) {
9335 if ((name != NULL) &&
9336 (!xmlStrEqual(name, cur->name)))
9337 break;
9338 n++;
9339 if (n == indx)
9340 addNode(list, cur);
9341 }
9342 break;
9343 case NODE_TEST_ALL:
9344 if (axis == AXIS_ATTRIBUTE) {
9345 if (cur->type == XML_ATTRIBUTE_NODE) {
9346 n++;
9347 if (n == indx)
9348 addNode(list, cur);
9349 }
9350 } else if (axis == AXIS_NAMESPACE) {
9351 if (cur->type == XML_NAMESPACE_DECL) {
9352 n++;
9353 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009354 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9355 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009356 }
9357 } else {
9358 if (cur->type == XML_ELEMENT_NODE) {
9359 if (prefix == NULL) {
9360 n++;
9361 if (n == indx)
9362 addNode(list, cur);
9363 } else if ((cur->ns != NULL) &&
9364 (xmlStrEqual(URI, cur->ns->href))) {
9365 n++;
9366 if (n == indx)
9367 addNode(list, cur);
9368 }
9369 }
9370 }
9371 break;
9372 case NODE_TEST_NS:{
9373 TODO;
9374 break;
9375 }
9376 case NODE_TEST_NAME:
9377 switch (cur->type) {
9378 case XML_ELEMENT_NODE:
9379 if (xmlStrEqual(name, cur->name)) {
9380 if (prefix == NULL) {
9381 if (cur->ns == NULL) {
9382 n++;
9383 if (n == indx)
9384 addNode(list, cur);
9385 }
9386 } else {
9387 if ((cur->ns != NULL) &&
9388 (xmlStrEqual(URI,
9389 cur->ns->href))) {
9390 n++;
9391 if (n == indx)
9392 addNode(list, cur);
9393 }
9394 }
9395 }
9396 break;
9397 case XML_ATTRIBUTE_NODE:{
9398 xmlAttrPtr attr = (xmlAttrPtr) cur;
9399
9400 if (xmlStrEqual(name, attr->name)) {
9401 if (prefix == NULL) {
9402 if ((attr->ns == NULL) ||
9403 (attr->ns->prefix == NULL)) {
9404 n++;
9405 if (n == indx)
9406 addNode(list, cur);
9407 }
9408 } else {
9409 if ((attr->ns != NULL) &&
9410 (xmlStrEqual(URI,
9411 attr->ns->
9412 href))) {
9413 n++;
9414 if (n == indx)
9415 addNode(list, cur);
9416 }
9417 }
9418 }
9419 break;
9420 }
9421 case XML_NAMESPACE_DECL:
9422 if (cur->type == XML_NAMESPACE_DECL) {
9423 xmlNsPtr ns = (xmlNsPtr) cur;
9424
9425 if ((ns->prefix != NULL) && (name != NULL)
9426 && (xmlStrEqual(ns->prefix, name))) {
9427 n++;
9428 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009429 xmlXPathNodeSetAddNs(list,
9430 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009431 }
9432 }
9433 break;
9434 default:
9435 break;
9436 }
9437 break;
9438 break;
9439 }
9440 } while (n < indx);
9441 }
9442 ctxt->context->node = tmp;
9443#ifdef DEBUG_STEP_NTH
9444 xmlGenericError(xmlGenericErrorContext,
9445 "\nExamined %d nodes, found %d nodes at that step\n",
9446 t, list->nodeNr);
9447#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009448 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009449 if ((obj->boolval) && (obj->user != NULL)) {
9450 ctxt->value->boolval = 1;
9451 ctxt->value->user = obj->user;
9452 obj->user = NULL;
9453 obj->boolval = 0;
9454 }
9455 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009456 return(t);
9457}
9458
9459/**
9460 * xmlXPathCompOpEvalFirst:
9461 * @ctxt: the XPath parser context with the compiled expression
9462 * @op: an XPath compiled operation
9463 * @first: the first elem found so far
9464 *
9465 * Evaluate the Precompiled XPath operation searching only the first
9466 * element in document order
9467 *
9468 * Returns the number of examined objects.
9469 */
9470static int
9471xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9472 xmlXPathStepOpPtr op, xmlNodePtr * first)
9473{
9474 int total = 0, cur;
9475 xmlXPathCompExprPtr comp;
9476 xmlXPathObjectPtr arg1, arg2;
9477
Daniel Veillard556c6682001-10-06 09:59:51 +00009478 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009479 comp = ctxt->comp;
9480 switch (op->op) {
9481 case XPATH_OP_END:
9482 return (0);
9483 case XPATH_OP_UNION:
9484 total =
9485 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9486 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009487 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009488 if ((ctxt->value != NULL)
9489 && (ctxt->value->type == XPATH_NODESET)
9490 && (ctxt->value->nodesetval != NULL)
9491 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9492 /*
9493 * limit tree traversing to first node in the result
9494 */
9495 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9496 *first = ctxt->value->nodesetval->nodeTab[0];
9497 }
9498 cur =
9499 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9500 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009501 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009502 CHECK_TYPE0(XPATH_NODESET);
9503 arg2 = valuePop(ctxt);
9504
9505 CHECK_TYPE0(XPATH_NODESET);
9506 arg1 = valuePop(ctxt);
9507
9508 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9509 arg2->nodesetval);
9510 valuePush(ctxt, arg1);
9511 xmlXPathFreeObject(arg2);
9512 /* optimizer */
9513 if (total > cur)
9514 xmlXPathCompSwap(op);
9515 return (total + cur);
9516 case XPATH_OP_ROOT:
9517 xmlXPathRoot(ctxt);
9518 return (0);
9519 case XPATH_OP_NODE:
9520 if (op->ch1 != -1)
9521 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009522 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009523 if (op->ch2 != -1)
9524 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009525 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009526 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9527 return (total);
9528 case XPATH_OP_RESET:
9529 if (op->ch1 != -1)
9530 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009531 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009532 if (op->ch2 != -1)
9533 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009534 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009535 ctxt->context->node = NULL;
9536 return (total);
9537 case XPATH_OP_COLLECT:{
9538 if (op->ch1 == -1)
9539 return (total);
9540
9541 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009542 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009543
9544 /*
9545 * Optimization for [n] selection where n is a number
9546 */
9547 if ((op->ch2 != -1) &&
9548 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9549 (comp->steps[op->ch2].ch1 == -1) &&
9550 (comp->steps[op->ch2].ch2 != -1) &&
9551 (comp->steps[comp->steps[op->ch2].ch2].op ==
9552 XPATH_OP_VALUE)) {
9553 xmlXPathObjectPtr val;
9554
9555 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9556 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9557 int indx = (int) val->floatval;
9558
9559 if (val->floatval == (float) indx) {
9560 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9561 first, NULL);
9562 return (total);
9563 }
9564 }
9565 }
9566 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9567 return (total);
9568 }
9569 case XPATH_OP_VALUE:
9570 valuePush(ctxt,
9571 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9572 return (0);
9573 case XPATH_OP_SORT:
9574 if (op->ch1 != -1)
9575 total +=
9576 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9577 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009578 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009579 if ((ctxt->value != NULL)
9580 && (ctxt->value->type == XPATH_NODESET)
9581 && (ctxt->value->nodesetval != NULL))
9582 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9583 return (total);
9584 default:
9585 return (xmlXPathCompOpEval(ctxt, op));
9586 }
9587}
9588
9589/**
9590 * xmlXPathCompOpEvalLast:
9591 * @ctxt: the XPath parser context with the compiled expression
9592 * @op: an XPath compiled operation
9593 * @last: the last elem found so far
9594 *
9595 * Evaluate the Precompiled XPath operation searching only the last
9596 * element in document order
9597 *
9598 * Returns the number of node traversed
9599 */
9600static int
9601xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9602 xmlNodePtr * last)
9603{
9604 int total = 0, cur;
9605 xmlXPathCompExprPtr comp;
9606 xmlXPathObjectPtr arg1, arg2;
9607
Daniel Veillard556c6682001-10-06 09:59:51 +00009608 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009609 comp = ctxt->comp;
9610 switch (op->op) {
9611 case XPATH_OP_END:
9612 return (0);
9613 case XPATH_OP_UNION:
9614 total =
9615 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009616 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009617 if ((ctxt->value != NULL)
9618 && (ctxt->value->type == XPATH_NODESET)
9619 && (ctxt->value->nodesetval != NULL)
9620 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9621 /*
9622 * limit tree traversing to first node in the result
9623 */
9624 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9625 *last =
9626 ctxt->value->nodesetval->nodeTab[ctxt->value->
9627 nodesetval->nodeNr -
9628 1];
9629 }
9630 cur =
9631 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009632 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009633 if ((ctxt->value != NULL)
9634 && (ctxt->value->type == XPATH_NODESET)
9635 && (ctxt->value->nodesetval != NULL)
9636 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9637 }
9638 CHECK_TYPE0(XPATH_NODESET);
9639 arg2 = valuePop(ctxt);
9640
9641 CHECK_TYPE0(XPATH_NODESET);
9642 arg1 = valuePop(ctxt);
9643
9644 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9645 arg2->nodesetval);
9646 valuePush(ctxt, arg1);
9647 xmlXPathFreeObject(arg2);
9648 /* optimizer */
9649 if (total > cur)
9650 xmlXPathCompSwap(op);
9651 return (total + cur);
9652 case XPATH_OP_ROOT:
9653 xmlXPathRoot(ctxt);
9654 return (0);
9655 case XPATH_OP_NODE:
9656 if (op->ch1 != -1)
9657 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009658 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009659 if (op->ch2 != -1)
9660 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009661 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009662 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9663 return (total);
9664 case XPATH_OP_RESET:
9665 if (op->ch1 != -1)
9666 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009667 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009668 if (op->ch2 != -1)
9669 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009670 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009671 ctxt->context->node = NULL;
9672 return (total);
9673 case XPATH_OP_COLLECT:{
9674 if (op->ch1 == -1)
9675 return (0);
9676
9677 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009678 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009679
9680 /*
9681 * Optimization for [n] selection where n is a number
9682 */
9683 if ((op->ch2 != -1) &&
9684 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9685 (comp->steps[op->ch2].ch1 == -1) &&
9686 (comp->steps[op->ch2].ch2 != -1) &&
9687 (comp->steps[comp->steps[op->ch2].ch2].op ==
9688 XPATH_OP_VALUE)) {
9689 xmlXPathObjectPtr val;
9690
9691 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9692 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9693 int indx = (int) val->floatval;
9694
9695 if (val->floatval == (float) indx) {
9696 total +=
9697 xmlXPathNodeCollectAndTestNth(ctxt, op,
9698 indx, NULL,
9699 last);
9700 return (total);
9701 }
9702 }
9703 }
9704 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9705 return (total);
9706 }
9707 case XPATH_OP_VALUE:
9708 valuePush(ctxt,
9709 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9710 return (0);
9711 case XPATH_OP_SORT:
9712 if (op->ch1 != -1)
9713 total +=
9714 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9715 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009716 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009717 if ((ctxt->value != NULL)
9718 && (ctxt->value->type == XPATH_NODESET)
9719 && (ctxt->value->nodesetval != NULL))
9720 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9721 return (total);
9722 default:
9723 return (xmlXPathCompOpEval(ctxt, op));
9724 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009725}
9726
Owen Taylor3473f882001-02-23 17:55:21 +00009727/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009728 * xmlXPathCompOpEval:
9729 * @ctxt: the XPath parser context with the compiled expression
9730 * @op: an XPath compiled operation
9731 *
9732 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009733 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009734 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009735static int
9736xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9737{
9738 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009739 int equal, ret;
9740 xmlXPathCompExprPtr comp;
9741 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009742 xmlNodePtr bak;
9743 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009744 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009745 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009746
Daniel Veillard556c6682001-10-06 09:59:51 +00009747 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009748 comp = ctxt->comp;
9749 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009750 case XPATH_OP_END:
9751 return (0);
9752 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009753 bakd = ctxt->context->doc;
9754 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009755 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009756 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009757 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009758 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009759 xmlXPathBooleanFunction(ctxt, 1);
9760 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9761 return (total);
9762 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009763 ctxt->context->doc = bakd;
9764 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009765 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009766 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009767 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009768 if (ctxt->error) {
9769 xmlXPathFreeObject(arg2);
9770 return(0);
9771 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009772 xmlXPathBooleanFunction(ctxt, 1);
9773 arg1 = valuePop(ctxt);
9774 arg1->boolval &= arg2->boolval;
9775 valuePush(ctxt, arg1);
9776 xmlXPathFreeObject(arg2);
9777 return (total);
9778 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009779 bakd = ctxt->context->doc;
9780 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009781 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009782 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009783 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009784 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009785 xmlXPathBooleanFunction(ctxt, 1);
9786 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9787 return (total);
9788 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009789 ctxt->context->doc = bakd;
9790 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009791 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009792 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009793 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009794 if (ctxt->error) {
9795 xmlXPathFreeObject(arg2);
9796 return(0);
9797 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009798 xmlXPathBooleanFunction(ctxt, 1);
9799 arg1 = valuePop(ctxt);
9800 arg1->boolval |= arg2->boolval;
9801 valuePush(ctxt, arg1);
9802 xmlXPathFreeObject(arg2);
9803 return (total);
9804 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009805 bakd = ctxt->context->doc;
9806 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009807 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009808 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009809 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009810 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009811 ctxt->context->doc = bakd;
9812 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009813 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009814 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009815 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009816 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009817 if (op->value)
9818 equal = xmlXPathEqualValues(ctxt);
9819 else
9820 equal = xmlXPathNotEqualValues(ctxt);
9821 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009822 return (total);
9823 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009824 bakd = ctxt->context->doc;
9825 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009826 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009827 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009828 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009829 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009830 ctxt->context->doc = bakd;
9831 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009832 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009833 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009834 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009835 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009836 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9837 valuePush(ctxt, xmlXPathNewBoolean(ret));
9838 return (total);
9839 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009840 bakd = ctxt->context->doc;
9841 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009842 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009843 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009844 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009845 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009846 if (op->ch2 != -1) {
9847 ctxt->context->doc = bakd;
9848 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009849 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009850 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009851 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009852 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009853 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009854 if (op->value == 0)
9855 xmlXPathSubValues(ctxt);
9856 else if (op->value == 1)
9857 xmlXPathAddValues(ctxt);
9858 else if (op->value == 2)
9859 xmlXPathValueFlipSign(ctxt);
9860 else if (op->value == 3) {
9861 CAST_TO_NUMBER;
9862 CHECK_TYPE0(XPATH_NUMBER);
9863 }
9864 return (total);
9865 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009866 bakd = ctxt->context->doc;
9867 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009868 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009869 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009870 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009871 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009872 ctxt->context->doc = bakd;
9873 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009874 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009875 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009876 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009877 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009878 if (op->value == 0)
9879 xmlXPathMultValues(ctxt);
9880 else if (op->value == 1)
9881 xmlXPathDivValues(ctxt);
9882 else if (op->value == 2)
9883 xmlXPathModValues(ctxt);
9884 return (total);
9885 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009886 bakd = ctxt->context->doc;
9887 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009888 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009889 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009890 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009891 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009892 ctxt->context->doc = bakd;
9893 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009894 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009895 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009896 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009897 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009898 CHECK_TYPE0(XPATH_NODESET);
9899 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009900
Daniel Veillardf06307e2001-07-03 10:35:50 +00009901 CHECK_TYPE0(XPATH_NODESET);
9902 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009903
Daniel Veillardf06307e2001-07-03 10:35:50 +00009904 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9905 arg2->nodesetval);
9906 valuePush(ctxt, arg1);
9907 xmlXPathFreeObject(arg2);
9908 return (total);
9909 case XPATH_OP_ROOT:
9910 xmlXPathRoot(ctxt);
9911 return (total);
9912 case XPATH_OP_NODE:
9913 if (op->ch1 != -1)
9914 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009915 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009916 if (op->ch2 != -1)
9917 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009918 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009919 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9920 return (total);
9921 case XPATH_OP_RESET:
9922 if (op->ch1 != -1)
9923 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009924 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009925 if (op->ch2 != -1)
9926 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009927 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009928 ctxt->context->node = NULL;
9929 return (total);
9930 case XPATH_OP_COLLECT:{
9931 if (op->ch1 == -1)
9932 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009933
Daniel Veillardf06307e2001-07-03 10:35:50 +00009934 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009935 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009936
Daniel Veillardf06307e2001-07-03 10:35:50 +00009937 /*
9938 * Optimization for [n] selection where n is a number
9939 */
9940 if ((op->ch2 != -1) &&
9941 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9942 (comp->steps[op->ch2].ch1 == -1) &&
9943 (comp->steps[op->ch2].ch2 != -1) &&
9944 (comp->steps[comp->steps[op->ch2].ch2].op ==
9945 XPATH_OP_VALUE)) {
9946 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009947
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9949 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9950 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009951
Daniel Veillardf06307e2001-07-03 10:35:50 +00009952 if (val->floatval == (float) indx) {
9953 total +=
9954 xmlXPathNodeCollectAndTestNth(ctxt, op,
9955 indx, NULL,
9956 NULL);
9957 return (total);
9958 }
9959 }
9960 }
9961 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9962 return (total);
9963 }
9964 case XPATH_OP_VALUE:
9965 valuePush(ctxt,
9966 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9967 return (total);
9968 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009969 xmlXPathObjectPtr val;
9970
Daniel Veillardf06307e2001-07-03 10:35:50 +00009971 if (op->ch1 != -1)
9972 total +=
9973 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009974 if (op->value5 == NULL) {
9975 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9976 if (val == NULL) {
9977 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9978 return(0);
9979 }
9980 valuePush(ctxt, val);
9981 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009982 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009983
Daniel Veillardf06307e2001-07-03 10:35:50 +00009984 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9985 if (URI == NULL) {
9986 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009987 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009988 op->value4, op->value5);
9989 return (total);
9990 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009991 val = xmlXPathVariableLookupNS(ctxt->context,
9992 op->value4, URI);
9993 if (val == NULL) {
9994 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9995 return(0);
9996 }
9997 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009998 }
9999 return (total);
10000 }
10001 case XPATH_OP_FUNCTION:{
10002 xmlXPathFunction func;
10003 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010004 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010005
10006 if (op->ch1 != -1)
10007 total +=
10008 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010009 if (ctxt->valueNr < op->value) {
10010 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010011 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010012 ctxt->error = XPATH_INVALID_OPERAND;
10013 return (total);
10014 }
10015 for (i = 0; i < op->value; i++)
10016 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10017 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010018 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010019 ctxt->error = XPATH_INVALID_OPERAND;
10020 return (total);
10021 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010022 if (op->cache != NULL)
10023 func = (xmlXPathFunction) op->cache;
10024 else {
10025 const xmlChar *URI = NULL;
10026
10027 if (op->value5 == NULL)
10028 func =
10029 xmlXPathFunctionLookup(ctxt->context,
10030 op->value4);
10031 else {
10032 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10033 if (URI == NULL) {
10034 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010035 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010036 op->value4, op->value5);
10037 return (total);
10038 }
10039 func = xmlXPathFunctionLookupNS(ctxt->context,
10040 op->value4, URI);
10041 }
10042 if (func == NULL) {
10043 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010044 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010045 op->value4);
10046 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010047 }
10048 op->cache = (void *) func;
10049 op->cacheURI = (void *) URI;
10050 }
10051 oldFunc = ctxt->context->function;
10052 oldFuncURI = ctxt->context->functionURI;
10053 ctxt->context->function = op->value4;
10054 ctxt->context->functionURI = op->cacheURI;
10055 func(ctxt, op->value);
10056 ctxt->context->function = oldFunc;
10057 ctxt->context->functionURI = oldFuncURI;
10058 return (total);
10059 }
10060 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010061 bakd = ctxt->context->doc;
10062 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010063 if (op->ch1 != -1)
10064 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010065 ctxt->context->doc = bakd;
10066 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010067 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010068 if (op->ch2 != -1)
10069 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010070 ctxt->context->doc = bakd;
10071 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010072 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010073 return (total);
10074 case XPATH_OP_PREDICATE:
10075 case XPATH_OP_FILTER:{
10076 xmlXPathObjectPtr res;
10077 xmlXPathObjectPtr obj, tmp;
10078 xmlNodeSetPtr newset = NULL;
10079 xmlNodeSetPtr oldset;
10080 xmlNodePtr oldnode;
10081 int i;
10082
10083 /*
10084 * Optimization for ()[1] selection i.e. the first elem
10085 */
10086 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10087 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10088 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10089 xmlXPathObjectPtr val;
10090
10091 val = comp->steps[op->ch2].value4;
10092 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10093 (val->floatval == 1.0)) {
10094 xmlNodePtr first = NULL;
10095
10096 total +=
10097 xmlXPathCompOpEvalFirst(ctxt,
10098 &comp->steps[op->ch1],
10099 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010100 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010101 /*
10102 * The nodeset should be in document order,
10103 * Keep only the first value
10104 */
10105 if ((ctxt->value != NULL) &&
10106 (ctxt->value->type == XPATH_NODESET) &&
10107 (ctxt->value->nodesetval != NULL) &&
10108 (ctxt->value->nodesetval->nodeNr > 1))
10109 ctxt->value->nodesetval->nodeNr = 1;
10110 return (total);
10111 }
10112 }
10113 /*
10114 * Optimization for ()[last()] selection i.e. the last elem
10115 */
10116 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10117 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10118 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10119 int f = comp->steps[op->ch2].ch1;
10120
10121 if ((f != -1) &&
10122 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10123 (comp->steps[f].value5 == NULL) &&
10124 (comp->steps[f].value == 0) &&
10125 (comp->steps[f].value4 != NULL) &&
10126 (xmlStrEqual
10127 (comp->steps[f].value4, BAD_CAST "last"))) {
10128 xmlNodePtr last = NULL;
10129
10130 total +=
10131 xmlXPathCompOpEvalLast(ctxt,
10132 &comp->steps[op->ch1],
10133 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010134 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010135 /*
10136 * The nodeset should be in document order,
10137 * Keep only the last value
10138 */
10139 if ((ctxt->value != NULL) &&
10140 (ctxt->value->type == XPATH_NODESET) &&
10141 (ctxt->value->nodesetval != NULL) &&
10142 (ctxt->value->nodesetval->nodeTab != NULL) &&
10143 (ctxt->value->nodesetval->nodeNr > 1)) {
10144 ctxt->value->nodesetval->nodeTab[0] =
10145 ctxt->value->nodesetval->nodeTab[ctxt->
10146 value->
10147 nodesetval->
10148 nodeNr -
10149 1];
10150 ctxt->value->nodesetval->nodeNr = 1;
10151 }
10152 return (total);
10153 }
10154 }
10155
10156 if (op->ch1 != -1)
10157 total +=
10158 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010159 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010160 if (op->ch2 == -1)
10161 return (total);
10162 if (ctxt->value == NULL)
10163 return (total);
10164
10165 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010166
10167#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010168 /*
10169 * Hum are we filtering the result of an XPointer expression
10170 */
10171 if (ctxt->value->type == XPATH_LOCATIONSET) {
10172 xmlLocationSetPtr newlocset = NULL;
10173 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010174
Daniel Veillardf06307e2001-07-03 10:35:50 +000010175 /*
10176 * Extract the old locset, and then evaluate the result of the
10177 * expression for all the element in the locset. use it to grow
10178 * up a new locset.
10179 */
10180 CHECK_TYPE0(XPATH_LOCATIONSET);
10181 obj = valuePop(ctxt);
10182 oldlocset = obj->user;
10183 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010184
Daniel Veillardf06307e2001-07-03 10:35:50 +000010185 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10186 ctxt->context->contextSize = 0;
10187 ctxt->context->proximityPosition = 0;
10188 if (op->ch2 != -1)
10189 total +=
10190 xmlXPathCompOpEval(ctxt,
10191 &comp->steps[op->ch2]);
10192 res = valuePop(ctxt);
10193 if (res != NULL)
10194 xmlXPathFreeObject(res);
10195 valuePush(ctxt, obj);
10196 CHECK_ERROR0;
10197 return (total);
10198 }
10199 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010200
Daniel Veillardf06307e2001-07-03 10:35:50 +000010201 for (i = 0; i < oldlocset->locNr; i++) {
10202 /*
10203 * Run the evaluation with a node list made of a
10204 * single item in the nodelocset.
10205 */
10206 ctxt->context->node = oldlocset->locTab[i]->user;
10207 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10208 valuePush(ctxt, tmp);
10209 ctxt->context->contextSize = oldlocset->locNr;
10210 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010211
Daniel Veillardf06307e2001-07-03 10:35:50 +000010212 if (op->ch2 != -1)
10213 total +=
10214 xmlXPathCompOpEval(ctxt,
10215 &comp->steps[op->ch2]);
10216 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010217
Daniel Veillardf06307e2001-07-03 10:35:50 +000010218 /*
10219 * The result of the evaluation need to be tested to
10220 * decided whether the filter succeeded or not
10221 */
10222 res = valuePop(ctxt);
10223 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10224 xmlXPtrLocationSetAdd(newlocset,
10225 xmlXPathObjectCopy
10226 (oldlocset->locTab[i]));
10227 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010228
Daniel Veillardf06307e2001-07-03 10:35:50 +000010229 /*
10230 * Cleanup
10231 */
10232 if (res != NULL)
10233 xmlXPathFreeObject(res);
10234 if (ctxt->value == tmp) {
10235 res = valuePop(ctxt);
10236 xmlXPathFreeObject(res);
10237 }
10238
10239 ctxt->context->node = NULL;
10240 }
10241
10242 /*
10243 * The result is used as the new evaluation locset.
10244 */
10245 xmlXPathFreeObject(obj);
10246 ctxt->context->node = NULL;
10247 ctxt->context->contextSize = -1;
10248 ctxt->context->proximityPosition = -1;
10249 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10250 ctxt->context->node = oldnode;
10251 return (total);
10252 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010253#endif /* LIBXML_XPTR_ENABLED */
10254
Daniel Veillardf06307e2001-07-03 10:35:50 +000010255 /*
10256 * Extract the old set, and then evaluate the result of the
10257 * expression for all the element in the set. use it to grow
10258 * up a new set.
10259 */
10260 CHECK_TYPE0(XPATH_NODESET);
10261 obj = valuePop(ctxt);
10262 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010263
Daniel Veillardf06307e2001-07-03 10:35:50 +000010264 oldnode = ctxt->context->node;
10265 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010266
Daniel Veillardf06307e2001-07-03 10:35:50 +000010267 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10268 ctxt->context->contextSize = 0;
10269 ctxt->context->proximityPosition = 0;
10270 if (op->ch2 != -1)
10271 total +=
10272 xmlXPathCompOpEval(ctxt,
10273 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010274 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010275 res = valuePop(ctxt);
10276 if (res != NULL)
10277 xmlXPathFreeObject(res);
10278 valuePush(ctxt, obj);
10279 ctxt->context->node = oldnode;
10280 CHECK_ERROR0;
10281 } else {
10282 /*
10283 * Initialize the new set.
10284 */
10285 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010286
Daniel Veillardf06307e2001-07-03 10:35:50 +000010287 for (i = 0; i < oldset->nodeNr; i++) {
10288 /*
10289 * Run the evaluation with a node list made of
10290 * a single item in the nodeset.
10291 */
10292 ctxt->context->node = oldset->nodeTab[i];
10293 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10294 valuePush(ctxt, tmp);
10295 ctxt->context->contextSize = oldset->nodeNr;
10296 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010297
Daniel Veillardf06307e2001-07-03 10:35:50 +000010298 if (op->ch2 != -1)
10299 total +=
10300 xmlXPathCompOpEval(ctxt,
10301 &comp->steps[op->ch2]);
10302 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010303
Daniel Veillardf06307e2001-07-03 10:35:50 +000010304 /*
10305 * The result of the evaluation need to be tested to
10306 * decided whether the filter succeeded or not
10307 */
10308 res = valuePop(ctxt);
10309 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10310 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10311 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010312
Daniel Veillardf06307e2001-07-03 10:35:50 +000010313 /*
10314 * Cleanup
10315 */
10316 if (res != NULL)
10317 xmlXPathFreeObject(res);
10318 if (ctxt->value == tmp) {
10319 res = valuePop(ctxt);
10320 xmlXPathFreeObject(res);
10321 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010322
Daniel Veillardf06307e2001-07-03 10:35:50 +000010323 ctxt->context->node = NULL;
10324 }
10325
10326 /*
10327 * The result is used as the new evaluation set.
10328 */
10329 xmlXPathFreeObject(obj);
10330 ctxt->context->node = NULL;
10331 ctxt->context->contextSize = -1;
10332 ctxt->context->proximityPosition = -1;
10333 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10334 }
10335 ctxt->context->node = oldnode;
10336 return (total);
10337 }
10338 case XPATH_OP_SORT:
10339 if (op->ch1 != -1)
10340 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010341 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010342 if ((ctxt->value != NULL) &&
10343 (ctxt->value->type == XPATH_NODESET) &&
10344 (ctxt->value->nodesetval != NULL))
10345 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10346 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010347#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010348 case XPATH_OP_RANGETO:{
10349 xmlXPathObjectPtr range;
10350 xmlXPathObjectPtr res, obj;
10351 xmlXPathObjectPtr tmp;
10352 xmlLocationSetPtr newset = NULL;
10353 xmlNodeSetPtr oldset;
10354 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010355
Daniel Veillardf06307e2001-07-03 10:35:50 +000010356 if (op->ch1 != -1)
10357 total +=
10358 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10359 if (op->ch2 == -1)
10360 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010361
Daniel Veillardf06307e2001-07-03 10:35:50 +000010362 CHECK_TYPE0(XPATH_NODESET);
10363 obj = valuePop(ctxt);
10364 oldset = obj->nodesetval;
10365 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010366
Daniel Veillardf06307e2001-07-03 10:35:50 +000010367 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010368
Daniel Veillardf06307e2001-07-03 10:35:50 +000010369 if (oldset != NULL) {
10370 for (i = 0; i < oldset->nodeNr; i++) {
10371 /*
10372 * Run the evaluation with a node list made of a single item
10373 * in the nodeset.
10374 */
10375 ctxt->context->node = oldset->nodeTab[i];
10376 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10377 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010378
Daniel Veillardf06307e2001-07-03 10:35:50 +000010379 if (op->ch2 != -1)
10380 total +=
10381 xmlXPathCompOpEval(ctxt,
10382 &comp->steps[op->ch2]);
10383 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010384
Daniel Veillardf06307e2001-07-03 10:35:50 +000010385 /*
10386 * The result of the evaluation need to be tested to
10387 * decided whether the filter succeeded or not
10388 */
10389 res = valuePop(ctxt);
10390 range =
10391 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10392 res);
10393 if (range != NULL) {
10394 xmlXPtrLocationSetAdd(newset, range);
10395 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010396
Daniel Veillardf06307e2001-07-03 10:35:50 +000010397 /*
10398 * Cleanup
10399 */
10400 if (res != NULL)
10401 xmlXPathFreeObject(res);
10402 if (ctxt->value == tmp) {
10403 res = valuePop(ctxt);
10404 xmlXPathFreeObject(res);
10405 }
10406
10407 ctxt->context->node = NULL;
10408 }
10409 }
10410
10411 /*
10412 * The result is used as the new evaluation set.
10413 */
10414 xmlXPathFreeObject(obj);
10415 ctxt->context->node = NULL;
10416 ctxt->context->contextSize = -1;
10417 ctxt->context->proximityPosition = -1;
10418 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10419 return (total);
10420 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010421#endif /* LIBXML_XPTR_ENABLED */
10422 }
10423 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010424 "XPath: unknown precompiled operation %d\n", op->op);
10425 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010426}
10427
10428/**
10429 * xmlXPathRunEval:
10430 * @ctxt: the XPath parser context with the compiled expression
10431 *
10432 * Evaluate the Precompiled XPath expression in the given context.
10433 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010434static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010435xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10436 xmlXPathCompExprPtr comp;
10437
10438 if ((ctxt == NULL) || (ctxt->comp == NULL))
10439 return;
10440
10441 if (ctxt->valueTab == NULL) {
10442 /* Allocate the value stack */
10443 ctxt->valueTab = (xmlXPathObjectPtr *)
10444 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10445 if (ctxt->valueTab == NULL) {
10446 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010447 }
10448 ctxt->valueNr = 0;
10449 ctxt->valueMax = 10;
10450 ctxt->value = NULL;
10451 }
10452 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010453 if(comp->last < 0) {
10454 xmlGenericError(xmlGenericErrorContext,
10455 "xmlXPathRunEval: last is less than zero\n");
10456 return;
10457 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010458 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10459}
10460
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010461/************************************************************************
10462 * *
10463 * Public interfaces *
10464 * *
10465 ************************************************************************/
10466
10467/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010468 * xmlXPathEvalPredicate:
10469 * @ctxt: the XPath context
10470 * @res: the Predicate Expression evaluation result
10471 *
10472 * Evaluate a predicate result for the current node.
10473 * A PredicateExpr is evaluated by evaluating the Expr and converting
10474 * the result to a boolean. If the result is a number, the result will
10475 * be converted to true if the number is equal to the position of the
10476 * context node in the context node list (as returned by the position
10477 * function) and will be converted to false otherwise; if the result
10478 * is not a number, then the result will be converted as if by a call
10479 * to the boolean function.
10480 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010481 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010482 */
10483int
10484xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10485 if (res == NULL) return(0);
10486 switch (res->type) {
10487 case XPATH_BOOLEAN:
10488 return(res->boolval);
10489 case XPATH_NUMBER:
10490 return(res->floatval == ctxt->proximityPosition);
10491 case XPATH_NODESET:
10492 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010493 if (res->nodesetval == NULL)
10494 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010495 return(res->nodesetval->nodeNr != 0);
10496 case XPATH_STRING:
10497 return((res->stringval != NULL) &&
10498 (xmlStrlen(res->stringval) != 0));
10499 default:
10500 STRANGE
10501 }
10502 return(0);
10503}
10504
10505/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010506 * xmlXPathEvaluatePredicateResult:
10507 * @ctxt: the XPath Parser context
10508 * @res: the Predicate Expression evaluation result
10509 *
10510 * Evaluate a predicate result for the current node.
10511 * A PredicateExpr is evaluated by evaluating the Expr and converting
10512 * the result to a boolean. If the result is a number, the result will
10513 * be converted to true if the number is equal to the position of the
10514 * context node in the context node list (as returned by the position
10515 * function) and will be converted to false otherwise; if the result
10516 * is not a number, then the result will be converted as if by a call
10517 * to the boolean function.
10518 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010519 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010520 */
10521int
10522xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10523 xmlXPathObjectPtr res) {
10524 if (res == NULL) return(0);
10525 switch (res->type) {
10526 case XPATH_BOOLEAN:
10527 return(res->boolval);
10528 case XPATH_NUMBER:
10529 return(res->floatval == ctxt->context->proximityPosition);
10530 case XPATH_NODESET:
10531 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010532 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010533 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010534 return(res->nodesetval->nodeNr != 0);
10535 case XPATH_STRING:
10536 return((res->stringval != NULL) &&
10537 (xmlStrlen(res->stringval) != 0));
10538 default:
10539 STRANGE
10540 }
10541 return(0);
10542}
10543
10544/**
10545 * xmlXPathCompile:
10546 * @str: the XPath expression
10547 *
10548 * Compile an XPath expression
10549 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010550 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010551 * the caller has to free the object.
10552 */
10553xmlXPathCompExprPtr
10554xmlXPathCompile(const xmlChar *str) {
10555 xmlXPathParserContextPtr ctxt;
10556 xmlXPathCompExprPtr comp;
10557
10558 xmlXPathInit();
10559
10560 ctxt = xmlXPathNewParserContext(str, NULL);
10561 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010562
Daniel Veillard40af6492001-04-22 08:50:55 +000010563 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010564 /*
10565 * aleksey: in some cases this line prints *second* error message
10566 * (see bug #78858) and probably this should be fixed.
10567 * However, we are not sure that all error messages are printed
10568 * out in other places. It's not critical so we leave it as-is for now
10569 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010570 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10571 comp = NULL;
10572 } else {
10573 comp = ctxt->comp;
10574 ctxt->comp = NULL;
10575 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010576 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010577#ifdef DEBUG_EVAL_COUNTS
10578 if (comp != NULL) {
10579 comp->string = xmlStrdup(str);
10580 comp->nb = 0;
10581 }
10582#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010583 return(comp);
10584}
10585
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010586/**
10587 * xmlXPathCompiledEval:
10588 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010589 * @ctx: the XPath context
10590 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010592 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010593 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010594 * the caller has to free the object.
10595 */
10596xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010597xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010598 xmlXPathParserContextPtr ctxt;
10599 xmlXPathObjectPtr res, tmp, init = NULL;
10600 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010601#ifndef LIBXML_THREAD_ENABLED
10602 static int reentance = 0;
10603#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010604
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010605 if ((comp == NULL) || (ctx == NULL))
10606 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010607 xmlXPathInit();
10608
10609 CHECK_CONTEXT(ctx)
10610
Daniel Veillard81463942001-10-16 12:34:39 +000010611#ifndef LIBXML_THREAD_ENABLED
10612 reentance++;
10613 if (reentance > 1)
10614 xmlXPathDisableOptimizer = 1;
10615#endif
10616
Daniel Veillardf06307e2001-07-03 10:35:50 +000010617#ifdef DEBUG_EVAL_COUNTS
10618 comp->nb++;
10619 if ((comp->string != NULL) && (comp->nb > 100)) {
10620 fprintf(stderr, "100 x %s\n", comp->string);
10621 comp->nb = 0;
10622 }
10623#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010624 ctxt = xmlXPathCompParserContext(comp, ctx);
10625 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010626
10627 if (ctxt->value == NULL) {
10628 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010629 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010630 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010631 } else {
10632 res = valuePop(ctxt);
10633 }
10634
Daniel Veillardf06307e2001-07-03 10:35:50 +000010635
Owen Taylor3473f882001-02-23 17:55:21 +000010636 do {
10637 tmp = valuePop(ctxt);
10638 if (tmp != NULL) {
10639 if (tmp != init)
10640 stack++;
10641 xmlXPathFreeObject(tmp);
10642 }
10643 } while (tmp != NULL);
10644 if ((stack != 0) && (res != NULL)) {
10645 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010646 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010647 stack);
10648 }
10649 if (ctxt->error != XPATH_EXPRESSION_OK) {
10650 xmlXPathFreeObject(res);
10651 res = NULL;
10652 }
10653
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010654
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010655 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010656 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010657#ifndef LIBXML_THREAD_ENABLED
10658 reentance--;
10659#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010660 return(res);
10661}
10662
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010663/**
10664 * xmlXPathEvalExpr:
10665 * @ctxt: the XPath Parser context
10666 *
10667 * Parse and evaluate an XPath expression in the given context,
10668 * then push the result on the context stack
10669 */
10670void
10671xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10672 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010673 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010674 xmlXPathRunEval(ctxt);
10675}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010676
10677/**
10678 * xmlXPathEval:
10679 * @str: the XPath expression
10680 * @ctx: the XPath context
10681 *
10682 * Evaluate the XPath Location Path in the given context.
10683 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010684 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010685 * the caller has to free the object.
10686 */
10687xmlXPathObjectPtr
10688xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10689 xmlXPathParserContextPtr ctxt;
10690 xmlXPathObjectPtr res, tmp, init = NULL;
10691 int stack = 0;
10692
10693 xmlXPathInit();
10694
10695 CHECK_CONTEXT(ctx)
10696
10697 ctxt = xmlXPathNewParserContext(str, ctx);
10698 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010699
10700 if (ctxt->value == NULL) {
10701 xmlGenericError(xmlGenericErrorContext,
10702 "xmlXPathEval: evaluation failed\n");
10703 res = NULL;
10704 } else if (*ctxt->cur != 0) {
10705 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10706 res = NULL;
10707 } else {
10708 res = valuePop(ctxt);
10709 }
10710
10711 do {
10712 tmp = valuePop(ctxt);
10713 if (tmp != NULL) {
10714 if (tmp != init)
10715 stack++;
10716 xmlXPathFreeObject(tmp);
10717 }
10718 } while (tmp != NULL);
10719 if ((stack != 0) && (res != NULL)) {
10720 xmlGenericError(xmlGenericErrorContext,
10721 "xmlXPathEval: %d object left on the stack\n",
10722 stack);
10723 }
10724 if (ctxt->error != XPATH_EXPRESSION_OK) {
10725 xmlXPathFreeObject(res);
10726 res = NULL;
10727 }
10728
Owen Taylor3473f882001-02-23 17:55:21 +000010729 xmlXPathFreeParserContext(ctxt);
10730 return(res);
10731}
10732
10733/**
10734 * xmlXPathEvalExpression:
10735 * @str: the XPath expression
10736 * @ctxt: the XPath context
10737 *
10738 * Evaluate the XPath expression in the given context.
10739 *
10740 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10741 * the caller has to free the object.
10742 */
10743xmlXPathObjectPtr
10744xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10745 xmlXPathParserContextPtr pctxt;
10746 xmlXPathObjectPtr res, tmp;
10747 int stack = 0;
10748
10749 xmlXPathInit();
10750
10751 CHECK_CONTEXT(ctxt)
10752
10753 pctxt = xmlXPathNewParserContext(str, ctxt);
10754 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010755
10756 if (*pctxt->cur != 0) {
10757 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10758 res = NULL;
10759 } else {
10760 res = valuePop(pctxt);
10761 }
10762 do {
10763 tmp = valuePop(pctxt);
10764 if (tmp != NULL) {
10765 xmlXPathFreeObject(tmp);
10766 stack++;
10767 }
10768 } while (tmp != NULL);
10769 if ((stack != 0) && (res != NULL)) {
10770 xmlGenericError(xmlGenericErrorContext,
10771 "xmlXPathEvalExpression: %d object left on the stack\n",
10772 stack);
10773 }
10774 xmlXPathFreeParserContext(pctxt);
10775 return(res);
10776}
10777
10778/**
10779 * xmlXPathRegisterAllFunctions:
10780 * @ctxt: the XPath context
10781 *
10782 * Registers all default XPath functions in this context
10783 */
10784void
10785xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10786{
10787 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10788 xmlXPathBooleanFunction);
10789 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10790 xmlXPathCeilingFunction);
10791 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10792 xmlXPathCountFunction);
10793 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10794 xmlXPathConcatFunction);
10795 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10796 xmlXPathContainsFunction);
10797 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10798 xmlXPathIdFunction);
10799 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10800 xmlXPathFalseFunction);
10801 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10802 xmlXPathFloorFunction);
10803 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10804 xmlXPathLastFunction);
10805 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10806 xmlXPathLangFunction);
10807 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10808 xmlXPathLocalNameFunction);
10809 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10810 xmlXPathNotFunction);
10811 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10812 xmlXPathNameFunction);
10813 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10814 xmlXPathNamespaceURIFunction);
10815 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10816 xmlXPathNormalizeFunction);
10817 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10818 xmlXPathNumberFunction);
10819 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10820 xmlXPathPositionFunction);
10821 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10822 xmlXPathRoundFunction);
10823 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10824 xmlXPathStringFunction);
10825 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10826 xmlXPathStringLengthFunction);
10827 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10828 xmlXPathStartsWithFunction);
10829 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10830 xmlXPathSubstringFunction);
10831 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10832 xmlXPathSubstringBeforeFunction);
10833 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10834 xmlXPathSubstringAfterFunction);
10835 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10836 xmlXPathSumFunction);
10837 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10838 xmlXPathTrueFunction);
10839 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10840 xmlXPathTranslateFunction);
10841}
10842
10843#endif /* LIBXML_XPATH_ENABLED */