blob: b176ed529217ff18f65a16c055154ed0f7cbbcde [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:
William M. Brackef61d202002-07-19 08:32:00 +00004423 ret = (arg1->boolval ==
4424 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004425 break;
4426 case XPATH_STRING:
4427 if ((arg2->stringval == NULL) ||
4428 (arg2->stringval[0] == 0)) ret = 0;
4429 else
4430 ret = 1;
4431 ret = (arg1->boolval == ret);
4432 break;
4433 case XPATH_USERS:
4434 case XPATH_POINT:
4435 case XPATH_RANGE:
4436 case XPATH_LOCATIONSET:
4437 TODO
4438 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004439 case XPATH_NODESET:
4440 case XPATH_XSLT_TREE:
4441 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004442 }
4443 break;
4444 case XPATH_NUMBER:
4445 switch (arg2->type) {
4446 case XPATH_UNDEFINED:
4447#ifdef DEBUG_EXPR
4448 xmlGenericError(xmlGenericErrorContext,
4449 "Equal: undefined\n");
4450#endif
4451 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004452 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004453 ret = (arg2->boolval==
4454 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004455 break;
4456 case XPATH_STRING:
4457 valuePush(ctxt, arg2);
4458 xmlXPathNumberFunction(ctxt, 1);
4459 arg2 = valuePop(ctxt);
4460 /* no break on purpose */
4461 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004462 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004463 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4464 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004465 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4466 if (xmlXPathIsInf(arg2->floatval) == 1)
4467 ret = 1;
4468 else
4469 ret = 0;
4470 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4471 if (xmlXPathIsInf(arg2->floatval) == -1)
4472 ret = 1;
4473 else
4474 ret = 0;
4475 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4476 if (xmlXPathIsInf(arg1->floatval) == 1)
4477 ret = 1;
4478 else
4479 ret = 0;
4480 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4481 if (xmlXPathIsInf(arg1->floatval) == -1)
4482 ret = 1;
4483 else
4484 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004485 } else {
4486 ret = (arg1->floatval == arg2->floatval);
4487 }
Owen Taylor3473f882001-02-23 17:55:21 +00004488 break;
4489 case XPATH_USERS:
4490 case XPATH_POINT:
4491 case XPATH_RANGE:
4492 case XPATH_LOCATIONSET:
4493 TODO
4494 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004495 case XPATH_NODESET:
4496 case XPATH_XSLT_TREE:
4497 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004498 }
4499 break;
4500 case XPATH_STRING:
4501 switch (arg2->type) {
4502 case XPATH_UNDEFINED:
4503#ifdef DEBUG_EXPR
4504 xmlGenericError(xmlGenericErrorContext,
4505 "Equal: undefined\n");
4506#endif
4507 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004508 case XPATH_BOOLEAN:
4509 if ((arg1->stringval == NULL) ||
4510 (arg1->stringval[0] == 0)) ret = 0;
4511 else
4512 ret = 1;
4513 ret = (arg2->boolval == ret);
4514 break;
4515 case XPATH_STRING:
4516 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4517 break;
4518 case XPATH_NUMBER:
4519 valuePush(ctxt, arg1);
4520 xmlXPathNumberFunction(ctxt, 1);
4521 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004522 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004523 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4524 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004525 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4526 if (xmlXPathIsInf(arg2->floatval) == 1)
4527 ret = 1;
4528 else
4529 ret = 0;
4530 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4531 if (xmlXPathIsInf(arg2->floatval) == -1)
4532 ret = 1;
4533 else
4534 ret = 0;
4535 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4536 if (xmlXPathIsInf(arg1->floatval) == 1)
4537 ret = 1;
4538 else
4539 ret = 0;
4540 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4541 if (xmlXPathIsInf(arg1->floatval) == -1)
4542 ret = 1;
4543 else
4544 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004545 } else {
4546 ret = (arg1->floatval == arg2->floatval);
4547 }
Owen Taylor3473f882001-02-23 17:55:21 +00004548 break;
4549 case XPATH_USERS:
4550 case XPATH_POINT:
4551 case XPATH_RANGE:
4552 case XPATH_LOCATIONSET:
4553 TODO
4554 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004555 case XPATH_NODESET:
4556 case XPATH_XSLT_TREE:
4557 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004558 }
4559 break;
4560 case XPATH_USERS:
4561 case XPATH_POINT:
4562 case XPATH_RANGE:
4563 case XPATH_LOCATIONSET:
4564 TODO
4565 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004566 case XPATH_NODESET:
4567 case XPATH_XSLT_TREE:
4568 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004569 }
4570 xmlXPathFreeObject(arg1);
4571 xmlXPathFreeObject(arg2);
4572 return(ret);
4573}
4574
William M. Brack0c022ad2002-07-12 00:56:01 +00004575/**
4576 * xmlXPathEqualValues:
4577 * @ctxt: the XPath Parser context
4578 *
4579 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4580 *
4581 * Returns 0 or 1 depending on the results of the test.
4582 */
4583int
4584xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4585 xmlXPathObjectPtr arg1, arg2, argtmp;
4586 int ret = 0;
4587
4588 arg2 = valuePop(ctxt);
4589 arg1 = valuePop(ctxt);
4590 if ((arg1 == NULL) || (arg2 == NULL)) {
4591 if (arg1 != NULL)
4592 xmlXPathFreeObject(arg1);
4593 else
4594 xmlXPathFreeObject(arg2);
4595 XP_ERROR0(XPATH_INVALID_OPERAND);
4596 }
4597
4598 if (arg1 == arg2) {
4599#ifdef DEBUG_EXPR
4600 xmlGenericError(xmlGenericErrorContext,
4601 "Equal: by pointer\n");
4602#endif
4603 return(1);
4604 }
4605
4606 /*
4607 *If either argument is a nodeset, it's a 'special case'
4608 */
4609 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4610 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4611 /*
4612 *Hack it to assure arg1 is the nodeset
4613 */
4614 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4615 argtmp = arg2;
4616 arg2 = arg1;
4617 arg1 = argtmp;
4618 }
4619 switch (arg2->type) {
4620 case XPATH_UNDEFINED:
4621#ifdef DEBUG_EXPR
4622 xmlGenericError(xmlGenericErrorContext,
4623 "Equal: undefined\n");
4624#endif
4625 break;
4626 case XPATH_NODESET:
4627 case XPATH_XSLT_TREE:
4628 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4629 break;
4630 case XPATH_BOOLEAN:
4631 if ((arg1->nodesetval == NULL) ||
4632 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4633 else
4634 ret = 1;
4635 ret = (ret == arg2->boolval);
4636 break;
4637 case XPATH_NUMBER:
4638 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4639 break;
4640 case XPATH_STRING:
4641 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4642 break;
4643 case XPATH_USERS:
4644 case XPATH_POINT:
4645 case XPATH_RANGE:
4646 case XPATH_LOCATIONSET:
4647 TODO
4648 break;
4649 }
4650 xmlXPathFreeObject(arg1);
4651 xmlXPathFreeObject(arg2);
4652 return(ret);
4653 }
4654
4655 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4656}
4657
4658/**
4659 * xmlXPathNotEqualValues:
4660 * @ctxt: the XPath Parser context
4661 *
4662 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4663 *
4664 * Returns 0 or 1 depending on the results of the test.
4665 */
4666int
4667xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4668 xmlXPathObjectPtr arg1, arg2, argtmp;
4669 int ret = 0;
4670
4671 arg2 = valuePop(ctxt);
4672 arg1 = valuePop(ctxt);
4673 if ((arg1 == NULL) || (arg2 == NULL)) {
4674 if (arg1 != NULL)
4675 xmlXPathFreeObject(arg1);
4676 else
4677 xmlXPathFreeObject(arg2);
4678 XP_ERROR0(XPATH_INVALID_OPERAND);
4679 }
4680
4681 if (arg1 == arg2) {
4682#ifdef DEBUG_EXPR
4683 xmlGenericError(xmlGenericErrorContext,
4684 "NotEqual: by pointer\n");
4685#endif
4686 return(0);
4687 }
4688
4689 /*
4690 *If either argument is a nodeset, it's a 'special case'
4691 */
4692 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4693 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4694 /*
4695 *Hack it to assure arg1 is the nodeset
4696 */
4697 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4698 argtmp = arg2;
4699 arg2 = arg1;
4700 arg1 = argtmp;
4701 }
4702 switch (arg2->type) {
4703 case XPATH_UNDEFINED:
4704#ifdef DEBUG_EXPR
4705 xmlGenericError(xmlGenericErrorContext,
4706 "NotEqual: undefined\n");
4707#endif
4708 break;
4709 case XPATH_NODESET:
4710 case XPATH_XSLT_TREE:
4711 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4712 break;
4713 case XPATH_BOOLEAN:
4714 if ((arg1->nodesetval == NULL) ||
4715 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4716 else
4717 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004718 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004719 break;
4720 case XPATH_NUMBER:
4721 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4722 break;
4723 case XPATH_STRING:
4724 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4725 break;
4726 case XPATH_USERS:
4727 case XPATH_POINT:
4728 case XPATH_RANGE:
4729 case XPATH_LOCATIONSET:
4730 TODO
4731 break;
4732 }
4733 xmlXPathFreeObject(arg1);
4734 xmlXPathFreeObject(arg2);
4735 return(ret);
4736 }
4737
4738 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4739}
Owen Taylor3473f882001-02-23 17:55:21 +00004740
4741/**
4742 * xmlXPathCompareValues:
4743 * @ctxt: the XPath Parser context
4744 * @inf: less than (1) or greater than (0)
4745 * @strict: is the comparison strict
4746 *
4747 * Implement the compare operation on XPath objects:
4748 * @arg1 < @arg2 (1, 1, ...
4749 * @arg1 <= @arg2 (1, 0, ...
4750 * @arg1 > @arg2 (0, 1, ...
4751 * @arg1 >= @arg2 (0, 0, ...
4752 *
4753 * When neither object to be compared is a node-set and the operator is
4754 * <=, <, >=, >, then the objects are compared by converted both objects
4755 * to numbers and comparing the numbers according to IEEE 754. The <
4756 * comparison will be true if and only if the first number is less than the
4757 * second number. The <= comparison will be true if and only if the first
4758 * number is less than or equal to the second number. The > comparison
4759 * will be true if and only if the first number is greater than the second
4760 * number. The >= comparison will be true if and only if the first number
4761 * is greater than or equal to the second number.
4762 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004763 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004764 */
4765int
4766xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004767 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004768 xmlXPathObjectPtr arg1, arg2;
4769
William M. Brack0c022ad2002-07-12 00:56:01 +00004770 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004771 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004772 if ((arg1 == NULL) || (arg2 == NULL)) {
4773 if (arg1 != NULL)
4774 xmlXPathFreeObject(arg1);
4775 else
4776 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004777 XP_ERROR0(XPATH_INVALID_OPERAND);
4778 }
4779
William M. Brack0c022ad2002-07-12 00:56:01 +00004780 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4781 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4782 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4783 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004784 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004785 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004786 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004787 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4788 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004789 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004790 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4791 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004792 }
4793 }
4794 return(ret);
4795 }
4796
4797 if (arg1->type != XPATH_NUMBER) {
4798 valuePush(ctxt, arg1);
4799 xmlXPathNumberFunction(ctxt, 1);
4800 arg1 = valuePop(ctxt);
4801 }
4802 if (arg1->type != XPATH_NUMBER) {
4803 xmlXPathFreeObject(arg1);
4804 xmlXPathFreeObject(arg2);
4805 XP_ERROR0(XPATH_INVALID_OPERAND);
4806 }
4807 if (arg2->type != XPATH_NUMBER) {
4808 valuePush(ctxt, arg2);
4809 xmlXPathNumberFunction(ctxt, 1);
4810 arg2 = valuePop(ctxt);
4811 }
4812 if (arg2->type != XPATH_NUMBER) {
4813 xmlXPathFreeObject(arg1);
4814 xmlXPathFreeObject(arg2);
4815 XP_ERROR0(XPATH_INVALID_OPERAND);
4816 }
4817 /*
4818 * Add tests for infinity and nan
4819 * => feedback on 3.4 for Inf and NaN
4820 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004821 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004822 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004823 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004824 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004825 arg1i=xmlXPathIsInf(arg1->floatval);
4826 arg2i=xmlXPathIsInf(arg2->floatval);
4827 if (inf && strict) {
4828 if ((arg1i == -1 && arg2i != -1) ||
4829 (arg2i == 1 && arg1i != 1)) {
4830 ret = 1;
4831 } else if (arg1i == 0 && arg2i == 0) {
4832 ret = (arg1->floatval < arg2->floatval);
4833 } else {
4834 ret = 0;
4835 }
4836 }
4837 else if (inf && !strict) {
4838 if (arg1i == -1 || arg2i == 1) {
4839 ret = 1;
4840 } else if (arg1i == 0 && arg2i == 0) {
4841 ret = (arg1->floatval <= arg2->floatval);
4842 } else {
4843 ret = 0;
4844 }
4845 }
4846 else if (!inf && strict) {
4847 if ((arg1i == 1 && arg2i != 1) ||
4848 (arg2i == -1 && arg1i != -1)) {
4849 ret = 1;
4850 } else if (arg1i == 0 && arg2i == 0) {
4851 ret = (arg1->floatval > arg2->floatval);
4852 } else {
4853 ret = 0;
4854 }
4855 }
4856 else if (!inf && !strict) {
4857 if (arg1i == 1 || arg2i == -1) {
4858 ret = 1;
4859 } else if (arg1i == 0 && arg2i == 0) {
4860 ret = (arg1->floatval >= arg2->floatval);
4861 } else {
4862 ret = 0;
4863 }
4864 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004865 }
Owen Taylor3473f882001-02-23 17:55:21 +00004866 xmlXPathFreeObject(arg1);
4867 xmlXPathFreeObject(arg2);
4868 return(ret);
4869}
4870
4871/**
4872 * xmlXPathValueFlipSign:
4873 * @ctxt: the XPath Parser context
4874 *
4875 * Implement the unary - operation on an XPath object
4876 * The numeric operators convert their operands to numbers as if
4877 * by calling the number function.
4878 */
4879void
4880xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004881 CAST_TO_NUMBER;
4882 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004883 if (xmlXPathIsNaN(ctxt->value->floatval))
4884 ctxt->value->floatval=xmlXPathNAN;
4885 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4886 ctxt->value->floatval=xmlXPathNINF;
4887 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4888 ctxt->value->floatval=xmlXPathPINF;
4889 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004890 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4891 ctxt->value->floatval = xmlXPathNZERO;
4892 else
4893 ctxt->value->floatval = 0;
4894 }
4895 else
4896 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004897}
4898
4899/**
4900 * xmlXPathAddValues:
4901 * @ctxt: the XPath Parser context
4902 *
4903 * Implement the add operation on XPath objects:
4904 * The numeric operators convert their operands to numbers as if
4905 * by calling the number function.
4906 */
4907void
4908xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4909 xmlXPathObjectPtr arg;
4910 double val;
4911
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004912 arg = valuePop(ctxt);
4913 if (arg == NULL)
4914 XP_ERROR(XPATH_INVALID_OPERAND);
4915 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004916 xmlXPathFreeObject(arg);
4917
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004918 CAST_TO_NUMBER;
4919 CHECK_TYPE(XPATH_NUMBER);
4920 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004921}
4922
4923/**
4924 * xmlXPathSubValues:
4925 * @ctxt: the XPath Parser context
4926 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004927 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004928 * The numeric operators convert their operands to numbers as if
4929 * by calling the number function.
4930 */
4931void
4932xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4933 xmlXPathObjectPtr arg;
4934 double val;
4935
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004936 arg = valuePop(ctxt);
4937 if (arg == NULL)
4938 XP_ERROR(XPATH_INVALID_OPERAND);
4939 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004940 xmlXPathFreeObject(arg);
4941
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004942 CAST_TO_NUMBER;
4943 CHECK_TYPE(XPATH_NUMBER);
4944 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004945}
4946
4947/**
4948 * xmlXPathMultValues:
4949 * @ctxt: the XPath Parser context
4950 *
4951 * Implement the multiply operation on XPath objects:
4952 * The numeric operators convert their operands to numbers as if
4953 * by calling the number function.
4954 */
4955void
4956xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4957 xmlXPathObjectPtr arg;
4958 double val;
4959
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004960 arg = valuePop(ctxt);
4961 if (arg == NULL)
4962 XP_ERROR(XPATH_INVALID_OPERAND);
4963 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004964 xmlXPathFreeObject(arg);
4965
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004966 CAST_TO_NUMBER;
4967 CHECK_TYPE(XPATH_NUMBER);
4968 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004969}
4970
4971/**
4972 * xmlXPathDivValues:
4973 * @ctxt: the XPath Parser context
4974 *
4975 * Implement the div operation on XPath objects @arg1 / @arg2:
4976 * The numeric operators convert their operands to numbers as if
4977 * by calling the number function.
4978 */
4979void
4980xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4981 xmlXPathObjectPtr arg;
4982 double val;
4983
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004984 arg = valuePop(ctxt);
4985 if (arg == NULL)
4986 XP_ERROR(XPATH_INVALID_OPERAND);
4987 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004988 xmlXPathFreeObject(arg);
4989
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004990 CAST_TO_NUMBER;
4991 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004992 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
4993 ctxt->value->floatval = xmlXPathNAN;
4994 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004995 if (ctxt->value->floatval == 0)
4996 ctxt->value->floatval = xmlXPathNAN;
4997 else if (ctxt->value->floatval > 0)
4998 ctxt->value->floatval = xmlXPathNINF;
4999 else if (ctxt->value->floatval < 0)
5000 ctxt->value->floatval = xmlXPathPINF;
5001 }
5002 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005003 if (ctxt->value->floatval == 0)
5004 ctxt->value->floatval = xmlXPathNAN;
5005 else if (ctxt->value->floatval > 0)
5006 ctxt->value->floatval = xmlXPathPINF;
5007 else if (ctxt->value->floatval < 0)
5008 ctxt->value->floatval = xmlXPathNINF;
5009 } else
5010 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005011}
5012
5013/**
5014 * xmlXPathModValues:
5015 * @ctxt: the XPath Parser context
5016 *
5017 * Implement the mod operation on XPath objects: @arg1 / @arg2
5018 * The numeric operators convert their operands to numbers as if
5019 * by calling the number function.
5020 */
5021void
5022xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5023 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005024 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005025
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005026 arg = valuePop(ctxt);
5027 if (arg == NULL)
5028 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005029 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005030 xmlXPathFreeObject(arg);
5031
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005032 CAST_TO_NUMBER;
5033 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005034 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005035 if (arg2 == 0)
5036 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005037 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005038 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005039 }
Owen Taylor3473f882001-02-23 17:55:21 +00005040}
5041
5042/************************************************************************
5043 * *
5044 * The traversal functions *
5045 * *
5046 ************************************************************************/
5047
Owen Taylor3473f882001-02-23 17:55:21 +00005048/*
5049 * A traversal function enumerates nodes along an axis.
5050 * Initially it must be called with NULL, and it indicates
5051 * termination on the axis by returning NULL.
5052 */
5053typedef xmlNodePtr (*xmlXPathTraversalFunction)
5054 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5055
5056/**
5057 * xmlXPathNextSelf:
5058 * @ctxt: the XPath Parser context
5059 * @cur: the current node in the traversal
5060 *
5061 * Traversal function for the "self" direction
5062 * The self axis contains just the context node itself
5063 *
5064 * Returns the next element following that axis
5065 */
5066xmlNodePtr
5067xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5068 if (cur == NULL)
5069 return(ctxt->context->node);
5070 return(NULL);
5071}
5072
5073/**
5074 * xmlXPathNextChild:
5075 * @ctxt: the XPath Parser context
5076 * @cur: the current node in the traversal
5077 *
5078 * Traversal function for the "child" direction
5079 * The child axis contains the children of the context node in document order.
5080 *
5081 * Returns the next element following that axis
5082 */
5083xmlNodePtr
5084xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5085 if (cur == NULL) {
5086 if (ctxt->context->node == NULL) return(NULL);
5087 switch (ctxt->context->node->type) {
5088 case XML_ELEMENT_NODE:
5089 case XML_TEXT_NODE:
5090 case XML_CDATA_SECTION_NODE:
5091 case XML_ENTITY_REF_NODE:
5092 case XML_ENTITY_NODE:
5093 case XML_PI_NODE:
5094 case XML_COMMENT_NODE:
5095 case XML_NOTATION_NODE:
5096 case XML_DTD_NODE:
5097 return(ctxt->context->node->children);
5098 case XML_DOCUMENT_NODE:
5099 case XML_DOCUMENT_TYPE_NODE:
5100 case XML_DOCUMENT_FRAG_NODE:
5101 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005102#ifdef LIBXML_DOCB_ENABLED
5103 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005104#endif
5105 return(((xmlDocPtr) ctxt->context->node)->children);
5106 case XML_ELEMENT_DECL:
5107 case XML_ATTRIBUTE_DECL:
5108 case XML_ENTITY_DECL:
5109 case XML_ATTRIBUTE_NODE:
5110 case XML_NAMESPACE_DECL:
5111 case XML_XINCLUDE_START:
5112 case XML_XINCLUDE_END:
5113 return(NULL);
5114 }
5115 return(NULL);
5116 }
5117 if ((cur->type == XML_DOCUMENT_NODE) ||
5118 (cur->type == XML_HTML_DOCUMENT_NODE))
5119 return(NULL);
5120 return(cur->next);
5121}
5122
5123/**
5124 * xmlXPathNextDescendant:
5125 * @ctxt: the XPath Parser context
5126 * @cur: the current node in the traversal
5127 *
5128 * Traversal function for the "descendant" direction
5129 * the descendant axis contains the descendants of the context node in document
5130 * order; a descendant is a child or a child of a child and so on.
5131 *
5132 * Returns the next element following that axis
5133 */
5134xmlNodePtr
5135xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5136 if (cur == NULL) {
5137 if (ctxt->context->node == NULL)
5138 return(NULL);
5139 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5140 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5141 return(NULL);
5142
5143 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5144 return(ctxt->context->doc->children);
5145 return(ctxt->context->node->children);
5146 }
5147
Daniel Veillard567e1b42001-08-01 15:53:47 +00005148 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005149 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00005150 return(cur->children);
5151 }
5152
5153 if (cur == ctxt->context->node) return(NULL);
5154
Owen Taylor3473f882001-02-23 17:55:21 +00005155 if (cur->next != NULL) return(cur->next);
5156
5157 do {
5158 cur = cur->parent;
5159 if (cur == NULL) return(NULL);
5160 if (cur == ctxt->context->node) return(NULL);
5161 if (cur->next != NULL) {
5162 cur = cur->next;
5163 return(cur);
5164 }
5165 } while (cur != NULL);
5166 return(cur);
5167}
5168
5169/**
5170 * xmlXPathNextDescendantOrSelf:
5171 * @ctxt: the XPath Parser context
5172 * @cur: the current node in the traversal
5173 *
5174 * Traversal function for the "descendant-or-self" direction
5175 * the descendant-or-self axis contains the context node and the descendants
5176 * of the context node in document order; thus the context node is the first
5177 * node on the axis, and the first child of the context node is the second node
5178 * on the axis
5179 *
5180 * Returns the next element following that axis
5181 */
5182xmlNodePtr
5183xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5184 if (cur == NULL) {
5185 if (ctxt->context->node == NULL)
5186 return(NULL);
5187 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5188 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5189 return(NULL);
5190 return(ctxt->context->node);
5191 }
5192
5193 return(xmlXPathNextDescendant(ctxt, cur));
5194}
5195
5196/**
5197 * xmlXPathNextParent:
5198 * @ctxt: the XPath Parser context
5199 * @cur: the current node in the traversal
5200 *
5201 * Traversal function for the "parent" direction
5202 * The parent axis contains the parent of the context node, if there is one.
5203 *
5204 * Returns the next element following that axis
5205 */
5206xmlNodePtr
5207xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5208 /*
5209 * the parent of an attribute or namespace node is the element
5210 * to which the attribute or namespace node is attached
5211 * Namespace handling !!!
5212 */
5213 if (cur == NULL) {
5214 if (ctxt->context->node == NULL) return(NULL);
5215 switch (ctxt->context->node->type) {
5216 case XML_ELEMENT_NODE:
5217 case XML_TEXT_NODE:
5218 case XML_CDATA_SECTION_NODE:
5219 case XML_ENTITY_REF_NODE:
5220 case XML_ENTITY_NODE:
5221 case XML_PI_NODE:
5222 case XML_COMMENT_NODE:
5223 case XML_NOTATION_NODE:
5224 case XML_DTD_NODE:
5225 case XML_ELEMENT_DECL:
5226 case XML_ATTRIBUTE_DECL:
5227 case XML_XINCLUDE_START:
5228 case XML_XINCLUDE_END:
5229 case XML_ENTITY_DECL:
5230 if (ctxt->context->node->parent == NULL)
5231 return((xmlNodePtr) ctxt->context->doc);
5232 return(ctxt->context->node->parent);
5233 case XML_ATTRIBUTE_NODE: {
5234 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5235
5236 return(att->parent);
5237 }
5238 case XML_DOCUMENT_NODE:
5239 case XML_DOCUMENT_TYPE_NODE:
5240 case XML_DOCUMENT_FRAG_NODE:
5241 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005242#ifdef LIBXML_DOCB_ENABLED
5243 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005244#endif
5245 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005246 case XML_NAMESPACE_DECL: {
5247 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5248
5249 if ((ns->next != NULL) &&
5250 (ns->next->type != XML_NAMESPACE_DECL))
5251 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005252 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005253 }
Owen Taylor3473f882001-02-23 17:55:21 +00005254 }
5255 }
5256 return(NULL);
5257}
5258
5259/**
5260 * xmlXPathNextAncestor:
5261 * @ctxt: the XPath Parser context
5262 * @cur: the current node in the traversal
5263 *
5264 * Traversal function for the "ancestor" direction
5265 * the ancestor axis contains the ancestors of the context node; the ancestors
5266 * of the context node consist of the parent of context node and the parent's
5267 * parent and so on; the nodes are ordered in reverse document order; thus the
5268 * parent is the first node on the axis, and the parent's parent is the second
5269 * node on the axis
5270 *
5271 * Returns the next element following that axis
5272 */
5273xmlNodePtr
5274xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5275 /*
5276 * the parent of an attribute or namespace node is the element
5277 * to which the attribute or namespace node is attached
5278 * !!!!!!!!!!!!!
5279 */
5280 if (cur == NULL) {
5281 if (ctxt->context->node == NULL) return(NULL);
5282 switch (ctxt->context->node->type) {
5283 case XML_ELEMENT_NODE:
5284 case XML_TEXT_NODE:
5285 case XML_CDATA_SECTION_NODE:
5286 case XML_ENTITY_REF_NODE:
5287 case XML_ENTITY_NODE:
5288 case XML_PI_NODE:
5289 case XML_COMMENT_NODE:
5290 case XML_DTD_NODE:
5291 case XML_ELEMENT_DECL:
5292 case XML_ATTRIBUTE_DECL:
5293 case XML_ENTITY_DECL:
5294 case XML_NOTATION_NODE:
5295 case XML_XINCLUDE_START:
5296 case XML_XINCLUDE_END:
5297 if (ctxt->context->node->parent == NULL)
5298 return((xmlNodePtr) ctxt->context->doc);
5299 return(ctxt->context->node->parent);
5300 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005301 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005302
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005303 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005304 }
5305 case XML_DOCUMENT_NODE:
5306 case XML_DOCUMENT_TYPE_NODE:
5307 case XML_DOCUMENT_FRAG_NODE:
5308 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005309#ifdef LIBXML_DOCB_ENABLED
5310 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005311#endif
5312 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005313 case XML_NAMESPACE_DECL: {
5314 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5315
5316 if ((ns->next != NULL) &&
5317 (ns->next->type != XML_NAMESPACE_DECL))
5318 return((xmlNodePtr) ns->next);
5319 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005320 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005321 }
Owen Taylor3473f882001-02-23 17:55:21 +00005322 }
5323 return(NULL);
5324 }
5325 if (cur == ctxt->context->doc->children)
5326 return((xmlNodePtr) ctxt->context->doc);
5327 if (cur == (xmlNodePtr) ctxt->context->doc)
5328 return(NULL);
5329 switch (cur->type) {
5330 case XML_ELEMENT_NODE:
5331 case XML_TEXT_NODE:
5332 case XML_CDATA_SECTION_NODE:
5333 case XML_ENTITY_REF_NODE:
5334 case XML_ENTITY_NODE:
5335 case XML_PI_NODE:
5336 case XML_COMMENT_NODE:
5337 case XML_NOTATION_NODE:
5338 case XML_DTD_NODE:
5339 case XML_ELEMENT_DECL:
5340 case XML_ATTRIBUTE_DECL:
5341 case XML_ENTITY_DECL:
5342 case XML_XINCLUDE_START:
5343 case XML_XINCLUDE_END:
5344 return(cur->parent);
5345 case XML_ATTRIBUTE_NODE: {
5346 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5347
5348 return(att->parent);
5349 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005350 case XML_NAMESPACE_DECL: {
5351 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5352
5353 if ((ns->next != NULL) &&
5354 (ns->next->type != XML_NAMESPACE_DECL))
5355 return((xmlNodePtr) ns->next);
5356 /* Bad, how did that namespace ended-up there ? */
5357 return(NULL);
5358 }
Owen Taylor3473f882001-02-23 17:55:21 +00005359 case XML_DOCUMENT_NODE:
5360 case XML_DOCUMENT_TYPE_NODE:
5361 case XML_DOCUMENT_FRAG_NODE:
5362 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005363#ifdef LIBXML_DOCB_ENABLED
5364 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005365#endif
5366 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005367 }
5368 return(NULL);
5369}
5370
5371/**
5372 * xmlXPathNextAncestorOrSelf:
5373 * @ctxt: the XPath Parser context
5374 * @cur: the current node in the traversal
5375 *
5376 * Traversal function for the "ancestor-or-self" direction
5377 * he ancestor-or-self axis contains the context node and ancestors of
5378 * the context node in reverse document order; thus the context node is
5379 * the first node on the axis, and the context node's parent the second;
5380 * parent here is defined the same as with the parent axis.
5381 *
5382 * Returns the next element following that axis
5383 */
5384xmlNodePtr
5385xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5386 if (cur == NULL)
5387 return(ctxt->context->node);
5388 return(xmlXPathNextAncestor(ctxt, cur));
5389}
5390
5391/**
5392 * xmlXPathNextFollowingSibling:
5393 * @ctxt: the XPath Parser context
5394 * @cur: the current node in the traversal
5395 *
5396 * Traversal function for the "following-sibling" direction
5397 * The following-sibling axis contains the following siblings of the context
5398 * node in document order.
5399 *
5400 * Returns the next element following that axis
5401 */
5402xmlNodePtr
5403xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5404 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5405 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5406 return(NULL);
5407 if (cur == (xmlNodePtr) ctxt->context->doc)
5408 return(NULL);
5409 if (cur == NULL)
5410 return(ctxt->context->node->next);
5411 return(cur->next);
5412}
5413
5414/**
5415 * xmlXPathNextPrecedingSibling:
5416 * @ctxt: the XPath Parser context
5417 * @cur: the current node in the traversal
5418 *
5419 * Traversal function for the "preceding-sibling" direction
5420 * The preceding-sibling axis contains the preceding siblings of the context
5421 * node in reverse document order; the first preceding sibling is first on the
5422 * axis; the sibling preceding that node is the second on the axis and so on.
5423 *
5424 * Returns the next element following that axis
5425 */
5426xmlNodePtr
5427xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5428 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5429 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5430 return(NULL);
5431 if (cur == (xmlNodePtr) ctxt->context->doc)
5432 return(NULL);
5433 if (cur == NULL)
5434 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005435 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5436 cur = cur->prev;
5437 if (cur == NULL)
5438 return(ctxt->context->node->prev);
5439 }
Owen Taylor3473f882001-02-23 17:55:21 +00005440 return(cur->prev);
5441}
5442
5443/**
5444 * xmlXPathNextFollowing:
5445 * @ctxt: the XPath Parser context
5446 * @cur: the current node in the traversal
5447 *
5448 * Traversal function for the "following" direction
5449 * The following axis contains all nodes in the same document as the context
5450 * node that are after the context node in document order, excluding any
5451 * descendants and excluding attribute nodes and namespace nodes; the nodes
5452 * are ordered in document order
5453 *
5454 * Returns the next element following that axis
5455 */
5456xmlNodePtr
5457xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5458 if (cur != NULL && cur->children != NULL)
5459 return cur->children ;
5460 if (cur == NULL) cur = ctxt->context->node;
5461 if (cur == NULL) return(NULL) ; /* ERROR */
5462 if (cur->next != NULL) return(cur->next) ;
5463 do {
5464 cur = cur->parent;
5465 if (cur == NULL) return(NULL);
5466 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5467 if (cur->next != NULL) return(cur->next);
5468 } while (cur != NULL);
5469 return(cur);
5470}
5471
5472/*
5473 * xmlXPathIsAncestor:
5474 * @ancestor: the ancestor node
5475 * @node: the current node
5476 *
5477 * Check that @ancestor is a @node's ancestor
5478 *
5479 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5480 */
5481static int
5482xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5483 if ((ancestor == NULL) || (node == NULL)) return(0);
5484 /* nodes need to be in the same document */
5485 if (ancestor->doc != node->doc) return(0);
5486 /* avoid searching if ancestor or node is the root node */
5487 if (ancestor == (xmlNodePtr) node->doc) return(1);
5488 if (node == (xmlNodePtr) ancestor->doc) return(0);
5489 while (node->parent != NULL) {
5490 if (node->parent == ancestor)
5491 return(1);
5492 node = node->parent;
5493 }
5494 return(0);
5495}
5496
5497/**
5498 * xmlXPathNextPreceding:
5499 * @ctxt: the XPath Parser context
5500 * @cur: the current node in the traversal
5501 *
5502 * Traversal function for the "preceding" direction
5503 * the preceding axis contains all nodes in the same document as the context
5504 * node that are before the context node in document order, excluding any
5505 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5506 * ordered in reverse document order
5507 *
5508 * Returns the next element following that axis
5509 */
5510xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005511xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5512{
Owen Taylor3473f882001-02-23 17:55:21 +00005513 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005514 cur = ctxt->context->node;
5515 if (cur == NULL)
5516 return (NULL);
5517 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5518 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005519 do {
5520 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005521 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5522 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005523 }
5524
5525 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005526 if (cur == NULL)
5527 return (NULL);
5528 if (cur == ctxt->context->doc->children)
5529 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005530 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005531 return (cur);
5532}
5533
5534/**
5535 * xmlXPathNextPrecedingInternal:
5536 * @ctxt: the XPath Parser context
5537 * @cur: the current node in the traversal
5538 *
5539 * Traversal function for the "preceding" direction
5540 * the preceding axis contains all nodes in the same document as the context
5541 * node that are before the context node in document order, excluding any
5542 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5543 * ordered in reverse document order
5544 * This is a faster implementation but internal only since it requires a
5545 * state kept in the parser context: ctxt->ancestor.
5546 *
5547 * Returns the next element following that axis
5548 */
5549static xmlNodePtr
5550xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5551 xmlNodePtr cur)
5552{
5553 if (cur == NULL) {
5554 cur = ctxt->context->node;
5555 if (cur == NULL)
5556 return (NULL);
5557 ctxt->ancestor = cur->parent;
5558 }
5559 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5560 cur = cur->prev;
5561 while (cur->prev == NULL) {
5562 cur = cur->parent;
5563 if (cur == NULL)
5564 return (NULL);
5565 if (cur == ctxt->context->doc->children)
5566 return (NULL);
5567 if (cur != ctxt->ancestor)
5568 return (cur);
5569 ctxt->ancestor = cur->parent;
5570 }
5571 cur = cur->prev;
5572 while (cur->last != NULL)
5573 cur = cur->last;
5574 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005575}
5576
5577/**
5578 * xmlXPathNextNamespace:
5579 * @ctxt: the XPath Parser context
5580 * @cur: the current attribute in the traversal
5581 *
5582 * Traversal function for the "namespace" direction
5583 * the namespace axis contains the namespace nodes of the context node;
5584 * the order of nodes on this axis is implementation-defined; the axis will
5585 * be empty unless the context node is an element
5586 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005587 * We keep the XML namespace node at the end of the list.
5588 *
Owen Taylor3473f882001-02-23 17:55:21 +00005589 * Returns the next element following that axis
5590 */
5591xmlNodePtr
5592xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5593 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005594 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005595 if (ctxt->context->tmpNsList != NULL)
5596 xmlFree(ctxt->context->tmpNsList);
5597 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005598 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005599 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005600 if (ctxt->context->tmpNsList != NULL) {
5601 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5602 ctxt->context->tmpNsNr++;
5603 }
5604 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005605 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005606 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005607 if (ctxt->context->tmpNsNr > 0) {
5608 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5609 } else {
5610 if (ctxt->context->tmpNsList != NULL)
5611 xmlFree(ctxt->context->tmpNsList);
5612 ctxt->context->tmpNsList = NULL;
5613 return(NULL);
5614 }
Owen Taylor3473f882001-02-23 17:55:21 +00005615}
5616
5617/**
5618 * xmlXPathNextAttribute:
5619 * @ctxt: the XPath Parser context
5620 * @cur: the current attribute in the traversal
5621 *
5622 * Traversal function for the "attribute" direction
5623 * TODO: support DTD inherited default attributes
5624 *
5625 * Returns the next element following that axis
5626 */
5627xmlNodePtr
5628xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005629 if (ctxt->context->node == NULL)
5630 return(NULL);
5631 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5632 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005633 if (cur == NULL) {
5634 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5635 return(NULL);
5636 return((xmlNodePtr)ctxt->context->node->properties);
5637 }
5638 return((xmlNodePtr)cur->next);
5639}
5640
5641/************************************************************************
5642 * *
5643 * NodeTest Functions *
5644 * *
5645 ************************************************************************/
5646
Owen Taylor3473f882001-02-23 17:55:21 +00005647#define IS_FUNCTION 200
5648
Owen Taylor3473f882001-02-23 17:55:21 +00005649
5650/************************************************************************
5651 * *
5652 * Implicit tree core function library *
5653 * *
5654 ************************************************************************/
5655
5656/**
5657 * xmlXPathRoot:
5658 * @ctxt: the XPath Parser context
5659 *
5660 * Initialize the context to the root of the document
5661 */
5662void
5663xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5664 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5665 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5666}
5667
5668/************************************************************************
5669 * *
5670 * The explicit core function library *
5671 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5672 * *
5673 ************************************************************************/
5674
5675
5676/**
5677 * xmlXPathLastFunction:
5678 * @ctxt: the XPath Parser context
5679 * @nargs: the number of arguments
5680 *
5681 * Implement the last() XPath function
5682 * number last()
5683 * The last function returns the number of nodes in the context node list.
5684 */
5685void
5686xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5687 CHECK_ARITY(0);
5688 if (ctxt->context->contextSize >= 0) {
5689 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5690#ifdef DEBUG_EXPR
5691 xmlGenericError(xmlGenericErrorContext,
5692 "last() : %d\n", ctxt->context->contextSize);
5693#endif
5694 } else {
5695 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5696 }
5697}
5698
5699/**
5700 * xmlXPathPositionFunction:
5701 * @ctxt: the XPath Parser context
5702 * @nargs: the number of arguments
5703 *
5704 * Implement the position() XPath function
5705 * number position()
5706 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005707 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005708 * will be equal to last().
5709 */
5710void
5711xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5712 CHECK_ARITY(0);
5713 if (ctxt->context->proximityPosition >= 0) {
5714 valuePush(ctxt,
5715 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5716#ifdef DEBUG_EXPR
5717 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5718 ctxt->context->proximityPosition);
5719#endif
5720 } else {
5721 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5722 }
5723}
5724
5725/**
5726 * xmlXPathCountFunction:
5727 * @ctxt: the XPath Parser context
5728 * @nargs: the number of arguments
5729 *
5730 * Implement the count() XPath function
5731 * number count(node-set)
5732 */
5733void
5734xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5735 xmlXPathObjectPtr cur;
5736
5737 CHECK_ARITY(1);
5738 if ((ctxt->value == NULL) ||
5739 ((ctxt->value->type != XPATH_NODESET) &&
5740 (ctxt->value->type != XPATH_XSLT_TREE)))
5741 XP_ERROR(XPATH_INVALID_TYPE);
5742 cur = valuePop(ctxt);
5743
Daniel Veillard911f49a2001-04-07 15:39:35 +00005744 if ((cur == NULL) || (cur->nodesetval == NULL))
5745 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005746 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005747 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005748 } else {
5749 if ((cur->nodesetval->nodeNr != 1) ||
5750 (cur->nodesetval->nodeTab == NULL)) {
5751 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5752 } else {
5753 xmlNodePtr tmp;
5754 int i = 0;
5755
5756 tmp = cur->nodesetval->nodeTab[0];
5757 if (tmp != NULL) {
5758 tmp = tmp->children;
5759 while (tmp != NULL) {
5760 tmp = tmp->next;
5761 i++;
5762 }
5763 }
5764 valuePush(ctxt, xmlXPathNewFloat((double) i));
5765 }
5766 }
Owen Taylor3473f882001-02-23 17:55:21 +00005767 xmlXPathFreeObject(cur);
5768}
5769
5770/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005771 * xmlXPathGetElementsByIds:
5772 * @doc: the document
5773 * @ids: a whitespace separated list of IDs
5774 *
5775 * Selects elements by their unique ID.
5776 *
5777 * Returns a node-set of selected elements.
5778 */
5779static xmlNodeSetPtr
5780xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5781 xmlNodeSetPtr ret;
5782 const xmlChar *cur = ids;
5783 xmlChar *ID;
5784 xmlAttrPtr attr;
5785 xmlNodePtr elem = NULL;
5786
5787 ret = xmlXPathNodeSetCreate(NULL);
5788
5789 while (IS_BLANK(*cur)) cur++;
5790 while (*cur != 0) {
5791 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5792 (*cur == '.') || (*cur == '-') ||
5793 (*cur == '_') || (*cur == ':') ||
5794 (IS_COMBINING(*cur)) ||
5795 (IS_EXTENDER(*cur)))
5796 cur++;
5797
5798 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5799
5800 ID = xmlStrndup(ids, cur - ids);
5801 attr = xmlGetID(doc, ID);
5802 if (attr != NULL) {
5803 elem = attr->parent;
5804 xmlXPathNodeSetAdd(ret, elem);
5805 }
5806 if (ID != NULL)
5807 xmlFree(ID);
5808
5809 while (IS_BLANK(*cur)) cur++;
5810 ids = cur;
5811 }
5812 return(ret);
5813}
5814
5815/**
Owen Taylor3473f882001-02-23 17:55:21 +00005816 * xmlXPathIdFunction:
5817 * @ctxt: the XPath Parser context
5818 * @nargs: the number of arguments
5819 *
5820 * Implement the id() XPath function
5821 * node-set id(object)
5822 * The id function selects elements by their unique ID
5823 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5824 * then the result is the union of the result of applying id to the
5825 * string value of each of the nodes in the argument node-set. When the
5826 * argument to id is of any other type, the argument is converted to a
5827 * string as if by a call to the string function; the string is split
5828 * into a whitespace-separated list of tokens (whitespace is any sequence
5829 * of characters matching the production S); the result is a node-set
5830 * containing the elements in the same document as the context node that
5831 * have a unique ID equal to any of the tokens in the list.
5832 */
5833void
5834xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005835 xmlChar *tokens;
5836 xmlNodeSetPtr ret;
5837 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005838
5839 CHECK_ARITY(1);
5840 obj = valuePop(ctxt);
5841 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005842 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005843 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005844 int i;
5845
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005846 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005847
Daniel Veillard911f49a2001-04-07 15:39:35 +00005848 if (obj->nodesetval != NULL) {
5849 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005850 tokens =
5851 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5852 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5853 ret = xmlXPathNodeSetMerge(ret, ns);
5854 xmlXPathFreeNodeSet(ns);
5855 if (tokens != NULL)
5856 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005857 }
Owen Taylor3473f882001-02-23 17:55:21 +00005858 }
5859
5860 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005861 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005862 return;
5863 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005864 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005865
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005866 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5867 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005868
Owen Taylor3473f882001-02-23 17:55:21 +00005869 xmlXPathFreeObject(obj);
5870 return;
5871}
5872
5873/**
5874 * xmlXPathLocalNameFunction:
5875 * @ctxt: the XPath Parser context
5876 * @nargs: the number of arguments
5877 *
5878 * Implement the local-name() XPath function
5879 * string local-name(node-set?)
5880 * The local-name function returns a string containing the local part
5881 * of the name of the node in the argument node-set that is first in
5882 * document order. If the node-set is empty or the first node has no
5883 * name, an empty string is returned. If the argument is omitted it
5884 * defaults to the context node.
5885 */
5886void
5887xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5888 xmlXPathObjectPtr cur;
5889
5890 if (nargs == 0) {
5891 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5892 nargs = 1;
5893 }
5894
5895 CHECK_ARITY(1);
5896 if ((ctxt->value == NULL) ||
5897 ((ctxt->value->type != XPATH_NODESET) &&
5898 (ctxt->value->type != XPATH_XSLT_TREE)))
5899 XP_ERROR(XPATH_INVALID_TYPE);
5900 cur = valuePop(ctxt);
5901
Daniel Veillard911f49a2001-04-07 15:39:35 +00005902 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005903 valuePush(ctxt, xmlXPathNewCString(""));
5904 } else {
5905 int i = 0; /* Should be first in document order !!!!! */
5906 switch (cur->nodesetval->nodeTab[i]->type) {
5907 case XML_ELEMENT_NODE:
5908 case XML_ATTRIBUTE_NODE:
5909 case XML_PI_NODE:
5910 valuePush(ctxt,
5911 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5912 break;
5913 case XML_NAMESPACE_DECL:
5914 valuePush(ctxt, xmlXPathNewString(
5915 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5916 break;
5917 default:
5918 valuePush(ctxt, xmlXPathNewCString(""));
5919 }
5920 }
5921 xmlXPathFreeObject(cur);
5922}
5923
5924/**
5925 * xmlXPathNamespaceURIFunction:
5926 * @ctxt: the XPath Parser context
5927 * @nargs: the number of arguments
5928 *
5929 * Implement the namespace-uri() XPath function
5930 * string namespace-uri(node-set?)
5931 * The namespace-uri function returns a string containing the
5932 * namespace URI of the expanded name of the node in the argument
5933 * node-set that is first in document order. If the node-set is empty,
5934 * the first node has no name, or the expanded name has no namespace
5935 * URI, an empty string is returned. If the argument is omitted it
5936 * defaults to the context node.
5937 */
5938void
5939xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5940 xmlXPathObjectPtr cur;
5941
5942 if (nargs == 0) {
5943 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5944 nargs = 1;
5945 }
5946 CHECK_ARITY(1);
5947 if ((ctxt->value == NULL) ||
5948 ((ctxt->value->type != XPATH_NODESET) &&
5949 (ctxt->value->type != XPATH_XSLT_TREE)))
5950 XP_ERROR(XPATH_INVALID_TYPE);
5951 cur = valuePop(ctxt);
5952
Daniel Veillard911f49a2001-04-07 15:39:35 +00005953 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005954 valuePush(ctxt, xmlXPathNewCString(""));
5955 } else {
5956 int i = 0; /* Should be first in document order !!!!! */
5957 switch (cur->nodesetval->nodeTab[i]->type) {
5958 case XML_ELEMENT_NODE:
5959 case XML_ATTRIBUTE_NODE:
5960 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5961 valuePush(ctxt, xmlXPathNewCString(""));
5962 else
5963 valuePush(ctxt, xmlXPathNewString(
5964 cur->nodesetval->nodeTab[i]->ns->href));
5965 break;
5966 default:
5967 valuePush(ctxt, xmlXPathNewCString(""));
5968 }
5969 }
5970 xmlXPathFreeObject(cur);
5971}
5972
5973/**
5974 * xmlXPathNameFunction:
5975 * @ctxt: the XPath Parser context
5976 * @nargs: the number of arguments
5977 *
5978 * Implement the name() XPath function
5979 * string name(node-set?)
5980 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005981 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005982 * order. The QName must represent the name with respect to the namespace
5983 * declarations in effect on the node whose name is being represented.
5984 * Typically, this will be the form in which the name occurred in the XML
5985 * source. This need not be the case if there are namespace declarations
5986 * in effect on the node that associate multiple prefixes with the same
5987 * namespace. However, an implementation may include information about
5988 * the original prefix in its representation of nodes; in this case, an
5989 * implementation can ensure that the returned string is always the same
5990 * as the QName used in the XML source. If the argument it omitted it
5991 * defaults to the context node.
5992 * Libxml keep the original prefix so the "real qualified name" used is
5993 * returned.
5994 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005995static void
Daniel Veillard04383752001-07-08 14:27:15 +00005996xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5997{
Owen Taylor3473f882001-02-23 17:55:21 +00005998 xmlXPathObjectPtr cur;
5999
6000 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006001 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6002 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006003 }
6004
6005 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006006 if ((ctxt->value == NULL) ||
6007 ((ctxt->value->type != XPATH_NODESET) &&
6008 (ctxt->value->type != XPATH_XSLT_TREE)))
6009 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006010 cur = valuePop(ctxt);
6011
Daniel Veillard911f49a2001-04-07 15:39:35 +00006012 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006013 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006014 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006015 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006016
Daniel Veillard04383752001-07-08 14:27:15 +00006017 switch (cur->nodesetval->nodeTab[i]->type) {
6018 case XML_ELEMENT_NODE:
6019 case XML_ATTRIBUTE_NODE:
6020 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6021 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
6022 valuePush(ctxt,
6023 xmlXPathNewString(cur->nodesetval->
6024 nodeTab[i]->name));
6025
6026 else {
6027 char name[2000];
6028
6029 snprintf(name, sizeof(name), "%s:%s",
6030 (char *) cur->nodesetval->nodeTab[i]->ns->
6031 prefix,
6032 (char *) cur->nodesetval->nodeTab[i]->name);
6033 name[sizeof(name) - 1] = 0;
6034 valuePush(ctxt, xmlXPathNewCString(name));
6035 }
6036 break;
6037 default:
6038 valuePush(ctxt,
6039 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6040 xmlXPathLocalNameFunction(ctxt, 1);
6041 }
Owen Taylor3473f882001-02-23 17:55:21 +00006042 }
6043 xmlXPathFreeObject(cur);
6044}
6045
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006046
6047/**
Owen Taylor3473f882001-02-23 17:55:21 +00006048 * xmlXPathStringFunction:
6049 * @ctxt: the XPath Parser context
6050 * @nargs: the number of arguments
6051 *
6052 * Implement the string() XPath function
6053 * string string(object?)
6054 * he string function converts an object to a string as follows:
6055 * - A node-set is converted to a string by returning the value of
6056 * the node in the node-set that is first in document order.
6057 * If the node-set is empty, an empty string is returned.
6058 * - A number is converted to a string as follows
6059 * + NaN is converted to the string NaN
6060 * + positive zero is converted to the string 0
6061 * + negative zero is converted to the string 0
6062 * + positive infinity is converted to the string Infinity
6063 * + negative infinity is converted to the string -Infinity
6064 * + if the number is an integer, the number is represented in
6065 * decimal form as a Number with no decimal point and no leading
6066 * zeros, preceded by a minus sign (-) if the number is negative
6067 * + otherwise, the number is represented in decimal form as a
6068 * Number including a decimal point with at least one digit
6069 * before the decimal point and at least one digit after the
6070 * decimal point, preceded by a minus sign (-) if the number
6071 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006072 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006073 * before the decimal point; beyond the one required digit
6074 * after the decimal point there must be as many, but only as
6075 * many, more digits as are needed to uniquely distinguish the
6076 * number from all other IEEE 754 numeric values.
6077 * - The boolean false value is converted to the string false.
6078 * The boolean true value is converted to the string true.
6079 *
6080 * If the argument is omitted, it defaults to a node-set with the
6081 * context node as its only member.
6082 */
6083void
6084xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6085 xmlXPathObjectPtr cur;
6086
6087 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006088 valuePush(ctxt,
6089 xmlXPathWrapString(
6090 xmlXPathCastNodeToString(ctxt->context->node)));
6091 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006092 }
6093
6094 CHECK_ARITY(1);
6095 cur = valuePop(ctxt);
6096 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006097 cur = xmlXPathConvertString(cur);
6098 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006099}
6100
6101/**
6102 * xmlXPathStringLengthFunction:
6103 * @ctxt: the XPath Parser context
6104 * @nargs: the number of arguments
6105 *
6106 * Implement the string-length() XPath function
6107 * number string-length(string?)
6108 * The string-length returns the number of characters in the string
6109 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6110 * the context node converted to a string, in other words the value
6111 * of the context node.
6112 */
6113void
6114xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6115 xmlXPathObjectPtr cur;
6116
6117 if (nargs == 0) {
6118 if (ctxt->context->node == NULL) {
6119 valuePush(ctxt, xmlXPathNewFloat(0));
6120 } else {
6121 xmlChar *content;
6122
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006123 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006124 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006125 xmlFree(content);
6126 }
6127 return;
6128 }
6129 CHECK_ARITY(1);
6130 CAST_TO_STRING;
6131 CHECK_TYPE(XPATH_STRING);
6132 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006133 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006134 xmlXPathFreeObject(cur);
6135}
6136
6137/**
6138 * xmlXPathConcatFunction:
6139 * @ctxt: the XPath Parser context
6140 * @nargs: the number of arguments
6141 *
6142 * Implement the concat() XPath function
6143 * string concat(string, string, string*)
6144 * The concat function returns the concatenation of its arguments.
6145 */
6146void
6147xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6148 xmlXPathObjectPtr cur, newobj;
6149 xmlChar *tmp;
6150
6151 if (nargs < 2) {
6152 CHECK_ARITY(2);
6153 }
6154
6155 CAST_TO_STRING;
6156 cur = valuePop(ctxt);
6157 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6158 xmlXPathFreeObject(cur);
6159 return;
6160 }
6161 nargs--;
6162
6163 while (nargs > 0) {
6164 CAST_TO_STRING;
6165 newobj = valuePop(ctxt);
6166 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6167 xmlXPathFreeObject(newobj);
6168 xmlXPathFreeObject(cur);
6169 XP_ERROR(XPATH_INVALID_TYPE);
6170 }
6171 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6172 newobj->stringval = cur->stringval;
6173 cur->stringval = tmp;
6174
6175 xmlXPathFreeObject(newobj);
6176 nargs--;
6177 }
6178 valuePush(ctxt, cur);
6179}
6180
6181/**
6182 * xmlXPathContainsFunction:
6183 * @ctxt: the XPath Parser context
6184 * @nargs: the number of arguments
6185 *
6186 * Implement the contains() XPath function
6187 * boolean contains(string, string)
6188 * The contains function returns true if the first argument string
6189 * contains the second argument string, and otherwise returns false.
6190 */
6191void
6192xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6193 xmlXPathObjectPtr hay, needle;
6194
6195 CHECK_ARITY(2);
6196 CAST_TO_STRING;
6197 CHECK_TYPE(XPATH_STRING);
6198 needle = valuePop(ctxt);
6199 CAST_TO_STRING;
6200 hay = valuePop(ctxt);
6201 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6202 xmlXPathFreeObject(hay);
6203 xmlXPathFreeObject(needle);
6204 XP_ERROR(XPATH_INVALID_TYPE);
6205 }
6206 if (xmlStrstr(hay->stringval, needle->stringval))
6207 valuePush(ctxt, xmlXPathNewBoolean(1));
6208 else
6209 valuePush(ctxt, xmlXPathNewBoolean(0));
6210 xmlXPathFreeObject(hay);
6211 xmlXPathFreeObject(needle);
6212}
6213
6214/**
6215 * xmlXPathStartsWithFunction:
6216 * @ctxt: the XPath Parser context
6217 * @nargs: the number of arguments
6218 *
6219 * Implement the starts-with() XPath function
6220 * boolean starts-with(string, string)
6221 * The starts-with function returns true if the first argument string
6222 * starts with the second argument string, and otherwise returns false.
6223 */
6224void
6225xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6226 xmlXPathObjectPtr hay, needle;
6227 int n;
6228
6229 CHECK_ARITY(2);
6230 CAST_TO_STRING;
6231 CHECK_TYPE(XPATH_STRING);
6232 needle = valuePop(ctxt);
6233 CAST_TO_STRING;
6234 hay = valuePop(ctxt);
6235 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6236 xmlXPathFreeObject(hay);
6237 xmlXPathFreeObject(needle);
6238 XP_ERROR(XPATH_INVALID_TYPE);
6239 }
6240 n = xmlStrlen(needle->stringval);
6241 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6242 valuePush(ctxt, xmlXPathNewBoolean(0));
6243 else
6244 valuePush(ctxt, xmlXPathNewBoolean(1));
6245 xmlXPathFreeObject(hay);
6246 xmlXPathFreeObject(needle);
6247}
6248
6249/**
6250 * xmlXPathSubstringFunction:
6251 * @ctxt: the XPath Parser context
6252 * @nargs: the number of arguments
6253 *
6254 * Implement the substring() XPath function
6255 * string substring(string, number, number?)
6256 * The substring function returns the substring of the first argument
6257 * starting at the position specified in the second argument with
6258 * length specified in the third argument. For example,
6259 * substring("12345",2,3) returns "234". If the third argument is not
6260 * specified, it returns the substring starting at the position specified
6261 * in the second argument and continuing to the end of the string. For
6262 * example, substring("12345",2) returns "2345". More precisely, each
6263 * character in the string (see [3.6 Strings]) is considered to have a
6264 * numeric position: the position of the first character is 1, the position
6265 * of the second character is 2 and so on. The returned substring contains
6266 * those characters for which the position of the character is greater than
6267 * or equal to the second argument and, if the third argument is specified,
6268 * less than the sum of the second and third arguments; the comparisons
6269 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6270 * - substring("12345", 1.5, 2.6) returns "234"
6271 * - substring("12345", 0, 3) returns "12"
6272 * - substring("12345", 0 div 0, 3) returns ""
6273 * - substring("12345", 1, 0 div 0) returns ""
6274 * - substring("12345", -42, 1 div 0) returns "12345"
6275 * - substring("12345", -1 div 0, 1 div 0) returns ""
6276 */
6277void
6278xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6279 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006280 double le=0, in;
6281 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006282 xmlChar *ret;
6283
Owen Taylor3473f882001-02-23 17:55:21 +00006284 if (nargs < 2) {
6285 CHECK_ARITY(2);
6286 }
6287 if (nargs > 3) {
6288 CHECK_ARITY(3);
6289 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006290 /*
6291 * take care of possible last (position) argument
6292 */
Owen Taylor3473f882001-02-23 17:55:21 +00006293 if (nargs == 3) {
6294 CAST_TO_NUMBER;
6295 CHECK_TYPE(XPATH_NUMBER);
6296 len = valuePop(ctxt);
6297 le = len->floatval;
6298 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006299 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006300
Owen Taylor3473f882001-02-23 17:55:21 +00006301 CAST_TO_NUMBER;
6302 CHECK_TYPE(XPATH_NUMBER);
6303 start = valuePop(ctxt);
6304 in = start->floatval;
6305 xmlXPathFreeObject(start);
6306 CAST_TO_STRING;
6307 CHECK_TYPE(XPATH_STRING);
6308 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006309 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006310
Daniel Veillard97ac1312001-05-30 19:14:17 +00006311 /*
6312 * If last pos not present, calculate last position
6313 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006314 if (nargs != 3) {
6315 le = (double)m;
6316 if (in < 1.0)
6317 in = 1.0;
6318 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006319
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006320 /* Need to check for the special cases where either
6321 * the index is NaN, the length is NaN, or both
6322 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006323 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006324 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006325 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006326 * To meet the requirements of the spec, the arguments
6327 * must be converted to integer format before
6328 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006329 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006330 * First we go to integer form, rounding up
6331 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006332 */
6333 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006334 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006335
Daniel Veillard9e412302002-06-10 15:59:44 +00006336 if (xmlXPathIsInf(le) == 1) {
6337 l = m;
6338 if (i < 1)
6339 i = 1;
6340 }
6341 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6342 l = 0;
6343 else {
6344 l = (int) le;
6345 if (((double)l)+0.5 <= le) l++;
6346 }
6347
6348 /* Now we normalize inidices */
6349 i -= 1;
6350 l += i;
6351 if (i < 0)
6352 i = 0;
6353 if (l > m)
6354 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006355
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006356 /* number of chars to copy */
6357 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006358
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006359 ret = xmlUTF8Strsub(str->stringval, i, l);
6360 }
6361 else {
6362 ret = NULL;
6363 }
6364
Owen Taylor3473f882001-02-23 17:55:21 +00006365 if (ret == NULL)
6366 valuePush(ctxt, xmlXPathNewCString(""));
6367 else {
6368 valuePush(ctxt, xmlXPathNewString(ret));
6369 xmlFree(ret);
6370 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006371
Owen Taylor3473f882001-02-23 17:55:21 +00006372 xmlXPathFreeObject(str);
6373}
6374
6375/**
6376 * xmlXPathSubstringBeforeFunction:
6377 * @ctxt: the XPath Parser context
6378 * @nargs: the number of arguments
6379 *
6380 * Implement the substring-before() XPath function
6381 * string substring-before(string, string)
6382 * The substring-before function returns the substring of the first
6383 * argument string that precedes the first occurrence of the second
6384 * argument string in the first argument string, or the empty string
6385 * if the first argument string does not contain the second argument
6386 * string. For example, substring-before("1999/04/01","/") returns 1999.
6387 */
6388void
6389xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6390 xmlXPathObjectPtr str;
6391 xmlXPathObjectPtr find;
6392 xmlBufferPtr target;
6393 const xmlChar *point;
6394 int offset;
6395
6396 CHECK_ARITY(2);
6397 CAST_TO_STRING;
6398 find = valuePop(ctxt);
6399 CAST_TO_STRING;
6400 str = valuePop(ctxt);
6401
6402 target = xmlBufferCreate();
6403 if (target) {
6404 point = xmlStrstr(str->stringval, find->stringval);
6405 if (point) {
6406 offset = (int)(point - str->stringval);
6407 xmlBufferAdd(target, str->stringval, offset);
6408 }
6409 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6410 xmlBufferFree(target);
6411 }
6412
6413 xmlXPathFreeObject(str);
6414 xmlXPathFreeObject(find);
6415}
6416
6417/**
6418 * xmlXPathSubstringAfterFunction:
6419 * @ctxt: the XPath Parser context
6420 * @nargs: the number of arguments
6421 *
6422 * Implement the substring-after() XPath function
6423 * string substring-after(string, string)
6424 * The substring-after function returns the substring of the first
6425 * argument string that follows the first occurrence of the second
6426 * argument string in the first argument string, or the empty stringi
6427 * if the first argument string does not contain the second argument
6428 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6429 * and substring-after("1999/04/01","19") returns 99/04/01.
6430 */
6431void
6432xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6433 xmlXPathObjectPtr str;
6434 xmlXPathObjectPtr find;
6435 xmlBufferPtr target;
6436 const xmlChar *point;
6437 int offset;
6438
6439 CHECK_ARITY(2);
6440 CAST_TO_STRING;
6441 find = valuePop(ctxt);
6442 CAST_TO_STRING;
6443 str = valuePop(ctxt);
6444
6445 target = xmlBufferCreate();
6446 if (target) {
6447 point = xmlStrstr(str->stringval, find->stringval);
6448 if (point) {
6449 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6450 xmlBufferAdd(target, &str->stringval[offset],
6451 xmlStrlen(str->stringval) - offset);
6452 }
6453 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6454 xmlBufferFree(target);
6455 }
6456
6457 xmlXPathFreeObject(str);
6458 xmlXPathFreeObject(find);
6459}
6460
6461/**
6462 * xmlXPathNormalizeFunction:
6463 * @ctxt: the XPath Parser context
6464 * @nargs: the number of arguments
6465 *
6466 * Implement the normalize-space() XPath function
6467 * string normalize-space(string?)
6468 * The normalize-space function returns the argument string with white
6469 * space normalized by stripping leading and trailing whitespace
6470 * and replacing sequences of whitespace characters by a single
6471 * space. Whitespace characters are the same allowed by the S production
6472 * in XML. If the argument is omitted, it defaults to the context
6473 * node converted to a string, in other words the value of the context node.
6474 */
6475void
6476xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6477 xmlXPathObjectPtr obj = NULL;
6478 xmlChar *source = NULL;
6479 xmlBufferPtr target;
6480 xmlChar blank;
6481
6482 if (nargs == 0) {
6483 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006484 valuePush(ctxt,
6485 xmlXPathWrapString(
6486 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006487 nargs = 1;
6488 }
6489
6490 CHECK_ARITY(1);
6491 CAST_TO_STRING;
6492 CHECK_TYPE(XPATH_STRING);
6493 obj = valuePop(ctxt);
6494 source = obj->stringval;
6495
6496 target = xmlBufferCreate();
6497 if (target && source) {
6498
6499 /* Skip leading whitespaces */
6500 while (IS_BLANK(*source))
6501 source++;
6502
6503 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6504 blank = 0;
6505 while (*source) {
6506 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006507 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006508 } else {
6509 if (blank) {
6510 xmlBufferAdd(target, &blank, 1);
6511 blank = 0;
6512 }
6513 xmlBufferAdd(target, source, 1);
6514 }
6515 source++;
6516 }
6517
6518 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6519 xmlBufferFree(target);
6520 }
6521 xmlXPathFreeObject(obj);
6522}
6523
6524/**
6525 * xmlXPathTranslateFunction:
6526 * @ctxt: the XPath Parser context
6527 * @nargs: the number of arguments
6528 *
6529 * Implement the translate() XPath function
6530 * string translate(string, string, string)
6531 * The translate function returns the first argument string with
6532 * occurrences of characters in the second argument string replaced
6533 * by the character at the corresponding position in the third argument
6534 * string. For example, translate("bar","abc","ABC") returns the string
6535 * BAr. If there is a character in the second argument string with no
6536 * character at a corresponding position in the third argument string
6537 * (because the second argument string is longer than the third argument
6538 * string), then occurrences of that character in the first argument
6539 * string are removed. For example, translate("--aaa--","abc-","ABC")
6540 * returns "AAA". If a character occurs more than once in second
6541 * argument string, then the first occurrence determines the replacement
6542 * character. If the third argument string is longer than the second
6543 * argument string, then excess characters are ignored.
6544 */
6545void
6546xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006547 xmlXPathObjectPtr str;
6548 xmlXPathObjectPtr from;
6549 xmlXPathObjectPtr to;
6550 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006551 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006552 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006553 xmlChar *point;
6554 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006555
Daniel Veillarde043ee12001-04-16 14:08:07 +00006556 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006557
Daniel Veillarde043ee12001-04-16 14:08:07 +00006558 CAST_TO_STRING;
6559 to = valuePop(ctxt);
6560 CAST_TO_STRING;
6561 from = valuePop(ctxt);
6562 CAST_TO_STRING;
6563 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006564
Daniel Veillarde043ee12001-04-16 14:08:07 +00006565 target = xmlBufferCreate();
6566 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006567 max = xmlUTF8Strlen(to->stringval);
6568 for (cptr = str->stringval; (ch=*cptr); ) {
6569 offset = xmlUTF8Strloc(from->stringval, cptr);
6570 if (offset >= 0) {
6571 if (offset < max) {
6572 point = xmlUTF8Strpos(to->stringval, offset);
6573 if (point)
6574 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6575 }
6576 } else
6577 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6578
6579 /* Step to next character in input */
6580 cptr++;
6581 if ( ch & 0x80 ) {
6582 /* if not simple ascii, verify proper format */
6583 if ( (ch & 0xc0) != 0xc0 ) {
6584 xmlGenericError(xmlGenericErrorContext,
6585 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6586 break;
6587 }
6588 /* then skip over remaining bytes for this char */
6589 while ( (ch <<= 1) & 0x80 )
6590 if ( (*cptr++ & 0xc0) != 0x80 ) {
6591 xmlGenericError(xmlGenericErrorContext,
6592 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6593 break;
6594 }
6595 if (ch & 0x80) /* must have had error encountered */
6596 break;
6597 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006598 }
Owen Taylor3473f882001-02-23 17:55:21 +00006599 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006600 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6601 xmlBufferFree(target);
6602 xmlXPathFreeObject(str);
6603 xmlXPathFreeObject(from);
6604 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006605}
6606
6607/**
6608 * xmlXPathBooleanFunction:
6609 * @ctxt: the XPath Parser context
6610 * @nargs: the number of arguments
6611 *
6612 * Implement the boolean() XPath function
6613 * boolean boolean(object)
6614 * he boolean function converts its argument to a boolean as follows:
6615 * - a number is true if and only if it is neither positive or
6616 * negative zero nor NaN
6617 * - a node-set is true if and only if it is non-empty
6618 * - a string is true if and only if its length is non-zero
6619 */
6620void
6621xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6622 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006623
6624 CHECK_ARITY(1);
6625 cur = valuePop(ctxt);
6626 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006627 cur = xmlXPathConvertBoolean(cur);
6628 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006629}
6630
6631/**
6632 * xmlXPathNotFunction:
6633 * @ctxt: the XPath Parser context
6634 * @nargs: the number of arguments
6635 *
6636 * Implement the not() XPath function
6637 * boolean not(boolean)
6638 * The not function returns true if its argument is false,
6639 * and false otherwise.
6640 */
6641void
6642xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6643 CHECK_ARITY(1);
6644 CAST_TO_BOOLEAN;
6645 CHECK_TYPE(XPATH_BOOLEAN);
6646 ctxt->value->boolval = ! ctxt->value->boolval;
6647}
6648
6649/**
6650 * xmlXPathTrueFunction:
6651 * @ctxt: the XPath Parser context
6652 * @nargs: the number of arguments
6653 *
6654 * Implement the true() XPath function
6655 * boolean true()
6656 */
6657void
6658xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6659 CHECK_ARITY(0);
6660 valuePush(ctxt, xmlXPathNewBoolean(1));
6661}
6662
6663/**
6664 * xmlXPathFalseFunction:
6665 * @ctxt: the XPath Parser context
6666 * @nargs: the number of arguments
6667 *
6668 * Implement the false() XPath function
6669 * boolean false()
6670 */
6671void
6672xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6673 CHECK_ARITY(0);
6674 valuePush(ctxt, xmlXPathNewBoolean(0));
6675}
6676
6677/**
6678 * xmlXPathLangFunction:
6679 * @ctxt: the XPath Parser context
6680 * @nargs: the number of arguments
6681 *
6682 * Implement the lang() XPath function
6683 * boolean lang(string)
6684 * The lang function returns true or false depending on whether the
6685 * language of the context node as specified by xml:lang attributes
6686 * is the same as or is a sublanguage of the language specified by
6687 * the argument string. The language of the context node is determined
6688 * by the value of the xml:lang attribute on the context node, or, if
6689 * the context node has no xml:lang attribute, by the value of the
6690 * xml:lang attribute on the nearest ancestor of the context node that
6691 * has an xml:lang attribute. If there is no such attribute, then lang
6692 * returns false. If there is such an attribute, then lang returns
6693 * true if the attribute value is equal to the argument ignoring case,
6694 * or if there is some suffix starting with - such that the attribute
6695 * value is equal to the argument ignoring that suffix of the attribute
6696 * value and ignoring case.
6697 */
6698void
6699xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6700 xmlXPathObjectPtr val;
6701 const xmlChar *theLang;
6702 const xmlChar *lang;
6703 int ret = 0;
6704 int i;
6705
6706 CHECK_ARITY(1);
6707 CAST_TO_STRING;
6708 CHECK_TYPE(XPATH_STRING);
6709 val = valuePop(ctxt);
6710 lang = val->stringval;
6711 theLang = xmlNodeGetLang(ctxt->context->node);
6712 if ((theLang != NULL) && (lang != NULL)) {
6713 for (i = 0;lang[i] != 0;i++)
6714 if (toupper(lang[i]) != toupper(theLang[i]))
6715 goto not_equal;
6716 ret = 1;
6717 }
6718not_equal:
6719 xmlXPathFreeObject(val);
6720 valuePush(ctxt, xmlXPathNewBoolean(ret));
6721}
6722
6723/**
6724 * xmlXPathNumberFunction:
6725 * @ctxt: the XPath Parser context
6726 * @nargs: the number of arguments
6727 *
6728 * Implement the number() XPath function
6729 * number number(object?)
6730 */
6731void
6732xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6733 xmlXPathObjectPtr cur;
6734 double res;
6735
6736 if (nargs == 0) {
6737 if (ctxt->context->node == NULL) {
6738 valuePush(ctxt, xmlXPathNewFloat(0.0));
6739 } else {
6740 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6741
6742 res = xmlXPathStringEvalNumber(content);
6743 valuePush(ctxt, xmlXPathNewFloat(res));
6744 xmlFree(content);
6745 }
6746 return;
6747 }
6748
6749 CHECK_ARITY(1);
6750 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006751 cur = xmlXPathConvertNumber(cur);
6752 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006753}
6754
6755/**
6756 * xmlXPathSumFunction:
6757 * @ctxt: the XPath Parser context
6758 * @nargs: the number of arguments
6759 *
6760 * Implement the sum() XPath function
6761 * number sum(node-set)
6762 * The sum function returns the sum of the values of the nodes in
6763 * the argument node-set.
6764 */
6765void
6766xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6767 xmlXPathObjectPtr cur;
6768 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006769 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006770
6771 CHECK_ARITY(1);
6772 if ((ctxt->value == NULL) ||
6773 ((ctxt->value->type != XPATH_NODESET) &&
6774 (ctxt->value->type != XPATH_XSLT_TREE)))
6775 XP_ERROR(XPATH_INVALID_TYPE);
6776 cur = valuePop(ctxt);
6777
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006778 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006779 valuePush(ctxt, xmlXPathNewFloat(0.0));
6780 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006781 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6782 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006783 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006784 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006785 }
6786 xmlXPathFreeObject(cur);
6787}
6788
6789/**
6790 * xmlXPathFloorFunction:
6791 * @ctxt: the XPath Parser context
6792 * @nargs: the number of arguments
6793 *
6794 * Implement the floor() XPath function
6795 * number floor(number)
6796 * The floor function returns the largest (closest to positive infinity)
6797 * number that is not greater than the argument and that is an integer.
6798 */
6799void
6800xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006801 double f;
6802
Owen Taylor3473f882001-02-23 17:55:21 +00006803 CHECK_ARITY(1);
6804 CAST_TO_NUMBER;
6805 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006806
6807 f = (double)((int) ctxt->value->floatval);
6808 if (f != ctxt->value->floatval) {
6809 if (ctxt->value->floatval > 0)
6810 ctxt->value->floatval = f;
6811 else
6812 ctxt->value->floatval = f - 1;
6813 }
Owen Taylor3473f882001-02-23 17:55:21 +00006814}
6815
6816/**
6817 * xmlXPathCeilingFunction:
6818 * @ctxt: the XPath Parser context
6819 * @nargs: the number of arguments
6820 *
6821 * Implement the ceiling() XPath function
6822 * number ceiling(number)
6823 * The ceiling function returns the smallest (closest to negative infinity)
6824 * number that is not less than the argument and that is an integer.
6825 */
6826void
6827xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6828 double f;
6829
6830 CHECK_ARITY(1);
6831 CAST_TO_NUMBER;
6832 CHECK_TYPE(XPATH_NUMBER);
6833
6834#if 0
6835 ctxt->value->floatval = ceil(ctxt->value->floatval);
6836#else
6837 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006838 if (f != ctxt->value->floatval) {
6839 if (ctxt->value->floatval > 0)
6840 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006841 else {
6842 if (ctxt->value->floatval < 0 && f == 0)
6843 ctxt->value->floatval = xmlXPathNZERO;
6844 else
6845 ctxt->value->floatval = f;
6846 }
6847
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006848 }
Owen Taylor3473f882001-02-23 17:55:21 +00006849#endif
6850}
6851
6852/**
6853 * xmlXPathRoundFunction:
6854 * @ctxt: the XPath Parser context
6855 * @nargs: the number of arguments
6856 *
6857 * Implement the round() XPath function
6858 * number round(number)
6859 * The round function returns the number that is closest to the
6860 * argument and that is an integer. If there are two such numbers,
6861 * then the one that is even is returned.
6862 */
6863void
6864xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6865 double f;
6866
6867 CHECK_ARITY(1);
6868 CAST_TO_NUMBER;
6869 CHECK_TYPE(XPATH_NUMBER);
6870
Daniel Veillardcda96922001-08-21 10:56:31 +00006871 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6872 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6873 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006874 (ctxt->value->floatval == 0.0))
6875 return;
6876
Owen Taylor3473f882001-02-23 17:55:21 +00006877 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006878 if (ctxt->value->floatval < 0) {
6879 if (ctxt->value->floatval < f - 0.5)
6880 ctxt->value->floatval = f - 1;
6881 else
6882 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006883 if (ctxt->value->floatval == 0)
6884 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006885 } else {
6886 if (ctxt->value->floatval < f + 0.5)
6887 ctxt->value->floatval = f;
6888 else
6889 ctxt->value->floatval = f + 1;
6890 }
Owen Taylor3473f882001-02-23 17:55:21 +00006891}
6892
6893/************************************************************************
6894 * *
6895 * The Parser *
6896 * *
6897 ************************************************************************/
6898
6899/*
6900 * a couple of forward declarations since we use a recursive call based
6901 * implementation.
6902 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006903static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006904static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006905static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006906#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006907static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6908#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006909#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006910static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006911#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006912static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6913 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006914
6915/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006916 * xmlXPathCurrentChar:
6917 * @ctxt: the XPath parser context
6918 * @cur: pointer to the beginning of the char
6919 * @len: pointer to the length of the char read
6920 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006921 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006922 * bytes in the input buffer.
6923 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006924 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006925 */
6926
6927static int
6928xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6929 unsigned char c;
6930 unsigned int val;
6931 const xmlChar *cur;
6932
6933 if (ctxt == NULL)
6934 return(0);
6935 cur = ctxt->cur;
6936
6937 /*
6938 * We are supposed to handle UTF8, check it's valid
6939 * From rfc2044: encoding of the Unicode values on UTF-8:
6940 *
6941 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6942 * 0000 0000-0000 007F 0xxxxxxx
6943 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6944 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6945 *
6946 * Check for the 0x110000 limit too
6947 */
6948 c = *cur;
6949 if (c & 0x80) {
6950 if ((cur[1] & 0xc0) != 0x80)
6951 goto encoding_error;
6952 if ((c & 0xe0) == 0xe0) {
6953
6954 if ((cur[2] & 0xc0) != 0x80)
6955 goto encoding_error;
6956 if ((c & 0xf0) == 0xf0) {
6957 if (((c & 0xf8) != 0xf0) ||
6958 ((cur[3] & 0xc0) != 0x80))
6959 goto encoding_error;
6960 /* 4-byte code */
6961 *len = 4;
6962 val = (cur[0] & 0x7) << 18;
6963 val |= (cur[1] & 0x3f) << 12;
6964 val |= (cur[2] & 0x3f) << 6;
6965 val |= cur[3] & 0x3f;
6966 } else {
6967 /* 3-byte code */
6968 *len = 3;
6969 val = (cur[0] & 0xf) << 12;
6970 val |= (cur[1] & 0x3f) << 6;
6971 val |= cur[2] & 0x3f;
6972 }
6973 } else {
6974 /* 2-byte code */
6975 *len = 2;
6976 val = (cur[0] & 0x1f) << 6;
6977 val |= cur[1] & 0x3f;
6978 }
6979 if (!IS_CHAR(val)) {
6980 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6981 }
6982 return(val);
6983 } else {
6984 /* 1-byte code */
6985 *len = 1;
6986 return((int) *cur);
6987 }
6988encoding_error:
6989 /*
6990 * If we detect an UTF8 error that probably mean that the
6991 * input encoding didn't get properly advertized in the
6992 * declaration header. Report the error and switch the encoding
6993 * to ISO-Latin-1 (if you don't like this policy, just declare the
6994 * encoding !)
6995 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006996 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006997 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006998}
6999
7000/**
Owen Taylor3473f882001-02-23 17:55:21 +00007001 * xmlXPathParseNCName:
7002 * @ctxt: the XPath Parser context
7003 *
7004 * parse an XML namespace non qualified name.
7005 *
7006 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7007 *
7008 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7009 * CombiningChar | Extender
7010 *
7011 * Returns the namespace name or NULL
7012 */
7013
7014xmlChar *
7015xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007016 const xmlChar *in;
7017 xmlChar *ret;
7018 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007019
Daniel Veillard2156a562001-04-28 12:24:34 +00007020 /*
7021 * Accelerator for simple ASCII names
7022 */
7023 in = ctxt->cur;
7024 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7025 ((*in >= 0x41) && (*in <= 0x5A)) ||
7026 (*in == '_')) {
7027 in++;
7028 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7029 ((*in >= 0x41) && (*in <= 0x5A)) ||
7030 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007031 (*in == '_') || (*in == '.') ||
7032 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007033 in++;
7034 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7035 (*in == '[') || (*in == ']') || (*in == ':') ||
7036 (*in == '@') || (*in == '*')) {
7037 count = in - ctxt->cur;
7038 if (count == 0)
7039 return(NULL);
7040 ret = xmlStrndup(ctxt->cur, count);
7041 ctxt->cur = in;
7042 return(ret);
7043 }
7044 }
7045 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007046}
7047
Daniel Veillard2156a562001-04-28 12:24:34 +00007048
Owen Taylor3473f882001-02-23 17:55:21 +00007049/**
7050 * xmlXPathParseQName:
7051 * @ctxt: the XPath Parser context
7052 * @prefix: a xmlChar **
7053 *
7054 * parse an XML qualified name
7055 *
7056 * [NS 5] QName ::= (Prefix ':')? LocalPart
7057 *
7058 * [NS 6] Prefix ::= NCName
7059 *
7060 * [NS 7] LocalPart ::= NCName
7061 *
7062 * Returns the function returns the local part, and prefix is updated
7063 * to get the Prefix if any.
7064 */
7065
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007066static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007067xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7068 xmlChar *ret = NULL;
7069
7070 *prefix = NULL;
7071 ret = xmlXPathParseNCName(ctxt);
7072 if (CUR == ':') {
7073 *prefix = ret;
7074 NEXT;
7075 ret = xmlXPathParseNCName(ctxt);
7076 }
7077 return(ret);
7078}
7079
7080/**
7081 * xmlXPathParseName:
7082 * @ctxt: the XPath Parser context
7083 *
7084 * parse an XML name
7085 *
7086 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7087 * CombiningChar | Extender
7088 *
7089 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7090 *
7091 * Returns the namespace name or NULL
7092 */
7093
7094xmlChar *
7095xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007096 const xmlChar *in;
7097 xmlChar *ret;
7098 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007099
Daniel Veillard61d80a22001-04-27 17:13:01 +00007100 /*
7101 * Accelerator for simple ASCII names
7102 */
7103 in = ctxt->cur;
7104 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7105 ((*in >= 0x41) && (*in <= 0x5A)) ||
7106 (*in == '_') || (*in == ':')) {
7107 in++;
7108 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7109 ((*in >= 0x41) && (*in <= 0x5A)) ||
7110 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007111 (*in == '_') || (*in == '-') ||
7112 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007113 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007114 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007115 count = in - ctxt->cur;
7116 ret = xmlStrndup(ctxt->cur, count);
7117 ctxt->cur = in;
7118 return(ret);
7119 }
7120 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007121 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007122}
7123
Daniel Veillard61d80a22001-04-27 17:13:01 +00007124static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007125xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007126 xmlChar buf[XML_MAX_NAMELEN + 5];
7127 int len = 0, l;
7128 int c;
7129
7130 /*
7131 * Handler for more complex cases
7132 */
7133 c = CUR_CHAR(l);
7134 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007135 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7136 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007137 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007138 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007139 return(NULL);
7140 }
7141
7142 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7143 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7144 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007145 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007146 (IS_COMBINING(c)) ||
7147 (IS_EXTENDER(c)))) {
7148 COPY_BUF(l,buf,len,c);
7149 NEXTL(l);
7150 c = CUR_CHAR(l);
7151 if (len >= XML_MAX_NAMELEN) {
7152 /*
7153 * Okay someone managed to make a huge name, so he's ready to pay
7154 * for the processing speed.
7155 */
7156 xmlChar *buffer;
7157 int max = len * 2;
7158
7159 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7160 if (buffer == NULL) {
7161 XP_ERROR0(XPATH_MEMORY_ERROR);
7162 }
7163 memcpy(buffer, buf, len);
7164 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7165 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007166 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007167 (IS_COMBINING(c)) ||
7168 (IS_EXTENDER(c))) {
7169 if (len + 10 > max) {
7170 max *= 2;
7171 buffer = (xmlChar *) xmlRealloc(buffer,
7172 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007173 if (buffer == NULL) {
7174 XP_ERROR0(XPATH_MEMORY_ERROR);
7175 }
7176 }
7177 COPY_BUF(l,buffer,len,c);
7178 NEXTL(l);
7179 c = CUR_CHAR(l);
7180 }
7181 buffer[len] = 0;
7182 return(buffer);
7183 }
7184 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007185 if (len == 0)
7186 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007187 return(xmlStrndup(buf, len));
7188}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007189
7190#define MAX_FRAC 20
7191
7192static double my_pow10[MAX_FRAC] = {
7193 1.0, 10.0, 100.0, 1000.0, 10000.0,
7194 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7195 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7196 100000000000000.0,
7197 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7198 1000000000000000000.0, 10000000000000000000.0
7199};
7200
Owen Taylor3473f882001-02-23 17:55:21 +00007201/**
7202 * xmlXPathStringEvalNumber:
7203 * @str: A string to scan
7204 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007205 * [30a] Float ::= Number ('e' Digits?)?
7206 *
Owen Taylor3473f882001-02-23 17:55:21 +00007207 * [30] Number ::= Digits ('.' Digits?)?
7208 * | '.' Digits
7209 * [31] Digits ::= [0-9]+
7210 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007211 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007212 * In complement of the Number expression, this function also handles
7213 * negative values : '-' Number.
7214 *
7215 * Returns the double value.
7216 */
7217double
7218xmlXPathStringEvalNumber(const xmlChar *str) {
7219 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007220 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007221 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007222 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007223 int exponent = 0;
7224 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007225#ifdef __GNUC__
7226 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007227 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007228#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007229 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007230 while (IS_BLANK(*cur)) cur++;
7231 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7232 return(xmlXPathNAN);
7233 }
7234 if (*cur == '-') {
7235 isneg = 1;
7236 cur++;
7237 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007238
7239#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007240 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007241 * tmp/temp is a workaround against a gcc compiler bug
7242 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007243 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007244 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007245 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007246 ret = ret * 10;
7247 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007248 ok = 1;
7249 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007250 temp = (double) tmp;
7251 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007252 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007253#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007254 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007255 while ((*cur >= '0') && (*cur <= '9')) {
7256 ret = ret * 10 + (*cur - '0');
7257 ok = 1;
7258 cur++;
7259 }
7260#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007261
Owen Taylor3473f882001-02-23 17:55:21 +00007262 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007263 int v, frac = 0;
7264 double fraction = 0;
7265
Owen Taylor3473f882001-02-23 17:55:21 +00007266 cur++;
7267 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7268 return(xmlXPathNAN);
7269 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007270 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7271 v = (*cur - '0');
7272 fraction = fraction * 10 + v;
7273 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007274 cur++;
7275 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007276 fraction /= my_pow10[frac];
7277 ret = ret + fraction;
7278 while ((*cur >= '0') && (*cur <= '9'))
7279 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007280 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007281 if ((*cur == 'e') || (*cur == 'E')) {
7282 cur++;
7283 if (*cur == '-') {
7284 is_exponent_negative = 1;
7285 cur++;
7286 }
7287 while ((*cur >= '0') && (*cur <= '9')) {
7288 exponent = exponent * 10 + (*cur - '0');
7289 cur++;
7290 }
7291 }
Owen Taylor3473f882001-02-23 17:55:21 +00007292 while (IS_BLANK(*cur)) cur++;
7293 if (*cur != 0) return(xmlXPathNAN);
7294 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007295 if (is_exponent_negative) exponent = -exponent;
7296 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007297 return(ret);
7298}
7299
7300/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007301 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007302 * @ctxt: the XPath Parser context
7303 *
7304 * [30] Number ::= Digits ('.' Digits?)?
7305 * | '.' Digits
7306 * [31] Digits ::= [0-9]+
7307 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007308 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007309 *
7310 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007311static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007312xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7313{
Owen Taylor3473f882001-02-23 17:55:21 +00007314 double ret = 0.0;
7315 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007316 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007317 int exponent = 0;
7318 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007319#ifdef __GNUC__
7320 unsigned long tmp = 0;
7321 double temp;
7322#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007323
7324 CHECK_ERROR;
7325 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7326 XP_ERROR(XPATH_NUMBER_ERROR);
7327 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007328#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007329 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007330 * tmp/temp is a workaround against a gcc compiler bug
7331 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007332 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007333 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007334 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007335 ret = ret * 10;
7336 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007337 ok = 1;
7338 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007339 temp = (double) tmp;
7340 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007341 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007342#else
7343 ret = 0;
7344 while ((CUR >= '0') && (CUR <= '9')) {
7345 ret = ret * 10 + (CUR - '0');
7346 ok = 1;
7347 NEXT;
7348 }
7349#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007350 if (CUR == '.') {
7351 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007352 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7353 XP_ERROR(XPATH_NUMBER_ERROR);
7354 }
7355 while ((CUR >= '0') && (CUR <= '9')) {
7356 mult /= 10;
7357 ret = ret + (CUR - '0') * mult;
7358 NEXT;
7359 }
Owen Taylor3473f882001-02-23 17:55:21 +00007360 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007361 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007362 NEXT;
7363 if (CUR == '-') {
7364 is_exponent_negative = 1;
7365 NEXT;
7366 }
7367 while ((CUR >= '0') && (CUR <= '9')) {
7368 exponent = exponent * 10 + (CUR - '0');
7369 NEXT;
7370 }
7371 if (is_exponent_negative)
7372 exponent = -exponent;
7373 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007374 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007375 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007376 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007377}
7378
7379/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007380 * xmlXPathParseLiteral:
7381 * @ctxt: the XPath Parser context
7382 *
7383 * Parse a Literal
7384 *
7385 * [29] Literal ::= '"' [^"]* '"'
7386 * | "'" [^']* "'"
7387 *
7388 * Returns the value found or NULL in case of error
7389 */
7390static xmlChar *
7391xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7392 const xmlChar *q;
7393 xmlChar *ret = NULL;
7394
7395 if (CUR == '"') {
7396 NEXT;
7397 q = CUR_PTR;
7398 while ((IS_CHAR(CUR)) && (CUR != '"'))
7399 NEXT;
7400 if (!IS_CHAR(CUR)) {
7401 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7402 } else {
7403 ret = xmlStrndup(q, CUR_PTR - q);
7404 NEXT;
7405 }
7406 } else if (CUR == '\'') {
7407 NEXT;
7408 q = CUR_PTR;
7409 while ((IS_CHAR(CUR)) && (CUR != '\''))
7410 NEXT;
7411 if (!IS_CHAR(CUR)) {
7412 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7413 } else {
7414 ret = xmlStrndup(q, CUR_PTR - q);
7415 NEXT;
7416 }
7417 } else {
7418 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7419 }
7420 return(ret);
7421}
7422
7423/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007424 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007425 * @ctxt: the XPath Parser context
7426 *
7427 * Parse a Literal and push it on the stack.
7428 *
7429 * [29] Literal ::= '"' [^"]* '"'
7430 * | "'" [^']* "'"
7431 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007432 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007433 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007434static void
7435xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007436 const xmlChar *q;
7437 xmlChar *ret = NULL;
7438
7439 if (CUR == '"') {
7440 NEXT;
7441 q = CUR_PTR;
7442 while ((IS_CHAR(CUR)) && (CUR != '"'))
7443 NEXT;
7444 if (!IS_CHAR(CUR)) {
7445 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7446 } else {
7447 ret = xmlStrndup(q, CUR_PTR - q);
7448 NEXT;
7449 }
7450 } else if (CUR == '\'') {
7451 NEXT;
7452 q = CUR_PTR;
7453 while ((IS_CHAR(CUR)) && (CUR != '\''))
7454 NEXT;
7455 if (!IS_CHAR(CUR)) {
7456 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7457 } else {
7458 ret = xmlStrndup(q, CUR_PTR - q);
7459 NEXT;
7460 }
7461 } else {
7462 XP_ERROR(XPATH_START_LITERAL_ERROR);
7463 }
7464 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007465 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7466 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007467 xmlFree(ret);
7468}
7469
7470/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007471 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007472 * @ctxt: the XPath Parser context
7473 *
7474 * Parse a VariableReference, evaluate it and push it on the stack.
7475 *
7476 * The variable bindings consist of a mapping from variable names
7477 * to variable values. The value of a variable is an object, which
7478 * of any of the types that are possible for the value of an expression,
7479 * and may also be of additional types not specified here.
7480 *
7481 * Early evaluation is possible since:
7482 * The variable bindings [...] used to evaluate a subexpression are
7483 * always the same as those used to evaluate the containing expression.
7484 *
7485 * [36] VariableReference ::= '$' QName
7486 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007487static void
7488xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007489 xmlChar *name;
7490 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007491
7492 SKIP_BLANKS;
7493 if (CUR != '$') {
7494 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7495 }
7496 NEXT;
7497 name = xmlXPathParseQName(ctxt, &prefix);
7498 if (name == NULL) {
7499 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7500 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007501 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007502 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7503 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007504 SKIP_BLANKS;
7505}
7506
7507/**
7508 * xmlXPathIsNodeType:
7509 * @ctxt: the XPath Parser context
7510 * @name: a name string
7511 *
7512 * Is the name given a NodeType one.
7513 *
7514 * [38] NodeType ::= 'comment'
7515 * | 'text'
7516 * | 'processing-instruction'
7517 * | 'node'
7518 *
7519 * Returns 1 if true 0 otherwise
7520 */
7521int
7522xmlXPathIsNodeType(const xmlChar *name) {
7523 if (name == NULL)
7524 return(0);
7525
Daniel Veillard1971ee22002-01-31 20:29:19 +00007526 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007527 return(1);
7528 if (xmlStrEqual(name, BAD_CAST "text"))
7529 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007530 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007531 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007532 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007533 return(1);
7534 return(0);
7535}
7536
7537/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007538 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007539 * @ctxt: the XPath Parser context
7540 *
7541 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7542 * [17] Argument ::= Expr
7543 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007544 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007545 * pushed on the stack
7546 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007547static void
7548xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007549 xmlChar *name;
7550 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007551 int nbargs = 0;
7552
7553 name = xmlXPathParseQName(ctxt, &prefix);
7554 if (name == NULL) {
7555 XP_ERROR(XPATH_EXPR_ERROR);
7556 }
7557 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007558#ifdef DEBUG_EXPR
7559 if (prefix == NULL)
7560 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7561 name);
7562 else
7563 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7564 prefix, name);
7565#endif
7566
Owen Taylor3473f882001-02-23 17:55:21 +00007567 if (CUR != '(') {
7568 XP_ERROR(XPATH_EXPR_ERROR);
7569 }
7570 NEXT;
7571 SKIP_BLANKS;
7572
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007573 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007574 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007575 int op1 = ctxt->comp->last;
7576 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007577 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007578 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007579 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007580 nbargs++;
7581 if (CUR == ')') break;
7582 if (CUR != ',') {
7583 XP_ERROR(XPATH_EXPR_ERROR);
7584 }
7585 NEXT;
7586 SKIP_BLANKS;
7587 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007588 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7589 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007590 NEXT;
7591 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007592}
7593
7594/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007595 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007596 * @ctxt: the XPath Parser context
7597 *
7598 * [15] PrimaryExpr ::= VariableReference
7599 * | '(' Expr ')'
7600 * | Literal
7601 * | Number
7602 * | FunctionCall
7603 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007604 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007605 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007606static void
7607xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007608 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007609 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007610 else if (CUR == '(') {
7611 NEXT;
7612 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007613 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007614 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007615 if (CUR != ')') {
7616 XP_ERROR(XPATH_EXPR_ERROR);
7617 }
7618 NEXT;
7619 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007620 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007621 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007622 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007623 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007624 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007625 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007626 }
7627 SKIP_BLANKS;
7628}
7629
7630/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007631 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007632 * @ctxt: the XPath Parser context
7633 *
7634 * [20] FilterExpr ::= PrimaryExpr
7635 * | FilterExpr Predicate
7636 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007637 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007638 * Square brackets are used to filter expressions in the same way that
7639 * they are used in location paths. It is an error if the expression to
7640 * be filtered does not evaluate to a node-set. The context node list
7641 * used for evaluating the expression in square brackets is the node-set
7642 * to be filtered listed in document order.
7643 */
7644
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007645static void
7646xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7647 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007648 CHECK_ERROR;
7649 SKIP_BLANKS;
7650
7651 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007652 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007653 SKIP_BLANKS;
7654 }
7655
7656
7657}
7658
7659/**
7660 * xmlXPathScanName:
7661 * @ctxt: the XPath Parser context
7662 *
7663 * Trickery: parse an XML name but without consuming the input flow
7664 * Needed to avoid insanity in the parser state.
7665 *
7666 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7667 * CombiningChar | Extender
7668 *
7669 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7670 *
7671 * [6] Names ::= Name (S Name)*
7672 *
7673 * Returns the Name parsed or NULL
7674 */
7675
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007676static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007677xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7678 xmlChar buf[XML_MAX_NAMELEN];
7679 int len = 0;
7680
7681 SKIP_BLANKS;
7682 if (!IS_LETTER(CUR) && (CUR != '_') &&
7683 (CUR != ':')) {
7684 return(NULL);
7685 }
7686
7687 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7688 (NXT(len) == '.') || (NXT(len) == '-') ||
7689 (NXT(len) == '_') || (NXT(len) == ':') ||
7690 (IS_COMBINING(NXT(len))) ||
7691 (IS_EXTENDER(NXT(len)))) {
7692 buf[len] = NXT(len);
7693 len++;
7694 if (len >= XML_MAX_NAMELEN) {
7695 xmlGenericError(xmlGenericErrorContext,
7696 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7697 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7698 (NXT(len) == '.') || (NXT(len) == '-') ||
7699 (NXT(len) == '_') || (NXT(len) == ':') ||
7700 (IS_COMBINING(NXT(len))) ||
7701 (IS_EXTENDER(NXT(len))))
7702 len++;
7703 break;
7704 }
7705 }
7706 return(xmlStrndup(buf, len));
7707}
7708
7709/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007710 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007711 * @ctxt: the XPath Parser context
7712 *
7713 * [19] PathExpr ::= LocationPath
7714 * | FilterExpr
7715 * | FilterExpr '/' RelativeLocationPath
7716 * | FilterExpr '//' RelativeLocationPath
7717 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007718 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007719 * The / operator and // operators combine an arbitrary expression
7720 * and a relative location path. It is an error if the expression
7721 * does not evaluate to a node-set.
7722 * The / operator does composition in the same way as when / is
7723 * used in a location path. As in location paths, // is short for
7724 * /descendant-or-self::node()/.
7725 */
7726
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007727static void
7728xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007729 int lc = 1; /* Should we branch to LocationPath ? */
7730 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7731
7732 SKIP_BLANKS;
7733 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007734 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007735 lc = 0;
7736 } else if (CUR == '*') {
7737 /* relative or absolute location path */
7738 lc = 1;
7739 } else if (CUR == '/') {
7740 /* relative or absolute location path */
7741 lc = 1;
7742 } else if (CUR == '@') {
7743 /* relative abbreviated attribute location path */
7744 lc = 1;
7745 } else if (CUR == '.') {
7746 /* relative abbreviated attribute location path */
7747 lc = 1;
7748 } else {
7749 /*
7750 * Problem is finding if we have a name here whether it's:
7751 * - a nodetype
7752 * - a function call in which case it's followed by '('
7753 * - an axis in which case it's followed by ':'
7754 * - a element name
7755 * We do an a priori analysis here rather than having to
7756 * maintain parsed token content through the recursive function
7757 * calls. This looks uglier but makes the code quite easier to
7758 * read/write/debug.
7759 */
7760 SKIP_BLANKS;
7761 name = xmlXPathScanName(ctxt);
7762 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7763#ifdef DEBUG_STEP
7764 xmlGenericError(xmlGenericErrorContext,
7765 "PathExpr: Axis\n");
7766#endif
7767 lc = 1;
7768 xmlFree(name);
7769 } else if (name != NULL) {
7770 int len =xmlStrlen(name);
7771 int blank = 0;
7772
7773
7774 while (NXT(len) != 0) {
7775 if (NXT(len) == '/') {
7776 /* element name */
7777#ifdef DEBUG_STEP
7778 xmlGenericError(xmlGenericErrorContext,
7779 "PathExpr: AbbrRelLocation\n");
7780#endif
7781 lc = 1;
7782 break;
7783 } else if (IS_BLANK(NXT(len))) {
7784 /* skip to next */
7785 blank = 1;
7786 } else if (NXT(len) == ':') {
7787#ifdef DEBUG_STEP
7788 xmlGenericError(xmlGenericErrorContext,
7789 "PathExpr: AbbrRelLocation\n");
7790#endif
7791 lc = 1;
7792 break;
7793 } else if ((NXT(len) == '(')) {
7794 /* Note Type or Function */
7795 if (xmlXPathIsNodeType(name)) {
7796#ifdef DEBUG_STEP
7797 xmlGenericError(xmlGenericErrorContext,
7798 "PathExpr: Type search\n");
7799#endif
7800 lc = 1;
7801 } else {
7802#ifdef DEBUG_STEP
7803 xmlGenericError(xmlGenericErrorContext,
7804 "PathExpr: function call\n");
7805#endif
7806 lc = 0;
7807 }
7808 break;
7809 } else if ((NXT(len) == '[')) {
7810 /* element name */
7811#ifdef DEBUG_STEP
7812 xmlGenericError(xmlGenericErrorContext,
7813 "PathExpr: AbbrRelLocation\n");
7814#endif
7815 lc = 1;
7816 break;
7817 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7818 (NXT(len) == '=')) {
7819 lc = 1;
7820 break;
7821 } else {
7822 lc = 1;
7823 break;
7824 }
7825 len++;
7826 }
7827 if (NXT(len) == 0) {
7828#ifdef DEBUG_STEP
7829 xmlGenericError(xmlGenericErrorContext,
7830 "PathExpr: AbbrRelLocation\n");
7831#endif
7832 /* element name */
7833 lc = 1;
7834 }
7835 xmlFree(name);
7836 } else {
7837 /* make sure all cases are covered explicitely */
7838 XP_ERROR(XPATH_EXPR_ERROR);
7839 }
7840 }
7841
7842 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007843 if (CUR == '/') {
7844 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7845 } else {
7846 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007847 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007848 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007849 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007850 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007851 CHECK_ERROR;
7852 if ((CUR == '/') && (NXT(1) == '/')) {
7853 SKIP(2);
7854 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007855
7856 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7857 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7858 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7859
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007860 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007861 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007862 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007863 }
7864 }
7865 SKIP_BLANKS;
7866}
7867
7868/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007869 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007870 * @ctxt: the XPath Parser context
7871 *
7872 * [18] UnionExpr ::= PathExpr
7873 * | UnionExpr '|' PathExpr
7874 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007875 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007876 */
7877
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007878static void
7879xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7880 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007881 CHECK_ERROR;
7882 SKIP_BLANKS;
7883 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007884 int op1 = ctxt->comp->last;
7885 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007886
7887 NEXT;
7888 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007889 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007890
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007891 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7892
Owen Taylor3473f882001-02-23 17:55:21 +00007893 SKIP_BLANKS;
7894 }
Owen Taylor3473f882001-02-23 17:55:21 +00007895}
7896
7897/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007898 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007899 * @ctxt: the XPath Parser context
7900 *
7901 * [27] UnaryExpr ::= UnionExpr
7902 * | '-' UnaryExpr
7903 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007904 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007905 */
7906
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007907static void
7908xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007909 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007910 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007911
7912 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007913 while (CUR == '-') {
7914 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007915 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007916 NEXT;
7917 SKIP_BLANKS;
7918 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007919
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007920 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007921 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007922 if (found) {
7923 if (minus)
7924 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7925 else
7926 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007927 }
7928}
7929
7930/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007931 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007932 * @ctxt: the XPath Parser context
7933 *
7934 * [26] MultiplicativeExpr ::= UnaryExpr
7935 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7936 * | MultiplicativeExpr 'div' UnaryExpr
7937 * | MultiplicativeExpr 'mod' UnaryExpr
7938 * [34] MultiplyOperator ::= '*'
7939 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007940 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007941 */
7942
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007943static void
7944xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7945 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007946 CHECK_ERROR;
7947 SKIP_BLANKS;
7948 while ((CUR == '*') ||
7949 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7950 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7951 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007952 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007953
7954 if (CUR == '*') {
7955 op = 0;
7956 NEXT;
7957 } else if (CUR == 'd') {
7958 op = 1;
7959 SKIP(3);
7960 } else if (CUR == 'm') {
7961 op = 2;
7962 SKIP(3);
7963 }
7964 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007965 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007966 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007967 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007968 SKIP_BLANKS;
7969 }
7970}
7971
7972/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007973 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007974 * @ctxt: the XPath Parser context
7975 *
7976 * [25] AdditiveExpr ::= MultiplicativeExpr
7977 * | AdditiveExpr '+' MultiplicativeExpr
7978 * | AdditiveExpr '-' MultiplicativeExpr
7979 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007980 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007981 */
7982
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007983static void
7984xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007985
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007986 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007987 CHECK_ERROR;
7988 SKIP_BLANKS;
7989 while ((CUR == '+') || (CUR == '-')) {
7990 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007991 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007992
7993 if (CUR == '+') plus = 1;
7994 else plus = 0;
7995 NEXT;
7996 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007997 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007998 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007999 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008000 SKIP_BLANKS;
8001 }
8002}
8003
8004/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008005 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008006 * @ctxt: the XPath Parser context
8007 *
8008 * [24] RelationalExpr ::= AdditiveExpr
8009 * | RelationalExpr '<' AdditiveExpr
8010 * | RelationalExpr '>' AdditiveExpr
8011 * | RelationalExpr '<=' AdditiveExpr
8012 * | RelationalExpr '>=' AdditiveExpr
8013 *
8014 * A <= B > C is allowed ? Answer from James, yes with
8015 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8016 * which is basically what got implemented.
8017 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008018 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008019 * on the stack
8020 */
8021
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008022static void
8023xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8024 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008025 CHECK_ERROR;
8026 SKIP_BLANKS;
8027 while ((CUR == '<') ||
8028 (CUR == '>') ||
8029 ((CUR == '<') && (NXT(1) == '=')) ||
8030 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008031 int inf, strict;
8032 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008033
8034 if (CUR == '<') inf = 1;
8035 else inf = 0;
8036 if (NXT(1) == '=') strict = 0;
8037 else strict = 1;
8038 NEXT;
8039 if (!strict) NEXT;
8040 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008041 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008042 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008043 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008044 SKIP_BLANKS;
8045 }
8046}
8047
8048/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008049 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008050 * @ctxt: the XPath Parser context
8051 *
8052 * [23] EqualityExpr ::= RelationalExpr
8053 * | EqualityExpr '=' RelationalExpr
8054 * | EqualityExpr '!=' RelationalExpr
8055 *
8056 * A != B != C is allowed ? Answer from James, yes with
8057 * (RelationalExpr = RelationalExpr) = RelationalExpr
8058 * (RelationalExpr != RelationalExpr) != RelationalExpr
8059 * which is basically what got implemented.
8060 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008061 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008062 *
8063 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008064static void
8065xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8066 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008067 CHECK_ERROR;
8068 SKIP_BLANKS;
8069 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008070 int eq;
8071 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008072
8073 if (CUR == '=') eq = 1;
8074 else eq = 0;
8075 NEXT;
8076 if (!eq) NEXT;
8077 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008078 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008079 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008080 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008081 SKIP_BLANKS;
8082 }
8083}
8084
8085/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008086 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008087 * @ctxt: the XPath Parser context
8088 *
8089 * [22] AndExpr ::= EqualityExpr
8090 * | AndExpr 'and' EqualityExpr
8091 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008092 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008093 *
8094 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008095static void
8096xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8097 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008098 CHECK_ERROR;
8099 SKIP_BLANKS;
8100 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008101 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008102 SKIP(3);
8103 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008104 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008105 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008106 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008107 SKIP_BLANKS;
8108 }
8109}
8110
8111/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008112 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008113 * @ctxt: the XPath Parser context
8114 *
8115 * [14] Expr ::= OrExpr
8116 * [21] OrExpr ::= AndExpr
8117 * | OrExpr 'or' AndExpr
8118 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008119 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008120 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008121static void
8122xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8123 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008124 CHECK_ERROR;
8125 SKIP_BLANKS;
8126 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008127 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008128 SKIP(2);
8129 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008130 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008131 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008132 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8133 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008134 SKIP_BLANKS;
8135 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008136 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8137 /* more ops could be optimized too */
8138 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8139 }
Owen Taylor3473f882001-02-23 17:55:21 +00008140}
8141
8142/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008143 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008144 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008145 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008146 *
8147 * [8] Predicate ::= '[' PredicateExpr ']'
8148 * [9] PredicateExpr ::= Expr
8149 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008150 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008151 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008152static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008153xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008154 int op1 = ctxt->comp->last;
8155
8156 SKIP_BLANKS;
8157 if (CUR != '[') {
8158 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8159 }
8160 NEXT;
8161 SKIP_BLANKS;
8162
8163 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008164 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008165 CHECK_ERROR;
8166
8167 if (CUR != ']') {
8168 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8169 }
8170
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008171 if (filter)
8172 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8173 else
8174 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008175
8176 NEXT;
8177 SKIP_BLANKS;
8178}
8179
8180/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008181 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008182 * @ctxt: the XPath Parser context
8183 * @test: pointer to a xmlXPathTestVal
8184 * @type: pointer to a xmlXPathTypeVal
8185 * @prefix: placeholder for a possible name prefix
8186 *
8187 * [7] NodeTest ::= NameTest
8188 * | NodeType '(' ')'
8189 * | 'processing-instruction' '(' Literal ')'
8190 *
8191 * [37] NameTest ::= '*'
8192 * | NCName ':' '*'
8193 * | QName
8194 * [38] NodeType ::= 'comment'
8195 * | 'text'
8196 * | 'processing-instruction'
8197 * | 'node'
8198 *
8199 * Returns the name found and update @test, @type and @prefix appropriately
8200 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008201static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008202xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8203 xmlXPathTypeVal *type, const xmlChar **prefix,
8204 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008205 int blanks;
8206
8207 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8208 STRANGE;
8209 return(NULL);
8210 }
8211 *type = 0;
8212 *test = 0;
8213 *prefix = NULL;
8214 SKIP_BLANKS;
8215
8216 if ((name == NULL) && (CUR == '*')) {
8217 /*
8218 * All elements
8219 */
8220 NEXT;
8221 *test = NODE_TEST_ALL;
8222 return(NULL);
8223 }
8224
8225 if (name == NULL)
8226 name = xmlXPathParseNCName(ctxt);
8227 if (name == NULL) {
8228 XP_ERROR0(XPATH_EXPR_ERROR);
8229 }
8230
8231 blanks = IS_BLANK(CUR);
8232 SKIP_BLANKS;
8233 if (CUR == '(') {
8234 NEXT;
8235 /*
8236 * NodeType or PI search
8237 */
8238 if (xmlStrEqual(name, BAD_CAST "comment"))
8239 *type = NODE_TYPE_COMMENT;
8240 else if (xmlStrEqual(name, BAD_CAST "node"))
8241 *type = NODE_TYPE_NODE;
8242 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8243 *type = NODE_TYPE_PI;
8244 else if (xmlStrEqual(name, BAD_CAST "text"))
8245 *type = NODE_TYPE_TEXT;
8246 else {
8247 if (name != NULL)
8248 xmlFree(name);
8249 XP_ERROR0(XPATH_EXPR_ERROR);
8250 }
8251
8252 *test = NODE_TEST_TYPE;
8253
8254 SKIP_BLANKS;
8255 if (*type == NODE_TYPE_PI) {
8256 /*
8257 * Specific case: search a PI by name.
8258 */
Owen Taylor3473f882001-02-23 17:55:21 +00008259 if (name != NULL)
8260 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008261 name = NULL;
8262 if (CUR != ')') {
8263 name = xmlXPathParseLiteral(ctxt);
8264 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008265 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008266 SKIP_BLANKS;
8267 }
Owen Taylor3473f882001-02-23 17:55:21 +00008268 }
8269 if (CUR != ')') {
8270 if (name != NULL)
8271 xmlFree(name);
8272 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8273 }
8274 NEXT;
8275 return(name);
8276 }
8277 *test = NODE_TEST_NAME;
8278 if ((!blanks) && (CUR == ':')) {
8279 NEXT;
8280
8281 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008282 * Since currently the parser context don't have a
8283 * namespace list associated:
8284 * The namespace name for this prefix can be computed
8285 * only at evaluation time. The compilation is done
8286 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008287 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008288#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008289 *prefix = xmlXPathNsLookup(ctxt->context, name);
8290 if (name != NULL)
8291 xmlFree(name);
8292 if (*prefix == NULL) {
8293 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8294 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008295#else
8296 *prefix = name;
8297#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008298
8299 if (CUR == '*') {
8300 /*
8301 * All elements
8302 */
8303 NEXT;
8304 *test = NODE_TEST_ALL;
8305 return(NULL);
8306 }
8307
8308 name = xmlXPathParseNCName(ctxt);
8309 if (name == NULL) {
8310 XP_ERROR0(XPATH_EXPR_ERROR);
8311 }
8312 }
8313 return(name);
8314}
8315
8316/**
8317 * xmlXPathIsAxisName:
8318 * @name: a preparsed name token
8319 *
8320 * [6] AxisName ::= 'ancestor'
8321 * | 'ancestor-or-self'
8322 * | 'attribute'
8323 * | 'child'
8324 * | 'descendant'
8325 * | 'descendant-or-self'
8326 * | 'following'
8327 * | 'following-sibling'
8328 * | 'namespace'
8329 * | 'parent'
8330 * | 'preceding'
8331 * | 'preceding-sibling'
8332 * | 'self'
8333 *
8334 * Returns the axis or 0
8335 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008336static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008337xmlXPathIsAxisName(const xmlChar *name) {
8338 xmlXPathAxisVal ret = 0;
8339 switch (name[0]) {
8340 case 'a':
8341 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8342 ret = AXIS_ANCESTOR;
8343 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8344 ret = AXIS_ANCESTOR_OR_SELF;
8345 if (xmlStrEqual(name, BAD_CAST "attribute"))
8346 ret = AXIS_ATTRIBUTE;
8347 break;
8348 case 'c':
8349 if (xmlStrEqual(name, BAD_CAST "child"))
8350 ret = AXIS_CHILD;
8351 break;
8352 case 'd':
8353 if (xmlStrEqual(name, BAD_CAST "descendant"))
8354 ret = AXIS_DESCENDANT;
8355 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8356 ret = AXIS_DESCENDANT_OR_SELF;
8357 break;
8358 case 'f':
8359 if (xmlStrEqual(name, BAD_CAST "following"))
8360 ret = AXIS_FOLLOWING;
8361 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8362 ret = AXIS_FOLLOWING_SIBLING;
8363 break;
8364 case 'n':
8365 if (xmlStrEqual(name, BAD_CAST "namespace"))
8366 ret = AXIS_NAMESPACE;
8367 break;
8368 case 'p':
8369 if (xmlStrEqual(name, BAD_CAST "parent"))
8370 ret = AXIS_PARENT;
8371 if (xmlStrEqual(name, BAD_CAST "preceding"))
8372 ret = AXIS_PRECEDING;
8373 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8374 ret = AXIS_PRECEDING_SIBLING;
8375 break;
8376 case 's':
8377 if (xmlStrEqual(name, BAD_CAST "self"))
8378 ret = AXIS_SELF;
8379 break;
8380 }
8381 return(ret);
8382}
8383
8384/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008385 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008386 * @ctxt: the XPath Parser context
8387 *
8388 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8389 * | AbbreviatedStep
8390 *
8391 * [12] AbbreviatedStep ::= '.' | '..'
8392 *
8393 * [5] AxisSpecifier ::= AxisName '::'
8394 * | AbbreviatedAxisSpecifier
8395 *
8396 * [13] AbbreviatedAxisSpecifier ::= '@'?
8397 *
8398 * Modified for XPtr range support as:
8399 *
8400 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8401 * | AbbreviatedStep
8402 * | 'range-to' '(' Expr ')' Predicate*
8403 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008404 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008405 * A location step of . is short for self::node(). This is
8406 * particularly useful in conjunction with //. For example, the
8407 * location path .//para is short for
8408 * self::node()/descendant-or-self::node()/child::para
8409 * and so will select all para descendant elements of the context
8410 * node.
8411 * Similarly, a location step of .. is short for parent::node().
8412 * For example, ../title is short for parent::node()/child::title
8413 * and so will select the title children of the parent of the context
8414 * node.
8415 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008416static void
8417xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008418#ifdef LIBXML_XPTR_ENABLED
8419 int rangeto = 0;
8420 int op2 = -1;
8421#endif
8422
Owen Taylor3473f882001-02-23 17:55:21 +00008423 SKIP_BLANKS;
8424 if ((CUR == '.') && (NXT(1) == '.')) {
8425 SKIP(2);
8426 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008427 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8428 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008429 } else if (CUR == '.') {
8430 NEXT;
8431 SKIP_BLANKS;
8432 } else {
8433 xmlChar *name = NULL;
8434 const xmlChar *prefix = NULL;
8435 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008436 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008437 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008438 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008439
8440 /*
8441 * The modification needed for XPointer change to the production
8442 */
8443#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008444 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008445 name = xmlXPathParseNCName(ctxt);
8446 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008447 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008448 xmlFree(name);
8449 SKIP_BLANKS;
8450 if (CUR != '(') {
8451 XP_ERROR(XPATH_EXPR_ERROR);
8452 }
8453 NEXT;
8454 SKIP_BLANKS;
8455
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008456 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008457 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008458 CHECK_ERROR;
8459
8460 SKIP_BLANKS;
8461 if (CUR != ')') {
8462 XP_ERROR(XPATH_EXPR_ERROR);
8463 }
8464 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008465 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008466 goto eval_predicates;
8467 }
8468 }
8469#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008470 if (CUR == '*') {
8471 axis = AXIS_CHILD;
8472 } else {
8473 if (name == NULL)
8474 name = xmlXPathParseNCName(ctxt);
8475 if (name != NULL) {
8476 axis = xmlXPathIsAxisName(name);
8477 if (axis != 0) {
8478 SKIP_BLANKS;
8479 if ((CUR == ':') && (NXT(1) == ':')) {
8480 SKIP(2);
8481 xmlFree(name);
8482 name = NULL;
8483 } else {
8484 /* an element name can conflict with an axis one :-\ */
8485 axis = AXIS_CHILD;
8486 }
Owen Taylor3473f882001-02-23 17:55:21 +00008487 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008488 axis = AXIS_CHILD;
8489 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008490 } else if (CUR == '@') {
8491 NEXT;
8492 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008493 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008494 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008495 }
Owen Taylor3473f882001-02-23 17:55:21 +00008496 }
8497
8498 CHECK_ERROR;
8499
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008500 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008501 if (test == 0)
8502 return;
8503
8504#ifdef DEBUG_STEP
8505 xmlGenericError(xmlGenericErrorContext,
8506 "Basis : computing new set\n");
8507#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008508
Owen Taylor3473f882001-02-23 17:55:21 +00008509#ifdef DEBUG_STEP
8510 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008511 if (ctxt->value == NULL)
8512 xmlGenericError(xmlGenericErrorContext, "no value\n");
8513 else if (ctxt->value->nodesetval == NULL)
8514 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8515 else
8516 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008517#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008518
8519eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008520 op1 = ctxt->comp->last;
8521 ctxt->comp->last = -1;
8522
Owen Taylor3473f882001-02-23 17:55:21 +00008523 SKIP_BLANKS;
8524 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008525 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008526 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008527
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008528#ifdef LIBXML_XPTR_ENABLED
8529 if (rangeto) {
8530 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8531 } else
8532#endif
8533 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8534 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008535
Owen Taylor3473f882001-02-23 17:55:21 +00008536 }
8537#ifdef DEBUG_STEP
8538 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008539 if (ctxt->value == NULL)
8540 xmlGenericError(xmlGenericErrorContext, "no value\n");
8541 else if (ctxt->value->nodesetval == NULL)
8542 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8543 else
8544 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8545 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008546#endif
8547}
8548
8549/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008550 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008551 * @ctxt: the XPath Parser context
8552 *
8553 * [3] RelativeLocationPath ::= Step
8554 * | RelativeLocationPath '/' Step
8555 * | AbbreviatedRelativeLocationPath
8556 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8557 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008558 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008559 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008560static void
Owen Taylor3473f882001-02-23 17:55:21 +00008561#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008562xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008563#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008564xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008565#endif
8566(xmlXPathParserContextPtr ctxt) {
8567 SKIP_BLANKS;
8568 if ((CUR == '/') && (NXT(1) == '/')) {
8569 SKIP(2);
8570 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008571 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8572 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008573 } else if (CUR == '/') {
8574 NEXT;
8575 SKIP_BLANKS;
8576 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008577 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008578 SKIP_BLANKS;
8579 while (CUR == '/') {
8580 if ((CUR == '/') && (NXT(1) == '/')) {
8581 SKIP(2);
8582 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008583 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008584 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008585 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008586 } else if (CUR == '/') {
8587 NEXT;
8588 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008589 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008590 }
8591 SKIP_BLANKS;
8592 }
8593}
8594
8595/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008596 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008597 * @ctxt: the XPath Parser context
8598 *
8599 * [1] LocationPath ::= RelativeLocationPath
8600 * | AbsoluteLocationPath
8601 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8602 * | AbbreviatedAbsoluteLocationPath
8603 * [10] AbbreviatedAbsoluteLocationPath ::=
8604 * '//' RelativeLocationPath
8605 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008606 * Compile a location path
8607 *
Owen Taylor3473f882001-02-23 17:55:21 +00008608 * // is short for /descendant-or-self::node()/. For example,
8609 * //para is short for /descendant-or-self::node()/child::para and
8610 * so will select any para element in the document (even a para element
8611 * that is a document element will be selected by //para since the
8612 * document element node is a child of the root node); div//para is
8613 * short for div/descendant-or-self::node()/child::para and so will
8614 * select all para descendants of div children.
8615 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008616static void
8617xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008618 SKIP_BLANKS;
8619 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008620 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008621 } else {
8622 while (CUR == '/') {
8623 if ((CUR == '/') && (NXT(1) == '/')) {
8624 SKIP(2);
8625 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008626 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8627 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008628 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008629 } else if (CUR == '/') {
8630 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008631 SKIP_BLANKS;
8632 if ((CUR != 0 ) &&
8633 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8634 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008635 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008636 }
8637 }
8638 }
8639}
8640
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008641/************************************************************************
8642 * *
8643 * XPath precompiled expression evaluation *
8644 * *
8645 ************************************************************************/
8646
Daniel Veillardf06307e2001-07-03 10:35:50 +00008647static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008648xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8649
8650/**
8651 * xmlXPathNodeCollectAndTest:
8652 * @ctxt: the XPath Parser context
8653 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008654 * @first: pointer to the first element in document order
8655 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008656 *
8657 * This is the function implementing a step: based on the current list
8658 * of nodes, it builds up a new list, looking at all nodes under that
8659 * axis and selecting them it also do the predicate filtering
8660 *
8661 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008662 *
8663 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008664 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008665static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008666xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008667 xmlXPathStepOpPtr op,
8668 xmlNodePtr * first, xmlNodePtr * last)
8669{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008670 xmlXPathAxisVal axis = op->value;
8671 xmlXPathTestVal test = op->value2;
8672 xmlXPathTypeVal type = op->value3;
8673 const xmlChar *prefix = op->value4;
8674 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008675 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008676
8677#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008678 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008679#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008680 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008681 xmlNodeSetPtr ret, list;
8682 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008683 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008684 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008685 xmlNodePtr cur = NULL;
8686 xmlXPathObjectPtr obj;
8687 xmlNodeSetPtr nodelist;
8688 xmlNodePtr tmp;
8689
Daniel Veillardf06307e2001-07-03 10:35:50 +00008690 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008691 obj = valuePop(ctxt);
8692 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008693 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008694 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008695 URI = xmlXPathNsLookup(ctxt->context, prefix);
8696 if (URI == NULL)
8697 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008698 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008699#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008700 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008701#endif
8702 switch (axis) {
8703 case AXIS_ANCESTOR:
8704#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008705 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008706#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008707 first = NULL;
8708 next = xmlXPathNextAncestor;
8709 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008710 case AXIS_ANCESTOR_OR_SELF:
8711#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008712 xmlGenericError(xmlGenericErrorContext,
8713 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008714#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008715 first = NULL;
8716 next = xmlXPathNextAncestorOrSelf;
8717 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008718 case AXIS_ATTRIBUTE:
8719#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008720 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008721#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008722 first = NULL;
8723 last = NULL;
8724 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008725 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008726 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008727 case AXIS_CHILD:
8728#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008729 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008730#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008731 last = NULL;
8732 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008733 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008734 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008735 case AXIS_DESCENDANT:
8736#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008737 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008738#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008739 last = NULL;
8740 next = xmlXPathNextDescendant;
8741 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008742 case AXIS_DESCENDANT_OR_SELF:
8743#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008744 xmlGenericError(xmlGenericErrorContext,
8745 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008746#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008747 last = NULL;
8748 next = xmlXPathNextDescendantOrSelf;
8749 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008750 case AXIS_FOLLOWING:
8751#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008752 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008753#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008754 last = NULL;
8755 next = xmlXPathNextFollowing;
8756 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008757 case AXIS_FOLLOWING_SIBLING:
8758#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008759 xmlGenericError(xmlGenericErrorContext,
8760 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008761#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008762 last = NULL;
8763 next = xmlXPathNextFollowingSibling;
8764 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008765 case AXIS_NAMESPACE:
8766#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008767 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008768#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008769 first = NULL;
8770 last = NULL;
8771 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008772 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008773 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008774 case AXIS_PARENT:
8775#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008776 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008777#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008778 first = NULL;
8779 next = xmlXPathNextParent;
8780 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008781 case AXIS_PRECEDING:
8782#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008783 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008784#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008785 first = NULL;
8786 next = xmlXPathNextPrecedingInternal;
8787 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008788 case AXIS_PRECEDING_SIBLING:
8789#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008790 xmlGenericError(xmlGenericErrorContext,
8791 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008792#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008793 first = NULL;
8794 next = xmlXPathNextPrecedingSibling;
8795 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008796 case AXIS_SELF:
8797#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008798 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008799#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008800 first = NULL;
8801 last = NULL;
8802 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008803 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008804 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008805 }
8806 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008807 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008808
8809 nodelist = obj->nodesetval;
8810 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008811 xmlXPathFreeObject(obj);
8812 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8813 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008814 }
8815 addNode = xmlXPathNodeSetAddUnique;
8816 ret = NULL;
8817#ifdef DEBUG_STEP
8818 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008819 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008820 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008821 case NODE_TEST_NONE:
8822 xmlGenericError(xmlGenericErrorContext,
8823 " searching for none !!!\n");
8824 break;
8825 case NODE_TEST_TYPE:
8826 xmlGenericError(xmlGenericErrorContext,
8827 " searching for type %d\n", type);
8828 break;
8829 case NODE_TEST_PI:
8830 xmlGenericError(xmlGenericErrorContext,
8831 " searching for PI !!!\n");
8832 break;
8833 case NODE_TEST_ALL:
8834 xmlGenericError(xmlGenericErrorContext,
8835 " searching for *\n");
8836 break;
8837 case NODE_TEST_NS:
8838 xmlGenericError(xmlGenericErrorContext,
8839 " searching for namespace %s\n",
8840 prefix);
8841 break;
8842 case NODE_TEST_NAME:
8843 xmlGenericError(xmlGenericErrorContext,
8844 " searching for name %s\n", name);
8845 if (prefix != NULL)
8846 xmlGenericError(xmlGenericErrorContext,
8847 " with namespace %s\n", prefix);
8848 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008849 }
8850 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8851#endif
8852 /*
8853 * 2.3 Node Tests
8854 * - For the attribute axis, the principal node type is attribute.
8855 * - For the namespace axis, the principal node type is namespace.
8856 * - For other axes, the principal node type is element.
8857 *
8858 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008859 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008860 * select all element children of the context node
8861 */
8862 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008863 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008864 ctxt->context->node = nodelist->nodeTab[i];
8865
Daniel Veillardf06307e2001-07-03 10:35:50 +00008866 cur = NULL;
8867 list = xmlXPathNodeSetCreate(NULL);
8868 do {
8869 cur = next(ctxt, cur);
8870 if (cur == NULL)
8871 break;
8872 if ((first != NULL) && (*first == cur))
8873 break;
8874 if (((t % 256) == 0) &&
8875 (first != NULL) && (*first != NULL) &&
8876 (xmlXPathCmpNodes(*first, cur) >= 0))
8877 break;
8878 if ((last != NULL) && (*last == cur))
8879 break;
8880 if (((t % 256) == 0) &&
8881 (last != NULL) && (*last != NULL) &&
8882 (xmlXPathCmpNodes(cur, *last) >= 0))
8883 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008884 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008885#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008886 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8887#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008888 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008889 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008890 ctxt->context->node = tmp;
8891 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008892 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008893 if ((cur->type == type) ||
8894 ((type == NODE_TYPE_NODE) &&
8895 ((cur->type == XML_DOCUMENT_NODE) ||
8896 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8897 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008898 (cur->type == XML_NAMESPACE_DECL) ||
8899 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008900 (cur->type == XML_PI_NODE) ||
8901 (cur->type == XML_COMMENT_NODE) ||
8902 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008903 (cur->type == XML_TEXT_NODE))) ||
8904 ((type == NODE_TYPE_TEXT) &&
8905 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008906#ifdef DEBUG_STEP
8907 n++;
8908#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008909 addNode(list, cur);
8910 }
8911 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008912 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008913 if (cur->type == XML_PI_NODE) {
8914 if ((name != NULL) &&
8915 (!xmlStrEqual(name, cur->name)))
8916 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008917#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008918 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008919#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008920 addNode(list, cur);
8921 }
8922 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008924 if (axis == AXIS_ATTRIBUTE) {
8925 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008927 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008928#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 addNode(list, cur);
8930 }
8931 } else if (axis == AXIS_NAMESPACE) {
8932 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008933#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008934 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008935#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008936 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8937 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 }
8939 } else {
8940 if (cur->type == XML_ELEMENT_NODE) {
8941 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008942#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008943 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008944#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008945 addNode(list, cur);
8946 } else if ((cur->ns != NULL) &&
8947 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008948#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008949 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008950#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008951 addNode(list, cur);
8952 }
8953 }
8954 }
8955 break;
8956 case NODE_TEST_NS:{
8957 TODO;
8958 break;
8959 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008960 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008961 switch (cur->type) {
8962 case XML_ELEMENT_NODE:
8963 if (xmlStrEqual(name, cur->name)) {
8964 if (prefix == NULL) {
8965 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008966#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008967 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008968#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 addNode(list, cur);
8970 }
8971 } else {
8972 if ((cur->ns != NULL) &&
8973 (xmlStrEqual(URI,
8974 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008975#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008978 addNode(list, cur);
8979 }
8980 }
8981 }
8982 break;
8983 case XML_ATTRIBUTE_NODE:{
8984 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985
Daniel Veillardf06307e2001-07-03 10:35:50 +00008986 if (xmlStrEqual(name, attr->name)) {
8987 if (prefix == NULL) {
8988 if ((attr->ns == NULL) ||
8989 (attr->ns->prefix == NULL)) {
8990#ifdef DEBUG_STEP
8991 n++;
8992#endif
8993 addNode(list,
8994 (xmlNodePtr) attr);
8995 }
8996 } else {
8997 if ((attr->ns != NULL) &&
8998 (xmlStrEqual(URI,
8999 attr->ns->
9000 href))) {
9001#ifdef DEBUG_STEP
9002 n++;
9003#endif
9004 addNode(list,
9005 (xmlNodePtr) attr);
9006 }
9007 }
9008 }
9009 break;
9010 }
9011 case XML_NAMESPACE_DECL:
9012 if (cur->type == XML_NAMESPACE_DECL) {
9013 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009014
Daniel Veillardf06307e2001-07-03 10:35:50 +00009015 if ((ns->prefix != NULL) && (name != NULL)
9016 && (xmlStrEqual(ns->prefix, name))) {
9017#ifdef DEBUG_STEP
9018 n++;
9019#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009020 xmlXPathNodeSetAddNs(list,
9021 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009022 }
9023 }
9024 break;
9025 default:
9026 break;
9027 }
9028 break;
9029 break;
9030 }
9031 } while (cur != NULL);
9032
9033 /*
9034 * If there is some predicate filtering do it now
9035 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009036 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009037 xmlXPathObjectPtr obj2;
9038
9039 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9040 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9041 CHECK_TYPE0(XPATH_NODESET);
9042 obj2 = valuePop(ctxt);
9043 list = obj2->nodesetval;
9044 obj2->nodesetval = NULL;
9045 xmlXPathFreeObject(obj2);
9046 }
9047 if (ret == NULL) {
9048 ret = list;
9049 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009050 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 xmlXPathFreeNodeSet(list);
9052 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009053 }
9054 ctxt->context->node = tmp;
9055#ifdef DEBUG_STEP
9056 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009057 "\nExamined %d nodes, found %d nodes at that step\n",
9058 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009059#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009060 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009061 if ((obj->boolval) && (obj->user != NULL)) {
9062 ctxt->value->boolval = 1;
9063 ctxt->value->user = obj->user;
9064 obj->user = NULL;
9065 obj->boolval = 0;
9066 }
9067 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009068 return(t);
9069}
9070
9071/**
9072 * xmlXPathNodeCollectAndTestNth:
9073 * @ctxt: the XPath Parser context
9074 * @op: the XPath precompiled step operation
9075 * @indx: the index to collect
9076 * @first: pointer to the first element in document order
9077 * @last: pointer to the last element in document order
9078 *
9079 * This is the function implementing a step: based on the current list
9080 * of nodes, it builds up a new list, looking at all nodes under that
9081 * axis and selecting them it also do the predicate filtering
9082 *
9083 * Pushes the new NodeSet resulting from the search.
9084 * Returns the number of node traversed
9085 */
9086static int
9087xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9088 xmlXPathStepOpPtr op, int indx,
9089 xmlNodePtr * first, xmlNodePtr * last)
9090{
9091 xmlXPathAxisVal axis = op->value;
9092 xmlXPathTestVal test = op->value2;
9093 xmlXPathTypeVal type = op->value3;
9094 const xmlChar *prefix = op->value4;
9095 const xmlChar *name = op->value5;
9096 const xmlChar *URI = NULL;
9097 int n = 0, t = 0;
9098
9099 int i;
9100 xmlNodeSetPtr list;
9101 xmlXPathTraversalFunction next = NULL;
9102 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9103 xmlNodePtr cur = NULL;
9104 xmlXPathObjectPtr obj;
9105 xmlNodeSetPtr nodelist;
9106 xmlNodePtr tmp;
9107
9108 CHECK_TYPE0(XPATH_NODESET);
9109 obj = valuePop(ctxt);
9110 addNode = xmlXPathNodeSetAdd;
9111 if (prefix != NULL) {
9112 URI = xmlXPathNsLookup(ctxt->context, prefix);
9113 if (URI == NULL)
9114 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9115 }
9116#ifdef DEBUG_STEP_NTH
9117 xmlGenericError(xmlGenericErrorContext, "new step : ");
9118 if (first != NULL) {
9119 if (*first != NULL)
9120 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9121 (*first)->name);
9122 else
9123 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9124 }
9125 if (last != NULL) {
9126 if (*last != NULL)
9127 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9128 (*last)->name);
9129 else
9130 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9131 }
9132#endif
9133 switch (axis) {
9134 case AXIS_ANCESTOR:
9135#ifdef DEBUG_STEP_NTH
9136 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9137#endif
9138 first = NULL;
9139 next = xmlXPathNextAncestor;
9140 break;
9141 case AXIS_ANCESTOR_OR_SELF:
9142#ifdef DEBUG_STEP_NTH
9143 xmlGenericError(xmlGenericErrorContext,
9144 "axis 'ancestors-or-self' ");
9145#endif
9146 first = NULL;
9147 next = xmlXPathNextAncestorOrSelf;
9148 break;
9149 case AXIS_ATTRIBUTE:
9150#ifdef DEBUG_STEP_NTH
9151 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9152#endif
9153 first = NULL;
9154 last = NULL;
9155 next = xmlXPathNextAttribute;
9156 break;
9157 case AXIS_CHILD:
9158#ifdef DEBUG_STEP_NTH
9159 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9160#endif
9161 last = NULL;
9162 next = xmlXPathNextChild;
9163 break;
9164 case AXIS_DESCENDANT:
9165#ifdef DEBUG_STEP_NTH
9166 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9167#endif
9168 last = NULL;
9169 next = xmlXPathNextDescendant;
9170 break;
9171 case AXIS_DESCENDANT_OR_SELF:
9172#ifdef DEBUG_STEP_NTH
9173 xmlGenericError(xmlGenericErrorContext,
9174 "axis 'descendant-or-self' ");
9175#endif
9176 last = NULL;
9177 next = xmlXPathNextDescendantOrSelf;
9178 break;
9179 case AXIS_FOLLOWING:
9180#ifdef DEBUG_STEP_NTH
9181 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9182#endif
9183 last = NULL;
9184 next = xmlXPathNextFollowing;
9185 break;
9186 case AXIS_FOLLOWING_SIBLING:
9187#ifdef DEBUG_STEP_NTH
9188 xmlGenericError(xmlGenericErrorContext,
9189 "axis 'following-siblings' ");
9190#endif
9191 last = NULL;
9192 next = xmlXPathNextFollowingSibling;
9193 break;
9194 case AXIS_NAMESPACE:
9195#ifdef DEBUG_STEP_NTH
9196 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9197#endif
9198 last = NULL;
9199 first = NULL;
9200 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9201 break;
9202 case AXIS_PARENT:
9203#ifdef DEBUG_STEP_NTH
9204 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9205#endif
9206 first = NULL;
9207 next = xmlXPathNextParent;
9208 break;
9209 case AXIS_PRECEDING:
9210#ifdef DEBUG_STEP_NTH
9211 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9212#endif
9213 first = NULL;
9214 next = xmlXPathNextPrecedingInternal;
9215 break;
9216 case AXIS_PRECEDING_SIBLING:
9217#ifdef DEBUG_STEP_NTH
9218 xmlGenericError(xmlGenericErrorContext,
9219 "axis 'preceding-sibling' ");
9220#endif
9221 first = NULL;
9222 next = xmlXPathNextPrecedingSibling;
9223 break;
9224 case AXIS_SELF:
9225#ifdef DEBUG_STEP_NTH
9226 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9227#endif
9228 first = NULL;
9229 last = NULL;
9230 next = xmlXPathNextSelf;
9231 break;
9232 }
9233 if (next == NULL)
9234 return(0);
9235
9236 nodelist = obj->nodesetval;
9237 if (nodelist == NULL) {
9238 xmlXPathFreeObject(obj);
9239 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9240 return(0);
9241 }
9242 addNode = xmlXPathNodeSetAddUnique;
9243#ifdef DEBUG_STEP_NTH
9244 xmlGenericError(xmlGenericErrorContext,
9245 " context contains %d nodes\n", nodelist->nodeNr);
9246 switch (test) {
9247 case NODE_TEST_NONE:
9248 xmlGenericError(xmlGenericErrorContext,
9249 " searching for none !!!\n");
9250 break;
9251 case NODE_TEST_TYPE:
9252 xmlGenericError(xmlGenericErrorContext,
9253 " searching for type %d\n", type);
9254 break;
9255 case NODE_TEST_PI:
9256 xmlGenericError(xmlGenericErrorContext,
9257 " searching for PI !!!\n");
9258 break;
9259 case NODE_TEST_ALL:
9260 xmlGenericError(xmlGenericErrorContext,
9261 " searching for *\n");
9262 break;
9263 case NODE_TEST_NS:
9264 xmlGenericError(xmlGenericErrorContext,
9265 " searching for namespace %s\n",
9266 prefix);
9267 break;
9268 case NODE_TEST_NAME:
9269 xmlGenericError(xmlGenericErrorContext,
9270 " searching for name %s\n", name);
9271 if (prefix != NULL)
9272 xmlGenericError(xmlGenericErrorContext,
9273 " with namespace %s\n", prefix);
9274 break;
9275 }
9276 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9277#endif
9278 /*
9279 * 2.3 Node Tests
9280 * - For the attribute axis, the principal node type is attribute.
9281 * - For the namespace axis, the principal node type is namespace.
9282 * - For other axes, the principal node type is element.
9283 *
9284 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009285 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009286 * select all element children of the context node
9287 */
9288 tmp = ctxt->context->node;
9289 list = xmlXPathNodeSetCreate(NULL);
9290 for (i = 0; i < nodelist->nodeNr; i++) {
9291 ctxt->context->node = nodelist->nodeTab[i];
9292
9293 cur = NULL;
9294 n = 0;
9295 do {
9296 cur = next(ctxt, cur);
9297 if (cur == NULL)
9298 break;
9299 if ((first != NULL) && (*first == cur))
9300 break;
9301 if (((t % 256) == 0) &&
9302 (first != NULL) && (*first != NULL) &&
9303 (xmlXPathCmpNodes(*first, cur) >= 0))
9304 break;
9305 if ((last != NULL) && (*last == cur))
9306 break;
9307 if (((t % 256) == 0) &&
9308 (last != NULL) && (*last != NULL) &&
9309 (xmlXPathCmpNodes(cur, *last) >= 0))
9310 break;
9311 t++;
9312 switch (test) {
9313 case NODE_TEST_NONE:
9314 ctxt->context->node = tmp;
9315 STRANGE return(0);
9316 case NODE_TEST_TYPE:
9317 if ((cur->type == type) ||
9318 ((type == NODE_TYPE_NODE) &&
9319 ((cur->type == XML_DOCUMENT_NODE) ||
9320 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9321 (cur->type == XML_ELEMENT_NODE) ||
9322 (cur->type == XML_PI_NODE) ||
9323 (cur->type == XML_COMMENT_NODE) ||
9324 (cur->type == XML_CDATA_SECTION_NODE) ||
9325 (cur->type == XML_TEXT_NODE)))) {
9326 n++;
9327 if (n == indx)
9328 addNode(list, cur);
9329 }
9330 break;
9331 case NODE_TEST_PI:
9332 if (cur->type == XML_PI_NODE) {
9333 if ((name != NULL) &&
9334 (!xmlStrEqual(name, cur->name)))
9335 break;
9336 n++;
9337 if (n == indx)
9338 addNode(list, cur);
9339 }
9340 break;
9341 case NODE_TEST_ALL:
9342 if (axis == AXIS_ATTRIBUTE) {
9343 if (cur->type == XML_ATTRIBUTE_NODE) {
9344 n++;
9345 if (n == indx)
9346 addNode(list, cur);
9347 }
9348 } else if (axis == AXIS_NAMESPACE) {
9349 if (cur->type == XML_NAMESPACE_DECL) {
9350 n++;
9351 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009352 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9353 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009354 }
9355 } else {
9356 if (cur->type == XML_ELEMENT_NODE) {
9357 if (prefix == NULL) {
9358 n++;
9359 if (n == indx)
9360 addNode(list, cur);
9361 } else if ((cur->ns != NULL) &&
9362 (xmlStrEqual(URI, cur->ns->href))) {
9363 n++;
9364 if (n == indx)
9365 addNode(list, cur);
9366 }
9367 }
9368 }
9369 break;
9370 case NODE_TEST_NS:{
9371 TODO;
9372 break;
9373 }
9374 case NODE_TEST_NAME:
9375 switch (cur->type) {
9376 case XML_ELEMENT_NODE:
9377 if (xmlStrEqual(name, cur->name)) {
9378 if (prefix == NULL) {
9379 if (cur->ns == NULL) {
9380 n++;
9381 if (n == indx)
9382 addNode(list, cur);
9383 }
9384 } else {
9385 if ((cur->ns != NULL) &&
9386 (xmlStrEqual(URI,
9387 cur->ns->href))) {
9388 n++;
9389 if (n == indx)
9390 addNode(list, cur);
9391 }
9392 }
9393 }
9394 break;
9395 case XML_ATTRIBUTE_NODE:{
9396 xmlAttrPtr attr = (xmlAttrPtr) cur;
9397
9398 if (xmlStrEqual(name, attr->name)) {
9399 if (prefix == NULL) {
9400 if ((attr->ns == NULL) ||
9401 (attr->ns->prefix == NULL)) {
9402 n++;
9403 if (n == indx)
9404 addNode(list, cur);
9405 }
9406 } else {
9407 if ((attr->ns != NULL) &&
9408 (xmlStrEqual(URI,
9409 attr->ns->
9410 href))) {
9411 n++;
9412 if (n == indx)
9413 addNode(list, cur);
9414 }
9415 }
9416 }
9417 break;
9418 }
9419 case XML_NAMESPACE_DECL:
9420 if (cur->type == XML_NAMESPACE_DECL) {
9421 xmlNsPtr ns = (xmlNsPtr) cur;
9422
9423 if ((ns->prefix != NULL) && (name != NULL)
9424 && (xmlStrEqual(ns->prefix, name))) {
9425 n++;
9426 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009427 xmlXPathNodeSetAddNs(list,
9428 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009429 }
9430 }
9431 break;
9432 default:
9433 break;
9434 }
9435 break;
9436 break;
9437 }
9438 } while (n < indx);
9439 }
9440 ctxt->context->node = tmp;
9441#ifdef DEBUG_STEP_NTH
9442 xmlGenericError(xmlGenericErrorContext,
9443 "\nExamined %d nodes, found %d nodes at that step\n",
9444 t, list->nodeNr);
9445#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009446 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009447 if ((obj->boolval) && (obj->user != NULL)) {
9448 ctxt->value->boolval = 1;
9449 ctxt->value->user = obj->user;
9450 obj->user = NULL;
9451 obj->boolval = 0;
9452 }
9453 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009454 return(t);
9455}
9456
9457/**
9458 * xmlXPathCompOpEvalFirst:
9459 * @ctxt: the XPath parser context with the compiled expression
9460 * @op: an XPath compiled operation
9461 * @first: the first elem found so far
9462 *
9463 * Evaluate the Precompiled XPath operation searching only the first
9464 * element in document order
9465 *
9466 * Returns the number of examined objects.
9467 */
9468static int
9469xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9470 xmlXPathStepOpPtr op, xmlNodePtr * first)
9471{
9472 int total = 0, cur;
9473 xmlXPathCompExprPtr comp;
9474 xmlXPathObjectPtr arg1, arg2;
9475
Daniel Veillard556c6682001-10-06 09:59:51 +00009476 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009477 comp = ctxt->comp;
9478 switch (op->op) {
9479 case XPATH_OP_END:
9480 return (0);
9481 case XPATH_OP_UNION:
9482 total =
9483 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9484 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009485 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009486 if ((ctxt->value != NULL)
9487 && (ctxt->value->type == XPATH_NODESET)
9488 && (ctxt->value->nodesetval != NULL)
9489 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9490 /*
9491 * limit tree traversing to first node in the result
9492 */
9493 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9494 *first = ctxt->value->nodesetval->nodeTab[0];
9495 }
9496 cur =
9497 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9498 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009499 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009500 CHECK_TYPE0(XPATH_NODESET);
9501 arg2 = valuePop(ctxt);
9502
9503 CHECK_TYPE0(XPATH_NODESET);
9504 arg1 = valuePop(ctxt);
9505
9506 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9507 arg2->nodesetval);
9508 valuePush(ctxt, arg1);
9509 xmlXPathFreeObject(arg2);
9510 /* optimizer */
9511 if (total > cur)
9512 xmlXPathCompSwap(op);
9513 return (total + cur);
9514 case XPATH_OP_ROOT:
9515 xmlXPathRoot(ctxt);
9516 return (0);
9517 case XPATH_OP_NODE:
9518 if (op->ch1 != -1)
9519 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009520 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009521 if (op->ch2 != -1)
9522 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009523 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009524 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9525 return (total);
9526 case XPATH_OP_RESET:
9527 if (op->ch1 != -1)
9528 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009529 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009530 if (op->ch2 != -1)
9531 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009532 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009533 ctxt->context->node = NULL;
9534 return (total);
9535 case XPATH_OP_COLLECT:{
9536 if (op->ch1 == -1)
9537 return (total);
9538
9539 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009540 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009541
9542 /*
9543 * Optimization for [n] selection where n is a number
9544 */
9545 if ((op->ch2 != -1) &&
9546 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9547 (comp->steps[op->ch2].ch1 == -1) &&
9548 (comp->steps[op->ch2].ch2 != -1) &&
9549 (comp->steps[comp->steps[op->ch2].ch2].op ==
9550 XPATH_OP_VALUE)) {
9551 xmlXPathObjectPtr val;
9552
9553 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9554 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9555 int indx = (int) val->floatval;
9556
9557 if (val->floatval == (float) indx) {
9558 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9559 first, NULL);
9560 return (total);
9561 }
9562 }
9563 }
9564 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9565 return (total);
9566 }
9567 case XPATH_OP_VALUE:
9568 valuePush(ctxt,
9569 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9570 return (0);
9571 case XPATH_OP_SORT:
9572 if (op->ch1 != -1)
9573 total +=
9574 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9575 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009576 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009577 if ((ctxt->value != NULL)
9578 && (ctxt->value->type == XPATH_NODESET)
9579 && (ctxt->value->nodesetval != NULL))
9580 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9581 return (total);
9582 default:
9583 return (xmlXPathCompOpEval(ctxt, op));
9584 }
9585}
9586
9587/**
9588 * xmlXPathCompOpEvalLast:
9589 * @ctxt: the XPath parser context with the compiled expression
9590 * @op: an XPath compiled operation
9591 * @last: the last elem found so far
9592 *
9593 * Evaluate the Precompiled XPath operation searching only the last
9594 * element in document order
9595 *
9596 * Returns the number of node traversed
9597 */
9598static int
9599xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9600 xmlNodePtr * last)
9601{
9602 int total = 0, cur;
9603 xmlXPathCompExprPtr comp;
9604 xmlXPathObjectPtr arg1, arg2;
9605
Daniel Veillard556c6682001-10-06 09:59:51 +00009606 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009607 comp = ctxt->comp;
9608 switch (op->op) {
9609 case XPATH_OP_END:
9610 return (0);
9611 case XPATH_OP_UNION:
9612 total =
9613 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009614 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009615 if ((ctxt->value != NULL)
9616 && (ctxt->value->type == XPATH_NODESET)
9617 && (ctxt->value->nodesetval != NULL)
9618 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9619 /*
9620 * limit tree traversing to first node in the result
9621 */
9622 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9623 *last =
9624 ctxt->value->nodesetval->nodeTab[ctxt->value->
9625 nodesetval->nodeNr -
9626 1];
9627 }
9628 cur =
9629 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009630 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009631 if ((ctxt->value != NULL)
9632 && (ctxt->value->type == XPATH_NODESET)
9633 && (ctxt->value->nodesetval != NULL)
9634 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9635 }
9636 CHECK_TYPE0(XPATH_NODESET);
9637 arg2 = valuePop(ctxt);
9638
9639 CHECK_TYPE0(XPATH_NODESET);
9640 arg1 = valuePop(ctxt);
9641
9642 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9643 arg2->nodesetval);
9644 valuePush(ctxt, arg1);
9645 xmlXPathFreeObject(arg2);
9646 /* optimizer */
9647 if (total > cur)
9648 xmlXPathCompSwap(op);
9649 return (total + cur);
9650 case XPATH_OP_ROOT:
9651 xmlXPathRoot(ctxt);
9652 return (0);
9653 case XPATH_OP_NODE:
9654 if (op->ch1 != -1)
9655 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009656 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009657 if (op->ch2 != -1)
9658 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009659 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009660 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9661 return (total);
9662 case XPATH_OP_RESET:
9663 if (op->ch1 != -1)
9664 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009665 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009666 if (op->ch2 != -1)
9667 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009668 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009669 ctxt->context->node = NULL;
9670 return (total);
9671 case XPATH_OP_COLLECT:{
9672 if (op->ch1 == -1)
9673 return (0);
9674
9675 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009676 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009677
9678 /*
9679 * Optimization for [n] selection where n is a number
9680 */
9681 if ((op->ch2 != -1) &&
9682 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9683 (comp->steps[op->ch2].ch1 == -1) &&
9684 (comp->steps[op->ch2].ch2 != -1) &&
9685 (comp->steps[comp->steps[op->ch2].ch2].op ==
9686 XPATH_OP_VALUE)) {
9687 xmlXPathObjectPtr val;
9688
9689 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9690 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9691 int indx = (int) val->floatval;
9692
9693 if (val->floatval == (float) indx) {
9694 total +=
9695 xmlXPathNodeCollectAndTestNth(ctxt, op,
9696 indx, NULL,
9697 last);
9698 return (total);
9699 }
9700 }
9701 }
9702 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9703 return (total);
9704 }
9705 case XPATH_OP_VALUE:
9706 valuePush(ctxt,
9707 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9708 return (0);
9709 case XPATH_OP_SORT:
9710 if (op->ch1 != -1)
9711 total +=
9712 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9713 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009714 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009715 if ((ctxt->value != NULL)
9716 && (ctxt->value->type == XPATH_NODESET)
9717 && (ctxt->value->nodesetval != NULL))
9718 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9719 return (total);
9720 default:
9721 return (xmlXPathCompOpEval(ctxt, op));
9722 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009723}
9724
Owen Taylor3473f882001-02-23 17:55:21 +00009725/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009726 * xmlXPathCompOpEval:
9727 * @ctxt: the XPath parser context with the compiled expression
9728 * @op: an XPath compiled operation
9729 *
9730 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009731 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009732 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009733static int
9734xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9735{
9736 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009737 int equal, ret;
9738 xmlXPathCompExprPtr comp;
9739 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009740 xmlNodePtr bak;
9741 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009742 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009743 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009744
Daniel Veillard556c6682001-10-06 09:59:51 +00009745 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009746 comp = ctxt->comp;
9747 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009748 case XPATH_OP_END:
9749 return (0);
9750 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009751 bakd = ctxt->context->doc;
9752 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009753 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009754 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009755 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009756 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009757 xmlXPathBooleanFunction(ctxt, 1);
9758 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9759 return (total);
9760 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009761 ctxt->context->doc = bakd;
9762 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009763 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009764 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009765 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009766 if (ctxt->error) {
9767 xmlXPathFreeObject(arg2);
9768 return(0);
9769 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009770 xmlXPathBooleanFunction(ctxt, 1);
9771 arg1 = valuePop(ctxt);
9772 arg1->boolval &= arg2->boolval;
9773 valuePush(ctxt, arg1);
9774 xmlXPathFreeObject(arg2);
9775 return (total);
9776 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009777 bakd = ctxt->context->doc;
9778 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009779 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009780 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009781 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009782 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009783 xmlXPathBooleanFunction(ctxt, 1);
9784 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9785 return (total);
9786 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009787 ctxt->context->doc = bakd;
9788 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009789 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009790 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009791 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009792 if (ctxt->error) {
9793 xmlXPathFreeObject(arg2);
9794 return(0);
9795 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009796 xmlXPathBooleanFunction(ctxt, 1);
9797 arg1 = valuePop(ctxt);
9798 arg1->boolval |= arg2->boolval;
9799 valuePush(ctxt, arg1);
9800 xmlXPathFreeObject(arg2);
9801 return (total);
9802 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009803 bakd = ctxt->context->doc;
9804 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009805 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009806 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009807 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009808 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009809 ctxt->context->doc = bakd;
9810 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009811 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009812 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009813 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009814 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009815 if (op->value)
9816 equal = xmlXPathEqualValues(ctxt);
9817 else
9818 equal = xmlXPathNotEqualValues(ctxt);
9819 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009820 return (total);
9821 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009822 bakd = ctxt->context->doc;
9823 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009824 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009825 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009827 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009828 ctxt->context->doc = bakd;
9829 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009830 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009831 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009832 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009833 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009834 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9835 valuePush(ctxt, xmlXPathNewBoolean(ret));
9836 return (total);
9837 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009838 bakd = ctxt->context->doc;
9839 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009840 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009841 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009843 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009844 if (op->ch2 != -1) {
9845 ctxt->context->doc = bakd;
9846 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009847 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009848 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009849 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009850 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009851 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009852 if (op->value == 0)
9853 xmlXPathSubValues(ctxt);
9854 else if (op->value == 1)
9855 xmlXPathAddValues(ctxt);
9856 else if (op->value == 2)
9857 xmlXPathValueFlipSign(ctxt);
9858 else if (op->value == 3) {
9859 CAST_TO_NUMBER;
9860 CHECK_TYPE0(XPATH_NUMBER);
9861 }
9862 return (total);
9863 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009864 bakd = ctxt->context->doc;
9865 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009866 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009867 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009868 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009869 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009870 ctxt->context->doc = bakd;
9871 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009872 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009873 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009874 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009875 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009876 if (op->value == 0)
9877 xmlXPathMultValues(ctxt);
9878 else if (op->value == 1)
9879 xmlXPathDivValues(ctxt);
9880 else if (op->value == 2)
9881 xmlXPathModValues(ctxt);
9882 return (total);
9883 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009884 bakd = ctxt->context->doc;
9885 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009886 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009887 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009888 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009889 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009890 ctxt->context->doc = bakd;
9891 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009892 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009893 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009894 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009895 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009896 CHECK_TYPE0(XPATH_NODESET);
9897 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009898
Daniel Veillardf06307e2001-07-03 10:35:50 +00009899 CHECK_TYPE0(XPATH_NODESET);
9900 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009901
Daniel Veillardf06307e2001-07-03 10:35:50 +00009902 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9903 arg2->nodesetval);
9904 valuePush(ctxt, arg1);
9905 xmlXPathFreeObject(arg2);
9906 return (total);
9907 case XPATH_OP_ROOT:
9908 xmlXPathRoot(ctxt);
9909 return (total);
9910 case XPATH_OP_NODE:
9911 if (op->ch1 != -1)
9912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009913 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009914 if (op->ch2 != -1)
9915 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009916 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009917 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9918 return (total);
9919 case XPATH_OP_RESET:
9920 if (op->ch1 != -1)
9921 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009922 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009923 if (op->ch2 != -1)
9924 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009925 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009926 ctxt->context->node = NULL;
9927 return (total);
9928 case XPATH_OP_COLLECT:{
9929 if (op->ch1 == -1)
9930 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009931
Daniel Veillardf06307e2001-07-03 10:35:50 +00009932 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009933 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009934
Daniel Veillardf06307e2001-07-03 10:35:50 +00009935 /*
9936 * Optimization for [n] selection where n is a number
9937 */
9938 if ((op->ch2 != -1) &&
9939 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9940 (comp->steps[op->ch2].ch1 == -1) &&
9941 (comp->steps[op->ch2].ch2 != -1) &&
9942 (comp->steps[comp->steps[op->ch2].ch2].op ==
9943 XPATH_OP_VALUE)) {
9944 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009945
Daniel Veillardf06307e2001-07-03 10:35:50 +00009946 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9947 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9948 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009949
Daniel Veillardf06307e2001-07-03 10:35:50 +00009950 if (val->floatval == (float) indx) {
9951 total +=
9952 xmlXPathNodeCollectAndTestNth(ctxt, op,
9953 indx, NULL,
9954 NULL);
9955 return (total);
9956 }
9957 }
9958 }
9959 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9960 return (total);
9961 }
9962 case XPATH_OP_VALUE:
9963 valuePush(ctxt,
9964 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9965 return (total);
9966 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009967 xmlXPathObjectPtr val;
9968
Daniel Veillardf06307e2001-07-03 10:35:50 +00009969 if (op->ch1 != -1)
9970 total +=
9971 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009972 if (op->value5 == NULL) {
9973 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9974 if (val == NULL) {
9975 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9976 return(0);
9977 }
9978 valuePush(ctxt, val);
9979 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009981
Daniel Veillardf06307e2001-07-03 10:35:50 +00009982 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9983 if (URI == NULL) {
9984 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009985 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009986 op->value4, op->value5);
9987 return (total);
9988 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009989 val = xmlXPathVariableLookupNS(ctxt->context,
9990 op->value4, URI);
9991 if (val == NULL) {
9992 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9993 return(0);
9994 }
9995 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 }
9997 return (total);
9998 }
9999 case XPATH_OP_FUNCTION:{
10000 xmlXPathFunction func;
10001 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010002 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010003
10004 if (op->ch1 != -1)
10005 total +=
10006 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010007 if (ctxt->valueNr < op->value) {
10008 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010009 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010010 ctxt->error = XPATH_INVALID_OPERAND;
10011 return (total);
10012 }
10013 for (i = 0; i < op->value; i++)
10014 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10015 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010016 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010017 ctxt->error = XPATH_INVALID_OPERAND;
10018 return (total);
10019 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010020 if (op->cache != NULL)
10021 func = (xmlXPathFunction) op->cache;
10022 else {
10023 const xmlChar *URI = NULL;
10024
10025 if (op->value5 == NULL)
10026 func =
10027 xmlXPathFunctionLookup(ctxt->context,
10028 op->value4);
10029 else {
10030 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10031 if (URI == NULL) {
10032 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010033 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010034 op->value4, op->value5);
10035 return (total);
10036 }
10037 func = xmlXPathFunctionLookupNS(ctxt->context,
10038 op->value4, URI);
10039 }
10040 if (func == NULL) {
10041 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010042 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 op->value4);
10044 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010045 }
10046 op->cache = (void *) func;
10047 op->cacheURI = (void *) URI;
10048 }
10049 oldFunc = ctxt->context->function;
10050 oldFuncURI = ctxt->context->functionURI;
10051 ctxt->context->function = op->value4;
10052 ctxt->context->functionURI = op->cacheURI;
10053 func(ctxt, op->value);
10054 ctxt->context->function = oldFunc;
10055 ctxt->context->functionURI = oldFuncURI;
10056 return (total);
10057 }
10058 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010059 bakd = ctxt->context->doc;
10060 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061 if (op->ch1 != -1)
10062 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010063 ctxt->context->doc = bakd;
10064 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010065 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010066 if (op->ch2 != -1)
10067 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010068 ctxt->context->doc = bakd;
10069 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010070 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010071 return (total);
10072 case XPATH_OP_PREDICATE:
10073 case XPATH_OP_FILTER:{
10074 xmlXPathObjectPtr res;
10075 xmlXPathObjectPtr obj, tmp;
10076 xmlNodeSetPtr newset = NULL;
10077 xmlNodeSetPtr oldset;
10078 xmlNodePtr oldnode;
10079 int i;
10080
10081 /*
10082 * Optimization for ()[1] selection i.e. the first elem
10083 */
10084 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10085 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10086 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10087 xmlXPathObjectPtr val;
10088
10089 val = comp->steps[op->ch2].value4;
10090 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10091 (val->floatval == 1.0)) {
10092 xmlNodePtr first = NULL;
10093
10094 total +=
10095 xmlXPathCompOpEvalFirst(ctxt,
10096 &comp->steps[op->ch1],
10097 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010098 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099 /*
10100 * The nodeset should be in document order,
10101 * Keep only the first value
10102 */
10103 if ((ctxt->value != NULL) &&
10104 (ctxt->value->type == XPATH_NODESET) &&
10105 (ctxt->value->nodesetval != NULL) &&
10106 (ctxt->value->nodesetval->nodeNr > 1))
10107 ctxt->value->nodesetval->nodeNr = 1;
10108 return (total);
10109 }
10110 }
10111 /*
10112 * Optimization for ()[last()] selection i.e. the last elem
10113 */
10114 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10115 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10116 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10117 int f = comp->steps[op->ch2].ch1;
10118
10119 if ((f != -1) &&
10120 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10121 (comp->steps[f].value5 == NULL) &&
10122 (comp->steps[f].value == 0) &&
10123 (comp->steps[f].value4 != NULL) &&
10124 (xmlStrEqual
10125 (comp->steps[f].value4, BAD_CAST "last"))) {
10126 xmlNodePtr last = NULL;
10127
10128 total +=
10129 xmlXPathCompOpEvalLast(ctxt,
10130 &comp->steps[op->ch1],
10131 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010132 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010133 /*
10134 * The nodeset should be in document order,
10135 * Keep only the last value
10136 */
10137 if ((ctxt->value != NULL) &&
10138 (ctxt->value->type == XPATH_NODESET) &&
10139 (ctxt->value->nodesetval != NULL) &&
10140 (ctxt->value->nodesetval->nodeTab != NULL) &&
10141 (ctxt->value->nodesetval->nodeNr > 1)) {
10142 ctxt->value->nodesetval->nodeTab[0] =
10143 ctxt->value->nodesetval->nodeTab[ctxt->
10144 value->
10145 nodesetval->
10146 nodeNr -
10147 1];
10148 ctxt->value->nodesetval->nodeNr = 1;
10149 }
10150 return (total);
10151 }
10152 }
10153
10154 if (op->ch1 != -1)
10155 total +=
10156 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010157 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010158 if (op->ch2 == -1)
10159 return (total);
10160 if (ctxt->value == NULL)
10161 return (total);
10162
10163 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010164
10165#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010166 /*
10167 * Hum are we filtering the result of an XPointer expression
10168 */
10169 if (ctxt->value->type == XPATH_LOCATIONSET) {
10170 xmlLocationSetPtr newlocset = NULL;
10171 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010172
Daniel Veillardf06307e2001-07-03 10:35:50 +000010173 /*
10174 * Extract the old locset, and then evaluate the result of the
10175 * expression for all the element in the locset. use it to grow
10176 * up a new locset.
10177 */
10178 CHECK_TYPE0(XPATH_LOCATIONSET);
10179 obj = valuePop(ctxt);
10180 oldlocset = obj->user;
10181 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010182
Daniel Veillardf06307e2001-07-03 10:35:50 +000010183 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10184 ctxt->context->contextSize = 0;
10185 ctxt->context->proximityPosition = 0;
10186 if (op->ch2 != -1)
10187 total +=
10188 xmlXPathCompOpEval(ctxt,
10189 &comp->steps[op->ch2]);
10190 res = valuePop(ctxt);
10191 if (res != NULL)
10192 xmlXPathFreeObject(res);
10193 valuePush(ctxt, obj);
10194 CHECK_ERROR0;
10195 return (total);
10196 }
10197 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010198
Daniel Veillardf06307e2001-07-03 10:35:50 +000010199 for (i = 0; i < oldlocset->locNr; i++) {
10200 /*
10201 * Run the evaluation with a node list made of a
10202 * single item in the nodelocset.
10203 */
10204 ctxt->context->node = oldlocset->locTab[i]->user;
10205 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10206 valuePush(ctxt, tmp);
10207 ctxt->context->contextSize = oldlocset->locNr;
10208 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010209
Daniel Veillardf06307e2001-07-03 10:35:50 +000010210 if (op->ch2 != -1)
10211 total +=
10212 xmlXPathCompOpEval(ctxt,
10213 &comp->steps[op->ch2]);
10214 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010215
Daniel Veillardf06307e2001-07-03 10:35:50 +000010216 /*
10217 * The result of the evaluation need to be tested to
10218 * decided whether the filter succeeded or not
10219 */
10220 res = valuePop(ctxt);
10221 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10222 xmlXPtrLocationSetAdd(newlocset,
10223 xmlXPathObjectCopy
10224 (oldlocset->locTab[i]));
10225 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010226
Daniel Veillardf06307e2001-07-03 10:35:50 +000010227 /*
10228 * Cleanup
10229 */
10230 if (res != NULL)
10231 xmlXPathFreeObject(res);
10232 if (ctxt->value == tmp) {
10233 res = valuePop(ctxt);
10234 xmlXPathFreeObject(res);
10235 }
10236
10237 ctxt->context->node = NULL;
10238 }
10239
10240 /*
10241 * The result is used as the new evaluation locset.
10242 */
10243 xmlXPathFreeObject(obj);
10244 ctxt->context->node = NULL;
10245 ctxt->context->contextSize = -1;
10246 ctxt->context->proximityPosition = -1;
10247 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10248 ctxt->context->node = oldnode;
10249 return (total);
10250 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010251#endif /* LIBXML_XPTR_ENABLED */
10252
Daniel Veillardf06307e2001-07-03 10:35:50 +000010253 /*
10254 * Extract the old set, and then evaluate the result of the
10255 * expression for all the element in the set. use it to grow
10256 * up a new set.
10257 */
10258 CHECK_TYPE0(XPATH_NODESET);
10259 obj = valuePop(ctxt);
10260 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010261
Daniel Veillardf06307e2001-07-03 10:35:50 +000010262 oldnode = ctxt->context->node;
10263 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010264
Daniel Veillardf06307e2001-07-03 10:35:50 +000010265 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10266 ctxt->context->contextSize = 0;
10267 ctxt->context->proximityPosition = 0;
10268 if (op->ch2 != -1)
10269 total +=
10270 xmlXPathCompOpEval(ctxt,
10271 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010272 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010273 res = valuePop(ctxt);
10274 if (res != NULL)
10275 xmlXPathFreeObject(res);
10276 valuePush(ctxt, obj);
10277 ctxt->context->node = oldnode;
10278 CHECK_ERROR0;
10279 } else {
10280 /*
10281 * Initialize the new set.
10282 */
10283 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010284
Daniel Veillardf06307e2001-07-03 10:35:50 +000010285 for (i = 0; i < oldset->nodeNr; i++) {
10286 /*
10287 * Run the evaluation with a node list made of
10288 * a single item in the nodeset.
10289 */
10290 ctxt->context->node = oldset->nodeTab[i];
10291 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10292 valuePush(ctxt, tmp);
10293 ctxt->context->contextSize = oldset->nodeNr;
10294 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010295
Daniel Veillardf06307e2001-07-03 10:35:50 +000010296 if (op->ch2 != -1)
10297 total +=
10298 xmlXPathCompOpEval(ctxt,
10299 &comp->steps[op->ch2]);
10300 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010301
Daniel Veillardf06307e2001-07-03 10:35:50 +000010302 /*
10303 * The result of the evaluation need to be tested to
10304 * decided whether the filter succeeded or not
10305 */
10306 res = valuePop(ctxt);
10307 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10308 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10309 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010310
Daniel Veillardf06307e2001-07-03 10:35:50 +000010311 /*
10312 * Cleanup
10313 */
10314 if (res != NULL)
10315 xmlXPathFreeObject(res);
10316 if (ctxt->value == tmp) {
10317 res = valuePop(ctxt);
10318 xmlXPathFreeObject(res);
10319 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010320
Daniel Veillardf06307e2001-07-03 10:35:50 +000010321 ctxt->context->node = NULL;
10322 }
10323
10324 /*
10325 * The result is used as the new evaluation set.
10326 */
10327 xmlXPathFreeObject(obj);
10328 ctxt->context->node = NULL;
10329 ctxt->context->contextSize = -1;
10330 ctxt->context->proximityPosition = -1;
10331 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10332 }
10333 ctxt->context->node = oldnode;
10334 return (total);
10335 }
10336 case XPATH_OP_SORT:
10337 if (op->ch1 != -1)
10338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010339 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010340 if ((ctxt->value != NULL) &&
10341 (ctxt->value->type == XPATH_NODESET) &&
10342 (ctxt->value->nodesetval != NULL))
10343 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10344 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010345#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010346 case XPATH_OP_RANGETO:{
10347 xmlXPathObjectPtr range;
10348 xmlXPathObjectPtr res, obj;
10349 xmlXPathObjectPtr tmp;
10350 xmlLocationSetPtr newset = NULL;
10351 xmlNodeSetPtr oldset;
10352 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010353
Daniel Veillardf06307e2001-07-03 10:35:50 +000010354 if (op->ch1 != -1)
10355 total +=
10356 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10357 if (op->ch2 == -1)
10358 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010359
Daniel Veillardf06307e2001-07-03 10:35:50 +000010360 CHECK_TYPE0(XPATH_NODESET);
10361 obj = valuePop(ctxt);
10362 oldset = obj->nodesetval;
10363 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010364
Daniel Veillardf06307e2001-07-03 10:35:50 +000010365 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010366
Daniel Veillardf06307e2001-07-03 10:35:50 +000010367 if (oldset != NULL) {
10368 for (i = 0; i < oldset->nodeNr; i++) {
10369 /*
10370 * Run the evaluation with a node list made of a single item
10371 * in the nodeset.
10372 */
10373 ctxt->context->node = oldset->nodeTab[i];
10374 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10375 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010376
Daniel Veillardf06307e2001-07-03 10:35:50 +000010377 if (op->ch2 != -1)
10378 total +=
10379 xmlXPathCompOpEval(ctxt,
10380 &comp->steps[op->ch2]);
10381 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010382
Daniel Veillardf06307e2001-07-03 10:35:50 +000010383 /*
10384 * The result of the evaluation need to be tested to
10385 * decided whether the filter succeeded or not
10386 */
10387 res = valuePop(ctxt);
10388 range =
10389 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10390 res);
10391 if (range != NULL) {
10392 xmlXPtrLocationSetAdd(newset, range);
10393 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010394
Daniel Veillardf06307e2001-07-03 10:35:50 +000010395 /*
10396 * Cleanup
10397 */
10398 if (res != NULL)
10399 xmlXPathFreeObject(res);
10400 if (ctxt->value == tmp) {
10401 res = valuePop(ctxt);
10402 xmlXPathFreeObject(res);
10403 }
10404
10405 ctxt->context->node = NULL;
10406 }
10407 }
10408
10409 /*
10410 * The result is used as the new evaluation set.
10411 */
10412 xmlXPathFreeObject(obj);
10413 ctxt->context->node = NULL;
10414 ctxt->context->contextSize = -1;
10415 ctxt->context->proximityPosition = -1;
10416 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10417 return (total);
10418 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010419#endif /* LIBXML_XPTR_ENABLED */
10420 }
10421 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010422 "XPath: unknown precompiled operation %d\n", op->op);
10423 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010424}
10425
10426/**
10427 * xmlXPathRunEval:
10428 * @ctxt: the XPath parser context with the compiled expression
10429 *
10430 * Evaluate the Precompiled XPath expression in the given context.
10431 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010432static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010433xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10434 xmlXPathCompExprPtr comp;
10435
10436 if ((ctxt == NULL) || (ctxt->comp == NULL))
10437 return;
10438
10439 if (ctxt->valueTab == NULL) {
10440 /* Allocate the value stack */
10441 ctxt->valueTab = (xmlXPathObjectPtr *)
10442 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10443 if (ctxt->valueTab == NULL) {
10444 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010445 }
10446 ctxt->valueNr = 0;
10447 ctxt->valueMax = 10;
10448 ctxt->value = NULL;
10449 }
10450 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010451 if(comp->last < 0) {
10452 xmlGenericError(xmlGenericErrorContext,
10453 "xmlXPathRunEval: last is less than zero\n");
10454 return;
10455 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010456 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10457}
10458
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010459/************************************************************************
10460 * *
10461 * Public interfaces *
10462 * *
10463 ************************************************************************/
10464
10465/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010466 * xmlXPathEvalPredicate:
10467 * @ctxt: the XPath context
10468 * @res: the Predicate Expression evaluation result
10469 *
10470 * Evaluate a predicate result for the current node.
10471 * A PredicateExpr is evaluated by evaluating the Expr and converting
10472 * the result to a boolean. If the result is a number, the result will
10473 * be converted to true if the number is equal to the position of the
10474 * context node in the context node list (as returned by the position
10475 * function) and will be converted to false otherwise; if the result
10476 * is not a number, then the result will be converted as if by a call
10477 * to the boolean function.
10478 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010479 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010480 */
10481int
10482xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10483 if (res == NULL) return(0);
10484 switch (res->type) {
10485 case XPATH_BOOLEAN:
10486 return(res->boolval);
10487 case XPATH_NUMBER:
10488 return(res->floatval == ctxt->proximityPosition);
10489 case XPATH_NODESET:
10490 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010491 if (res->nodesetval == NULL)
10492 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010493 return(res->nodesetval->nodeNr != 0);
10494 case XPATH_STRING:
10495 return((res->stringval != NULL) &&
10496 (xmlStrlen(res->stringval) != 0));
10497 default:
10498 STRANGE
10499 }
10500 return(0);
10501}
10502
10503/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010504 * xmlXPathEvaluatePredicateResult:
10505 * @ctxt: the XPath Parser context
10506 * @res: the Predicate Expression evaluation result
10507 *
10508 * Evaluate a predicate result for the current node.
10509 * A PredicateExpr is evaluated by evaluating the Expr and converting
10510 * the result to a boolean. If the result is a number, the result will
10511 * be converted to true if the number is equal to the position of the
10512 * context node in the context node list (as returned by the position
10513 * function) and will be converted to false otherwise; if the result
10514 * is not a number, then the result will be converted as if by a call
10515 * to the boolean function.
10516 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010517 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010518 */
10519int
10520xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10521 xmlXPathObjectPtr res) {
10522 if (res == NULL) return(0);
10523 switch (res->type) {
10524 case XPATH_BOOLEAN:
10525 return(res->boolval);
10526 case XPATH_NUMBER:
10527 return(res->floatval == ctxt->context->proximityPosition);
10528 case XPATH_NODESET:
10529 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010530 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010531 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010532 return(res->nodesetval->nodeNr != 0);
10533 case XPATH_STRING:
10534 return((res->stringval != NULL) &&
10535 (xmlStrlen(res->stringval) != 0));
10536 default:
10537 STRANGE
10538 }
10539 return(0);
10540}
10541
10542/**
10543 * xmlXPathCompile:
10544 * @str: the XPath expression
10545 *
10546 * Compile an XPath expression
10547 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010548 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010549 * the caller has to free the object.
10550 */
10551xmlXPathCompExprPtr
10552xmlXPathCompile(const xmlChar *str) {
10553 xmlXPathParserContextPtr ctxt;
10554 xmlXPathCompExprPtr comp;
10555
10556 xmlXPathInit();
10557
10558 ctxt = xmlXPathNewParserContext(str, NULL);
10559 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010560
Daniel Veillard40af6492001-04-22 08:50:55 +000010561 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010562 /*
10563 * aleksey: in some cases this line prints *second* error message
10564 * (see bug #78858) and probably this should be fixed.
10565 * However, we are not sure that all error messages are printed
10566 * out in other places. It's not critical so we leave it as-is for now
10567 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010568 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10569 comp = NULL;
10570 } else {
10571 comp = ctxt->comp;
10572 ctxt->comp = NULL;
10573 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010574 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010575#ifdef DEBUG_EVAL_COUNTS
10576 if (comp != NULL) {
10577 comp->string = xmlStrdup(str);
10578 comp->nb = 0;
10579 }
10580#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010581 return(comp);
10582}
10583
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010584/**
10585 * xmlXPathCompiledEval:
10586 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010587 * @ctx: the XPath context
10588 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010589 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010590 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010591 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010592 * the caller has to free the object.
10593 */
10594xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010595xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010596 xmlXPathParserContextPtr ctxt;
10597 xmlXPathObjectPtr res, tmp, init = NULL;
10598 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010599#ifndef LIBXML_THREAD_ENABLED
10600 static int reentance = 0;
10601#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010602
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010603 if ((comp == NULL) || (ctx == NULL))
10604 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010605 xmlXPathInit();
10606
10607 CHECK_CONTEXT(ctx)
10608
Daniel Veillard81463942001-10-16 12:34:39 +000010609#ifndef LIBXML_THREAD_ENABLED
10610 reentance++;
10611 if (reentance > 1)
10612 xmlXPathDisableOptimizer = 1;
10613#endif
10614
Daniel Veillardf06307e2001-07-03 10:35:50 +000010615#ifdef DEBUG_EVAL_COUNTS
10616 comp->nb++;
10617 if ((comp->string != NULL) && (comp->nb > 100)) {
10618 fprintf(stderr, "100 x %s\n", comp->string);
10619 comp->nb = 0;
10620 }
10621#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010622 ctxt = xmlXPathCompParserContext(comp, ctx);
10623 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010624
10625 if (ctxt->value == NULL) {
10626 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010627 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010628 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010629 } else {
10630 res = valuePop(ctxt);
10631 }
10632
Daniel Veillardf06307e2001-07-03 10:35:50 +000010633
Owen Taylor3473f882001-02-23 17:55:21 +000010634 do {
10635 tmp = valuePop(ctxt);
10636 if (tmp != NULL) {
10637 if (tmp != init)
10638 stack++;
10639 xmlXPathFreeObject(tmp);
10640 }
10641 } while (tmp != NULL);
10642 if ((stack != 0) && (res != NULL)) {
10643 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010644 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010645 stack);
10646 }
10647 if (ctxt->error != XPATH_EXPRESSION_OK) {
10648 xmlXPathFreeObject(res);
10649 res = NULL;
10650 }
10651
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010652
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010653 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010654 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010655#ifndef LIBXML_THREAD_ENABLED
10656 reentance--;
10657#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010658 return(res);
10659}
10660
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010661/**
10662 * xmlXPathEvalExpr:
10663 * @ctxt: the XPath Parser context
10664 *
10665 * Parse and evaluate an XPath expression in the given context,
10666 * then push the result on the context stack
10667 */
10668void
10669xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10670 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010671 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010672 xmlXPathRunEval(ctxt);
10673}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010674
10675/**
10676 * xmlXPathEval:
10677 * @str: the XPath expression
10678 * @ctx: the XPath context
10679 *
10680 * Evaluate the XPath Location Path in the given context.
10681 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010682 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683 * the caller has to free the object.
10684 */
10685xmlXPathObjectPtr
10686xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10687 xmlXPathParserContextPtr ctxt;
10688 xmlXPathObjectPtr res, tmp, init = NULL;
10689 int stack = 0;
10690
10691 xmlXPathInit();
10692
10693 CHECK_CONTEXT(ctx)
10694
10695 ctxt = xmlXPathNewParserContext(str, ctx);
10696 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010697
10698 if (ctxt->value == NULL) {
10699 xmlGenericError(xmlGenericErrorContext,
10700 "xmlXPathEval: evaluation failed\n");
10701 res = NULL;
10702 } else if (*ctxt->cur != 0) {
10703 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10704 res = NULL;
10705 } else {
10706 res = valuePop(ctxt);
10707 }
10708
10709 do {
10710 tmp = valuePop(ctxt);
10711 if (tmp != NULL) {
10712 if (tmp != init)
10713 stack++;
10714 xmlXPathFreeObject(tmp);
10715 }
10716 } while (tmp != NULL);
10717 if ((stack != 0) && (res != NULL)) {
10718 xmlGenericError(xmlGenericErrorContext,
10719 "xmlXPathEval: %d object left on the stack\n",
10720 stack);
10721 }
10722 if (ctxt->error != XPATH_EXPRESSION_OK) {
10723 xmlXPathFreeObject(res);
10724 res = NULL;
10725 }
10726
Owen Taylor3473f882001-02-23 17:55:21 +000010727 xmlXPathFreeParserContext(ctxt);
10728 return(res);
10729}
10730
10731/**
10732 * xmlXPathEvalExpression:
10733 * @str: the XPath expression
10734 * @ctxt: the XPath context
10735 *
10736 * Evaluate the XPath expression in the given context.
10737 *
10738 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10739 * the caller has to free the object.
10740 */
10741xmlXPathObjectPtr
10742xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10743 xmlXPathParserContextPtr pctxt;
10744 xmlXPathObjectPtr res, tmp;
10745 int stack = 0;
10746
10747 xmlXPathInit();
10748
10749 CHECK_CONTEXT(ctxt)
10750
10751 pctxt = xmlXPathNewParserContext(str, ctxt);
10752 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010753
10754 if (*pctxt->cur != 0) {
10755 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10756 res = NULL;
10757 } else {
10758 res = valuePop(pctxt);
10759 }
10760 do {
10761 tmp = valuePop(pctxt);
10762 if (tmp != NULL) {
10763 xmlXPathFreeObject(tmp);
10764 stack++;
10765 }
10766 } while (tmp != NULL);
10767 if ((stack != 0) && (res != NULL)) {
10768 xmlGenericError(xmlGenericErrorContext,
10769 "xmlXPathEvalExpression: %d object left on the stack\n",
10770 stack);
10771 }
10772 xmlXPathFreeParserContext(pctxt);
10773 return(res);
10774}
10775
10776/**
10777 * xmlXPathRegisterAllFunctions:
10778 * @ctxt: the XPath context
10779 *
10780 * Registers all default XPath functions in this context
10781 */
10782void
10783xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10784{
10785 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10786 xmlXPathBooleanFunction);
10787 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10788 xmlXPathCeilingFunction);
10789 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10790 xmlXPathCountFunction);
10791 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10792 xmlXPathConcatFunction);
10793 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10794 xmlXPathContainsFunction);
10795 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10796 xmlXPathIdFunction);
10797 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10798 xmlXPathFalseFunction);
10799 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10800 xmlXPathFloorFunction);
10801 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10802 xmlXPathLastFunction);
10803 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10804 xmlXPathLangFunction);
10805 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10806 xmlXPathLocalNameFunction);
10807 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10808 xmlXPathNotFunction);
10809 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10810 xmlXPathNameFunction);
10811 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10812 xmlXPathNamespaceURIFunction);
10813 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10814 xmlXPathNormalizeFunction);
10815 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10816 xmlXPathNumberFunction);
10817 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10818 xmlXPathPositionFunction);
10819 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10820 xmlXPathRoundFunction);
10821 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10822 xmlXPathStringFunction);
10823 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10824 xmlXPathStringLengthFunction);
10825 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10826 xmlXPathStartsWithFunction);
10827 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10828 xmlXPathSubstringFunction);
10829 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10830 xmlXPathSubstringBeforeFunction);
10831 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10832 xmlXPathSubstringAfterFunction);
10833 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10834 xmlXPathSumFunction);
10835 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10836 xmlXPathTrueFunction);
10837 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10838 xmlXPathTranslateFunction);
10839}
10840
10841#endif /* LIBXML_XPATH_ENABLED */