blob: eac0937143d7eb51d4780269b4452e86a13dc992 [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,
Daniel Veillard118aed72002-09-24 14:13:13 +000070 BAD_CAST "xml",
71 NULL
Daniel Veillard20ee8c02001-10-05 09:18:14 +000072};
73static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillardda423da2002-04-10 19:25:38 +000074#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +000075/*
76 * Optimizer is disabled only when threaded apps are detected while
77 * the library ain't compiled for thread safety.
78 */
79static int xmlXPathDisableOptimizer = 0;
80#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000081
Daniel Veillard9e7160d2001-03-18 23:17:47 +000082/************************************************************************
83 * *
84 * Floating point stuff *
85 * *
86 ************************************************************************/
87
Daniel Veillardc0631a62001-09-20 13:56:06 +000088#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000089#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000090#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000091#include "trionan.c"
92
Owen Taylor3473f882001-02-23 17:55:21 +000093/*
Owen Taylor3473f882001-02-23 17:55:21 +000094 * The lack of portability of this section of the libc is annoying !
95 */
96double xmlXPathNAN = 0;
97double xmlXPathPINF = 1;
98double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000099double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000100static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000101
Owen Taylor3473f882001-02-23 17:55:21 +0000102/**
103 * xmlXPathInit:
104 *
105 * Initialize the XPath environment
106 */
107void
108xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000109 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000110
Bjorn Reese45029602001-08-21 09:23:53 +0000111 xmlXPathPINF = trio_pinf();
112 xmlXPathNINF = trio_ninf();
113 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000114 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000115
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000116 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000117}
118
Daniel Veillardcda96922001-08-21 10:56:31 +0000119/**
120 * xmlXPathIsNaN:
121 * @val: a double value
122 *
123 * Provides a portable isnan() function to detect whether a double
124 * is a NotaNumber. Based on trio code
125 * http://sourceforge.net/projects/ctrio/
126 *
127 * Returns 1 if the value is a NaN, 0 otherwise
128 */
129int
130xmlXPathIsNaN(double val) {
131 return(trio_isnan(val));
132}
133
134/**
135 * xmlXPathIsInf:
136 * @val: a double value
137 *
138 * Provides a portable isinf() function to detect whether a double
139 * is a +Infinite or -Infinite. Based on trio code
140 * http://sourceforge.net/projects/ctrio/
141 *
142 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
143 */
144int
145xmlXPathIsInf(double val) {
146 return(trio_isinf(val));
147}
148
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000149/**
150 * xmlXPathGetSign:
151 * @val: a double value
152 *
153 * Provides a portable function to detect the sign of a double
154 * Modified from trio code
155 * http://sourceforge.net/projects/ctrio/
156 *
157 * Returns 1 if the value is Negative, 0 if positive
158 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000159static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000160xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000161 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000162}
163
164
Owen Taylor3473f882001-02-23 17:55:21 +0000165/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000166 * *
167 * Parser Types *
168 * *
169 ************************************************************************/
170
171/*
172 * Types are private:
173 */
174
175typedef enum {
176 XPATH_OP_END=0,
177 XPATH_OP_AND,
178 XPATH_OP_OR,
179 XPATH_OP_EQUAL,
180 XPATH_OP_CMP,
181 XPATH_OP_PLUS,
182 XPATH_OP_MULT,
183 XPATH_OP_UNION,
184 XPATH_OP_ROOT,
185 XPATH_OP_NODE,
186 XPATH_OP_RESET,
187 XPATH_OP_COLLECT,
188 XPATH_OP_VALUE,
189 XPATH_OP_VARIABLE,
190 XPATH_OP_FUNCTION,
191 XPATH_OP_ARG,
192 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000193 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000194 XPATH_OP_SORT
195#ifdef LIBXML_XPTR_ENABLED
196 ,XPATH_OP_RANGETO
197#endif
198} xmlXPathOp;
199
200typedef enum {
201 AXIS_ANCESTOR = 1,
202 AXIS_ANCESTOR_OR_SELF,
203 AXIS_ATTRIBUTE,
204 AXIS_CHILD,
205 AXIS_DESCENDANT,
206 AXIS_DESCENDANT_OR_SELF,
207 AXIS_FOLLOWING,
208 AXIS_FOLLOWING_SIBLING,
209 AXIS_NAMESPACE,
210 AXIS_PARENT,
211 AXIS_PRECEDING,
212 AXIS_PRECEDING_SIBLING,
213 AXIS_SELF
214} xmlXPathAxisVal;
215
216typedef enum {
217 NODE_TEST_NONE = 0,
218 NODE_TEST_TYPE = 1,
219 NODE_TEST_PI = 2,
220 NODE_TEST_ALL = 3,
221 NODE_TEST_NS = 4,
222 NODE_TEST_NAME = 5
223} xmlXPathTestVal;
224
225typedef enum {
226 NODE_TYPE_NODE = 0,
227 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
228 NODE_TYPE_TEXT = XML_TEXT_NODE,
229 NODE_TYPE_PI = XML_PI_NODE
230} xmlXPathTypeVal;
231
232
233typedef struct _xmlXPathStepOp xmlXPathStepOp;
234typedef xmlXPathStepOp *xmlXPathStepOpPtr;
235struct _xmlXPathStepOp {
236 xmlXPathOp op;
237 int ch1;
238 int ch2;
239 int value;
240 int value2;
241 int value3;
242 void *value4;
243 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000244 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000245 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000246};
247
248struct _xmlXPathCompExpr {
249 int nbStep;
250 int maxStep;
251 xmlXPathStepOp *steps; /* ops for computation */
252 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000253 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000254#ifdef DEBUG_EVAL_COUNTS
255 int nb;
256 xmlChar *string;
257#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000258};
259
260/************************************************************************
261 * *
262 * Parser Type functions *
263 * *
264 ************************************************************************/
265
266/**
267 * xmlXPathNewCompExpr:
268 *
269 * Create a new Xpath component
270 *
271 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
272 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000273static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000274xmlXPathNewCompExpr(void) {
275 xmlXPathCompExprPtr cur;
276
277 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
278 if (cur == NULL) {
279 xmlGenericError(xmlGenericErrorContext,
280 "xmlXPathNewCompExpr : malloc failed\n");
281 return(NULL);
282 }
283 memset(cur, 0, sizeof(xmlXPathCompExpr));
284 cur->maxStep = 10;
285 cur->nbStep = 0;
286 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
287 sizeof(xmlXPathStepOp));
288 if (cur->steps == NULL) {
289 xmlGenericError(xmlGenericErrorContext,
290 "xmlXPathNewCompExpr : malloc failed\n");
291 xmlFree(cur);
292 return(NULL);
293 }
294 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
295 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000296#ifdef DEBUG_EVAL_COUNTS
297 cur->nb = 0;
298#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000299 return(cur);
300}
301
302/**
303 * xmlXPathFreeCompExpr:
304 * @comp: an XPATH comp
305 *
306 * Free up the memory allocated by @comp
307 */
308void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000309xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
310{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000311 xmlXPathStepOpPtr op;
312 int i;
313
314 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000315 return;
316 for (i = 0; i < comp->nbStep; i++) {
317 op = &comp->steps[i];
318 if (op->value4 != NULL) {
319 if (op->op == XPATH_OP_VALUE)
320 xmlXPathFreeObject(op->value4);
321 else
322 xmlFree(op->value4);
323 }
324 if (op->value5 != NULL)
325 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000326 }
327 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000329 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000330#ifdef DEBUG_EVAL_COUNTS
331 if (comp->string != NULL) {
332 xmlFree(comp->string);
333 }
334#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000335 if (comp->expr != NULL) {
336 xmlFree(comp->expr);
337 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000338
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000339 xmlFree(comp);
340}
341
342/**
343 * xmlXPathCompExprAdd:
344 * @comp: the compiled expression
345 * @ch1: first child index
346 * @ch2: second child index
347 * @op: an op
348 * @value: the first int value
349 * @value2: the second int value
350 * @value3: the third int value
351 * @value4: the first string value
352 * @value5: the second string value
353 *
354 * Add an step to an XPath Compiled Expression
355 *
356 * Returns -1 in case of failure, the index otherwise
357 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000358static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000359xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
360 xmlXPathOp op, int value,
361 int value2, int value3, void *value4, void *value5) {
362 if (comp->nbStep >= comp->maxStep) {
363 xmlXPathStepOp *real;
364
365 comp->maxStep *= 2;
366 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
367 comp->maxStep * sizeof(xmlXPathStepOp));
368 if (real == NULL) {
369 comp->maxStep /= 2;
370 xmlGenericError(xmlGenericErrorContext,
371 "xmlXPathCompExprAdd : realloc failed\n");
372 return(-1);
373 }
374 comp->steps = real;
375 }
376 comp->last = comp->nbStep;
377 comp->steps[comp->nbStep].ch1 = ch1;
378 comp->steps[comp->nbStep].ch2 = ch2;
379 comp->steps[comp->nbStep].op = op;
380 comp->steps[comp->nbStep].value = value;
381 comp->steps[comp->nbStep].value2 = value2;
382 comp->steps[comp->nbStep].value3 = value3;
383 comp->steps[comp->nbStep].value4 = value4;
384 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000385 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000386 return(comp->nbStep++);
387}
388
Daniel Veillardf06307e2001-07-03 10:35:50 +0000389/**
390 * xmlXPathCompSwap:
391 * @comp: the compiled expression
392 * @op: operation index
393 *
394 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000395 */
396static void
397xmlXPathCompSwap(xmlXPathStepOpPtr op) {
398 int tmp;
399
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000400#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000401 /*
402 * Since this manipulates possibly shared variables, this is
403 * disable if one detects that the library is used in a multithreaded
404 * application
405 */
406 if (xmlXPathDisableOptimizer)
407 return;
408#endif
409
Daniel Veillardf06307e2001-07-03 10:35:50 +0000410 tmp = op->ch1;
411 op->ch1 = op->ch2;
412 op->ch2 = tmp;
413}
414
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000415#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
416 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
417 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000418#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
419 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
420 (op), (val), (val2), (val3), (val4), (val5))
421
422#define PUSH_LEAVE_EXPR(op, val, val2) \
423xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
424
425#define PUSH_UNARY_EXPR(op, ch, val, val2) \
426xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
427
428#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
429xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
430
431/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000432 * *
433 * Debugging related functions *
434 * *
435 ************************************************************************/
436
437#define TODO \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Unimplemented block at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#define STRANGE \
443 xmlGenericError(xmlGenericErrorContext, \
444 "Internal error at %s:%d\n", \
445 __FILE__, __LINE__);
446
447#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000448static void
449xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000450 int i;
451 char shift[100];
452
453 for (i = 0;((i < depth) && (i < 25));i++)
454 shift[2 * i] = shift[2 * i + 1] = ' ';
455 shift[2 * i] = shift[2 * i + 1] = 0;
456 if (cur == NULL) {
457 fprintf(output, shift);
458 fprintf(output, "Node is NULL !\n");
459 return;
460
461 }
462
463 if ((cur->type == XML_DOCUMENT_NODE) ||
464 (cur->type == XML_HTML_DOCUMENT_NODE)) {
465 fprintf(output, shift);
466 fprintf(output, " /\n");
467 } else if (cur->type == XML_ATTRIBUTE_NODE)
468 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
469 else
470 xmlDebugDumpOneNode(output, cur, depth);
471}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000472static void
473xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000474 xmlNodePtr tmp;
475 int i;
476 char shift[100];
477
478 for (i = 0;((i < depth) && (i < 25));i++)
479 shift[2 * i] = shift[2 * i + 1] = ' ';
480 shift[2 * i] = shift[2 * i + 1] = 0;
481 if (cur == NULL) {
482 fprintf(output, shift);
483 fprintf(output, "Node is NULL !\n");
484 return;
485
486 }
487
488 while (cur != NULL) {
489 tmp = cur;
490 cur = cur->next;
491 xmlDebugDumpOneNode(output, tmp, depth);
492 }
493}
Owen Taylor3473f882001-02-23 17:55:21 +0000494
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000495static void
496xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000497 int i;
498 char shift[100];
499
500 for (i = 0;((i < depth) && (i < 25));i++)
501 shift[2 * i] = shift[2 * i + 1] = ' ';
502 shift[2 * i] = shift[2 * i + 1] = 0;
503
504 if (cur == NULL) {
505 fprintf(output, shift);
506 fprintf(output, "NodeSet is NULL !\n");
507 return;
508
509 }
510
Daniel Veillard911f49a2001-04-07 15:39:35 +0000511 if (cur != NULL) {
512 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
513 for (i = 0;i < cur->nodeNr;i++) {
514 fprintf(output, shift);
515 fprintf(output, "%d", i + 1);
516 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
517 }
Owen Taylor3473f882001-02-23 17:55:21 +0000518 }
519}
520
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000521static void
522xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000523 int i;
524 char shift[100];
525
526 for (i = 0;((i < depth) && (i < 25));i++)
527 shift[2 * i] = shift[2 * i + 1] = ' ';
528 shift[2 * i] = shift[2 * i + 1] = 0;
529
530 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
531 fprintf(output, shift);
532 fprintf(output, "Value Tree is NULL !\n");
533 return;
534
535 }
536
537 fprintf(output, shift);
538 fprintf(output, "%d", i + 1);
539 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
540}
Owen Taylor3473f882001-02-23 17:55:21 +0000541#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000542static void
543xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000544 int i;
545 char shift[100];
546
547 for (i = 0;((i < depth) && (i < 25));i++)
548 shift[2 * i] = shift[2 * i + 1] = ' ';
549 shift[2 * i] = shift[2 * i + 1] = 0;
550
551 if (cur == NULL) {
552 fprintf(output, shift);
553 fprintf(output, "LocationSet is NULL !\n");
554 return;
555
556 }
557
558 for (i = 0;i < cur->locNr;i++) {
559 fprintf(output, shift);
560 fprintf(output, "%d : ", i + 1);
561 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
562 }
563}
Daniel Veillard017b1082001-06-21 11:20:21 +0000564#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000565
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000566/**
567 * xmlXPathDebugDumpObject:
568 * @output: the FILE * to dump the output
569 * @cur: the object to inspect
570 * @depth: indentation level
571 *
572 * Dump the content of the object for debugging purposes
573 */
574void
575xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000576 int i;
577 char shift[100];
578
579 for (i = 0;((i < depth) && (i < 25));i++)
580 shift[2 * i] = shift[2 * i + 1] = ' ';
581 shift[2 * i] = shift[2 * i + 1] = 0;
582
583 fprintf(output, shift);
584
585 if (cur == NULL) {
586 fprintf(output, "Object is empty (NULL)\n");
587 return;
588 }
589 switch(cur->type) {
590 case XPATH_UNDEFINED:
591 fprintf(output, "Object is uninitialized\n");
592 break;
593 case XPATH_NODESET:
594 fprintf(output, "Object is a Node Set :\n");
595 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
596 break;
597 case XPATH_XSLT_TREE:
598 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000599 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000600 break;
601 case XPATH_BOOLEAN:
602 fprintf(output, "Object is a Boolean : ");
603 if (cur->boolval) fprintf(output, "true\n");
604 else fprintf(output, "false\n");
605 break;
606 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000607 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000608 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000609 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000610 break;
611 case -1:
612 fprintf(output, "Object is a number : -Infinity\n");
613 break;
614 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000615 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000616 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000617 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
618 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000619 } else {
620 fprintf(output, "Object is a number : %0g\n", cur->floatval);
621 }
622 }
Owen Taylor3473f882001-02-23 17:55:21 +0000623 break;
624 case XPATH_STRING:
625 fprintf(output, "Object is a string : ");
626 xmlDebugDumpString(output, cur->stringval);
627 fprintf(output, "\n");
628 break;
629 case XPATH_POINT:
630 fprintf(output, "Object is a point : index %d in node", cur->index);
631 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
632 fprintf(output, "\n");
633 break;
634 case XPATH_RANGE:
635 if ((cur->user2 == NULL) ||
636 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
637 fprintf(output, "Object is a collapsed range :\n");
638 fprintf(output, shift);
639 if (cur->index >= 0)
640 fprintf(output, "index %d in ", cur->index);
641 fprintf(output, "node\n");
642 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
643 depth + 1);
644 } else {
645 fprintf(output, "Object is a range :\n");
646 fprintf(output, shift);
647 fprintf(output, "From ");
648 if (cur->index >= 0)
649 fprintf(output, "index %d in ", cur->index);
650 fprintf(output, "node\n");
651 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
652 depth + 1);
653 fprintf(output, shift);
654 fprintf(output, "To ");
655 if (cur->index2 >= 0)
656 fprintf(output, "index %d in ", cur->index2);
657 fprintf(output, "node\n");
658 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
659 depth + 1);
660 fprintf(output, "\n");
661 }
662 break;
663 case XPATH_LOCATIONSET:
664#if defined(LIBXML_XPTR_ENABLED)
665 fprintf(output, "Object is a Location Set:\n");
666 xmlXPathDebugDumpLocationSet(output,
667 (xmlLocationSetPtr) cur->user, depth);
668#endif
669 break;
670 case XPATH_USERS:
671 fprintf(output, "Object is user defined\n");
672 break;
673 }
674}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000675
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000676static void
677xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000678 xmlXPathStepOpPtr op, int depth) {
679 int i;
680 char shift[100];
681
682 for (i = 0;((i < depth) && (i < 25));i++)
683 shift[2 * i] = shift[2 * i + 1] = ' ';
684 shift[2 * i] = shift[2 * i + 1] = 0;
685
686 fprintf(output, shift);
687 if (op == NULL) {
688 fprintf(output, "Step is NULL\n");
689 return;
690 }
691 switch (op->op) {
692 case XPATH_OP_END:
693 fprintf(output, "END"); break;
694 case XPATH_OP_AND:
695 fprintf(output, "AND"); break;
696 case XPATH_OP_OR:
697 fprintf(output, "OR"); break;
698 case XPATH_OP_EQUAL:
699 if (op->value)
700 fprintf(output, "EQUAL =");
701 else
702 fprintf(output, "EQUAL !=");
703 break;
704 case XPATH_OP_CMP:
705 if (op->value)
706 fprintf(output, "CMP <");
707 else
708 fprintf(output, "CMP >");
709 if (!op->value2)
710 fprintf(output, "=");
711 break;
712 case XPATH_OP_PLUS:
713 if (op->value == 0)
714 fprintf(output, "PLUS -");
715 else if (op->value == 1)
716 fprintf(output, "PLUS +");
717 else if (op->value == 2)
718 fprintf(output, "PLUS unary -");
719 else if (op->value == 3)
720 fprintf(output, "PLUS unary - -");
721 break;
722 case XPATH_OP_MULT:
723 if (op->value == 0)
724 fprintf(output, "MULT *");
725 else if (op->value == 1)
726 fprintf(output, "MULT div");
727 else
728 fprintf(output, "MULT mod");
729 break;
730 case XPATH_OP_UNION:
731 fprintf(output, "UNION"); break;
732 case XPATH_OP_ROOT:
733 fprintf(output, "ROOT"); break;
734 case XPATH_OP_NODE:
735 fprintf(output, "NODE"); break;
736 case XPATH_OP_RESET:
737 fprintf(output, "RESET"); break;
738 case XPATH_OP_SORT:
739 fprintf(output, "SORT"); break;
740 case XPATH_OP_COLLECT: {
741 xmlXPathAxisVal axis = op->value;
742 xmlXPathTestVal test = op->value2;
743 xmlXPathTypeVal type = op->value3;
744 const xmlChar *prefix = op->value4;
745 const xmlChar *name = op->value5;
746
747 fprintf(output, "COLLECT ");
748 switch (axis) {
749 case AXIS_ANCESTOR:
750 fprintf(output, " 'ancestors' "); break;
751 case AXIS_ANCESTOR_OR_SELF:
752 fprintf(output, " 'ancestors-or-self' "); break;
753 case AXIS_ATTRIBUTE:
754 fprintf(output, " 'attributes' "); break;
755 case AXIS_CHILD:
756 fprintf(output, " 'child' "); break;
757 case AXIS_DESCENDANT:
758 fprintf(output, " 'descendant' "); break;
759 case AXIS_DESCENDANT_OR_SELF:
760 fprintf(output, " 'descendant-or-self' "); break;
761 case AXIS_FOLLOWING:
762 fprintf(output, " 'following' "); break;
763 case AXIS_FOLLOWING_SIBLING:
764 fprintf(output, " 'following-siblings' "); break;
765 case AXIS_NAMESPACE:
766 fprintf(output, " 'namespace' "); break;
767 case AXIS_PARENT:
768 fprintf(output, " 'parent' "); break;
769 case AXIS_PRECEDING:
770 fprintf(output, " 'preceding' "); break;
771 case AXIS_PRECEDING_SIBLING:
772 fprintf(output, " 'preceding-sibling' "); break;
773 case AXIS_SELF:
774 fprintf(output, " 'self' "); break;
775 }
776 switch (test) {
777 case NODE_TEST_NONE:
778 fprintf(output, "'none' "); break;
779 case NODE_TEST_TYPE:
780 fprintf(output, "'type' "); break;
781 case NODE_TEST_PI:
782 fprintf(output, "'PI' "); break;
783 case NODE_TEST_ALL:
784 fprintf(output, "'all' "); break;
785 case NODE_TEST_NS:
786 fprintf(output, "'namespace' "); break;
787 case NODE_TEST_NAME:
788 fprintf(output, "'name' "); break;
789 }
790 switch (type) {
791 case NODE_TYPE_NODE:
792 fprintf(output, "'node' "); break;
793 case NODE_TYPE_COMMENT:
794 fprintf(output, "'comment' "); break;
795 case NODE_TYPE_TEXT:
796 fprintf(output, "'text' "); break;
797 case NODE_TYPE_PI:
798 fprintf(output, "'PI' "); break;
799 }
800 if (prefix != NULL)
801 fprintf(output, "%s:", prefix);
802 if (name != NULL)
803 fprintf(output, "%s", name);
804 break;
805
806 }
807 case XPATH_OP_VALUE: {
808 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
809
810 fprintf(output, "ELEM ");
811 xmlXPathDebugDumpObject(output, object, 0);
812 goto finish;
813 }
814 case XPATH_OP_VARIABLE: {
815 const xmlChar *prefix = op->value5;
816 const xmlChar *name = op->value4;
817
818 if (prefix != NULL)
819 fprintf(output, "VARIABLE %s:%s", prefix, name);
820 else
821 fprintf(output, "VARIABLE %s", name);
822 break;
823 }
824 case XPATH_OP_FUNCTION: {
825 int nbargs = op->value;
826 const xmlChar *prefix = op->value5;
827 const xmlChar *name = op->value4;
828
829 if (prefix != NULL)
830 fprintf(output, "FUNCTION %s:%s(%d args)",
831 prefix, name, nbargs);
832 else
833 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
834 break;
835 }
836 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
837 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000838 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000839#ifdef LIBXML_XPTR_ENABLED
840 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
841#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000842 default:
843 fprintf(output, "UNKNOWN %d\n", op->op); return;
844 }
845 fprintf(output, "\n");
846finish:
847 if (op->ch1 >= 0)
848 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
849 if (op->ch2 >= 0)
850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
851}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000852
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000853/**
854 * xmlXPathDebugDumpCompExpr:
855 * @output: the FILE * for the output
856 * @comp: the precompiled XPath expression
857 * @depth: the indentation level.
858 *
859 * Dumps the tree of the compiled XPath expression.
860 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000861void
862xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
863 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000864 int i;
865 char shift[100];
866
867 for (i = 0;((i < depth) && (i < 25));i++)
868 shift[2 * i] = shift[2 * i + 1] = ' ';
869 shift[2 * i] = shift[2 * i + 1] = 0;
870
871 fprintf(output, shift);
872
873 if (comp == NULL) {
874 fprintf(output, "Compiled Expression is NULL\n");
875 return;
876 }
877 fprintf(output, "Compiled Expression : %d elements\n",
878 comp->nbStep);
879 i = comp->last;
880 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
881}
Daniel Veillard017b1082001-06-21 11:20:21 +0000882#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000883
884/************************************************************************
885 * *
886 * Parser stacks related functions and macros *
887 * *
888 ************************************************************************/
889
890/*
891 * Generic function for accessing stacks in the Parser Context
892 */
893
894#define PUSH_AND_POP(type, name) \
895extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
896 if (ctxt->name##Nr >= ctxt->name##Max) { \
897 ctxt->name##Max *= 2; \
898 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
899 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
900 if (ctxt->name##Tab == NULL) { \
901 xmlGenericError(xmlGenericErrorContext, \
902 "realloc failed !\n"); \
903 return(0); \
904 } \
905 } \
906 ctxt->name##Tab[ctxt->name##Nr] = value; \
907 ctxt->name = value; \
908 return(ctxt->name##Nr++); \
909} \
910extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
911 type ret; \
912 if (ctxt->name##Nr <= 0) return(0); \
913 ctxt->name##Nr--; \
914 if (ctxt->name##Nr > 0) \
915 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
916 else \
917 ctxt->name = NULL; \
918 ret = ctxt->name##Tab[ctxt->name##Nr]; \
919 ctxt->name##Tab[ctxt->name##Nr] = 0; \
920 return(ret); \
921} \
922
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000923/**
924 * valuePop:
925 * @ctxt: an XPath evaluation context
926 *
927 * Pops the top XPath object from the value stack
928 *
929 * Returns the XPath object just removed
930 */
931/**
932 * valuePush:
933 * @ctxt: an XPath evaluation context
934 * @value: the XPath object
935 *
936 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000937 *
938 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000939 */
Owen Taylor3473f882001-02-23 17:55:21 +0000940PUSH_AND_POP(xmlXPathObjectPtr, value)
941
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000942/**
943 * xmlXPathPopBoolean:
944 * @ctxt: an XPath parser context
945 *
946 * Pops a boolean from the stack, handling conversion if needed.
947 * Check error with #xmlXPathCheckError.
948 *
949 * Returns the boolean
950 */
951int
952xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
953 xmlXPathObjectPtr obj;
954 int ret;
955
956 obj = valuePop(ctxt);
957 if (obj == NULL) {
958 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
959 return(0);
960 }
961 ret = xmlXPathCastToBoolean(obj);
962 xmlXPathFreeObject(obj);
963 return(ret);
964}
965
966/**
967 * xmlXPathPopNumber:
968 * @ctxt: an XPath parser context
969 *
970 * Pops a number from the stack, handling conversion if needed.
971 * Check error with #xmlXPathCheckError.
972 *
973 * Returns the number
974 */
975double
976xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
977 xmlXPathObjectPtr obj;
978 double ret;
979
980 obj = valuePop(ctxt);
981 if (obj == NULL) {
982 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
983 return(0);
984 }
985 ret = xmlXPathCastToNumber(obj);
986 xmlXPathFreeObject(obj);
987 return(ret);
988}
989
990/**
991 * xmlXPathPopString:
992 * @ctxt: an XPath parser context
993 *
994 * Pops a string from the stack, handling conversion if needed.
995 * Check error with #xmlXPathCheckError.
996 *
997 * Returns the string
998 */
999xmlChar *
1000xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1001 xmlXPathObjectPtr obj;
1002 xmlChar * ret;
1003
1004 obj = valuePop(ctxt);
1005 if (obj == NULL) {
1006 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1007 return(NULL);
1008 }
1009 ret = xmlXPathCastToString(obj);
1010 /* TODO: needs refactoring somewhere else */
1011 if (obj->stringval == ret)
1012 obj->stringval = NULL;
1013 xmlXPathFreeObject(obj);
1014 return(ret);
1015}
1016
1017/**
1018 * xmlXPathPopNodeSet:
1019 * @ctxt: an XPath parser context
1020 *
1021 * Pops a node-set from the stack, handling conversion if needed.
1022 * Check error with #xmlXPathCheckError.
1023 *
1024 * Returns the node-set
1025 */
1026xmlNodeSetPtr
1027xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1028 xmlXPathObjectPtr obj;
1029 xmlNodeSetPtr ret;
1030
1031 if (ctxt->value == NULL) {
1032 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1033 return(NULL);
1034 }
1035 if (!xmlXPathStackIsNodeSet(ctxt)) {
1036 xmlXPathSetTypeError(ctxt);
1037 return(NULL);
1038 }
1039 obj = valuePop(ctxt);
1040 ret = obj->nodesetval;
1041 xmlXPathFreeNodeSetList(obj);
1042 return(ret);
1043}
1044
1045/**
1046 * xmlXPathPopExternal:
1047 * @ctxt: an XPath parser context
1048 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001049 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001050 * Check error with #xmlXPathCheckError.
1051 *
1052 * Returns the object
1053 */
1054void *
1055xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1056 xmlXPathObjectPtr obj;
1057 void * ret;
1058
1059 if (ctxt->value == NULL) {
1060 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1061 return(NULL);
1062 }
1063 if (ctxt->value->type != XPATH_USERS) {
1064 xmlXPathSetTypeError(ctxt);
1065 return(NULL);
1066 }
1067 obj = valuePop(ctxt);
1068 ret = obj->user;
1069 xmlXPathFreeObject(obj);
1070 return(ret);
1071}
1072
Owen Taylor3473f882001-02-23 17:55:21 +00001073/*
1074 * Macros for accessing the content. Those should be used only by the parser,
1075 * and not exported.
1076 *
1077 * Dirty macros, i.e. one need to make assumption on the context to use them
1078 *
1079 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1080 * CUR returns the current xmlChar value, i.e. a 8 bit value
1081 * in ISO-Latin or UTF-8.
1082 * This should be used internally by the parser
1083 * only to compare to ASCII values otherwise it would break when
1084 * running with UTF-8 encoding.
1085 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1086 * to compare on ASCII based substring.
1087 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1088 * strings within the parser.
1089 * CURRENT Returns the current char value, with the full decoding of
1090 * UTF-8 if we are using this mode. It returns an int.
1091 * NEXT Skip to the next character, this does the proper decoding
1092 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1093 * It returns the pointer to the current xmlChar.
1094 */
1095
1096#define CUR (*ctxt->cur)
1097#define SKIP(val) ctxt->cur += (val)
1098#define NXT(val) ctxt->cur[(val)]
1099#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001100#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1101
1102#define COPY_BUF(l,b,i,v) \
1103 if (l == 1) b[i++] = (xmlChar) v; \
1104 else i += xmlCopyChar(l,&b[i],v)
1105
1106#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001107
1108#define SKIP_BLANKS \
1109 while (IS_BLANK(*(ctxt->cur))) NEXT
1110
1111#define CURRENT (*ctxt->cur)
1112#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1113
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001114
1115#ifndef DBL_DIG
1116#define DBL_DIG 16
1117#endif
1118#ifndef DBL_EPSILON
1119#define DBL_EPSILON 1E-9
1120#endif
1121
1122#define UPPER_DOUBLE 1E9
1123#define LOWER_DOUBLE 1E-5
1124
1125#define INTEGER_DIGITS DBL_DIG
1126#define FRACTION_DIGITS (DBL_DIG + 1)
1127#define EXPONENT_DIGITS (3 + 2)
1128
1129/**
1130 * xmlXPathFormatNumber:
1131 * @number: number to format
1132 * @buffer: output buffer
1133 * @buffersize: size of output buffer
1134 *
1135 * Convert the number into a string representation.
1136 */
1137static void
1138xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1139{
Daniel Veillardcda96922001-08-21 10:56:31 +00001140 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001141 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001142 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001143 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001144 break;
1145 case -1:
1146 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001147 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001148 break;
1149 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001150 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001151 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001152 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001153 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001154 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001155 } else if (number == ((int) number)) {
1156 char work[30];
1157 char *ptr, *cur;
1158 int res, value = (int) number;
1159
1160 ptr = &buffer[0];
1161 if (value < 0) {
1162 *ptr++ = '-';
1163 value = -value;
1164 }
1165 if (value == 0) {
1166 *ptr++ = '0';
1167 } else {
1168 cur = &work[0];
1169 while (value != 0) {
1170 res = value % 10;
1171 value = value / 10;
1172 *cur++ = '0' + res;
1173 }
1174 cur--;
1175 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1176 *ptr++ = *cur--;
1177 }
1178 }
1179 if (ptr - buffer < buffersize) {
1180 *ptr = 0;
1181 } else if (buffersize > 0) {
1182 ptr--;
1183 *ptr = 0;
1184 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001185 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001186 /* 3 is sign, decimal point, and terminating zero */
1187 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1188 int integer_place, fraction_place;
1189 char *ptr;
1190 char *after_fraction;
1191 double absolute_value;
1192 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001193
Bjorn Reese70a9da52001-04-21 16:57:29 +00001194 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001195
Bjorn Reese70a9da52001-04-21 16:57:29 +00001196 /*
1197 * First choose format - scientific or regular floating point.
1198 * In either case, result is in work, and after_fraction points
1199 * just past the fractional part.
1200 */
1201 if ( ((absolute_value > UPPER_DOUBLE) ||
1202 (absolute_value < LOWER_DOUBLE)) &&
1203 (absolute_value != 0.0) ) {
1204 /* Use scientific notation */
1205 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1206 fraction_place = DBL_DIG - 1;
1207 snprintf(work, sizeof(work),"%*.*e",
1208 integer_place, fraction_place, number);
1209 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001210 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001211 else {
1212 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001213 if (absolute_value > 0.0)
1214 integer_place = 1 + (int)log10(absolute_value);
1215 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001216 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001217 fraction_place = (integer_place > 0)
1218 ? DBL_DIG - integer_place
1219 : DBL_DIG;
1220 size = snprintf(work, sizeof(work), "%0.*f",
1221 fraction_place, number);
1222 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001223 }
1224
Bjorn Reese70a9da52001-04-21 16:57:29 +00001225 /* Remove fractional trailing zeroes */
1226 ptr = after_fraction;
1227 while (*(--ptr) == '0')
1228 ;
1229 if (*ptr != '.')
1230 ptr++;
1231 strcpy(ptr, after_fraction);
1232
1233 /* Finally copy result back to caller */
1234 size = strlen(work) + 1;
1235 if (size > buffersize) {
1236 work[buffersize - 1] = 0;
1237 size = buffersize;
1238 }
1239 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001240 }
1241 break;
1242 }
1243}
1244
Owen Taylor3473f882001-02-23 17:55:21 +00001245/************************************************************************
1246 * *
1247 * Error handling routines *
1248 * *
1249 ************************************************************************/
1250
1251
Daniel Veillardb44025c2001-10-11 22:55:55 +00001252static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001253 "Ok",
1254 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001255 "Unfinished literal",
1256 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001257 "Expected $ for variable reference",
1258 "Undefined variable",
1259 "Invalid predicate",
1260 "Invalid expression",
1261 "Missing closing curly brace",
1262 "Unregistered function",
1263 "Invalid operand",
1264 "Invalid type",
1265 "Invalid number of arguments",
1266 "Invalid context size",
1267 "Invalid context position",
1268 "Memory allocation error",
1269 "Syntax error",
1270 "Resource error",
1271 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001272 "Undefined namespace prefix",
1273 "Encoding error",
1274 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001275};
1276
1277/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001278 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001279 * @ctxt: the XPath Parser context
1280 * @file: the file name
1281 * @line: the line number
1282 * @no: the error number
1283 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001284 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001285 */
1286void
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001287xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1288 int line ATTRIBUTE_UNUSED, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001289 int n;
1290 const xmlChar *cur;
1291 const xmlChar *base;
1292
Owen Taylor3473f882001-02-23 17:55:21 +00001293 cur = ctxt->cur;
1294 base = ctxt->base;
Daniel Veillard118aed72002-09-24 14:13:13 +00001295 if ((cur == NULL) || (base == NULL)) {
1296 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1297 xmlGenericError(xmlGenericErrorContext,
1298 "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1299 ctxt->comp->expr);
1300 } else {
1301 xmlGenericError(xmlGenericErrorContext,
1302 "XPath error %s\n", xmlXPathErrorMessages[no]);
1303 }
1304
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001305 return;
Daniel Veillard118aed72002-09-24 14:13:13 +00001306 }
1307 xmlGenericError(xmlGenericErrorContext,
1308 "XPath error %s\n", xmlXPathErrorMessages[no]);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001309
Owen Taylor3473f882001-02-23 17:55:21 +00001310 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1311 cur--;
1312 }
1313 n = 0;
1314 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1315 cur--;
1316 if ((*cur == '\n') || (*cur == '\r')) cur++;
1317 base = cur;
1318 n = 0;
1319 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1320 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1321 n++;
1322 }
1323 xmlGenericError(xmlGenericErrorContext, "\n");
1324 cur = ctxt->cur;
1325 while ((*cur == '\n') || (*cur == '\r'))
1326 cur--;
1327 n = 0;
1328 while ((cur != base) && (n++ < 80)) {
1329 xmlGenericError(xmlGenericErrorContext, " ");
1330 base++;
1331 }
1332 xmlGenericError(xmlGenericErrorContext,"^\n");
1333}
1334
1335
1336/************************************************************************
1337 * *
1338 * Routines to handle NodeSets *
1339 * *
1340 ************************************************************************/
1341
1342/**
1343 * xmlXPathCmpNodes:
1344 * @node1: the first node
1345 * @node2: the second node
1346 *
1347 * Compare two nodes w.r.t document order
1348 *
1349 * Returns -2 in case of error 1 if first point < second point, 0 if
1350 * that's the same node, -1 otherwise
1351 */
1352int
1353xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1354 int depth1, depth2;
1355 xmlNodePtr cur, root;
1356
1357 if ((node1 == NULL) || (node2 == NULL))
1358 return(-2);
1359 /*
1360 * a couple of optimizations which will avoid computations in most cases
1361 */
1362 if (node1 == node2)
1363 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001364 if ((node1->type == XML_NAMESPACE_DECL) ||
1365 (node2->type == XML_NAMESPACE_DECL))
1366 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001367 if (node1 == node2->prev)
1368 return(1);
1369 if (node1 == node2->next)
1370 return(-1);
1371
1372 /*
1373 * compute depth to root
1374 */
1375 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1376 if (cur == node1)
1377 return(1);
1378 depth2++;
1379 }
1380 root = cur;
1381 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1382 if (cur == node2)
1383 return(-1);
1384 depth1++;
1385 }
1386 /*
1387 * Distinct document (or distinct entities :-( ) case.
1388 */
1389 if (root != cur) {
1390 return(-2);
1391 }
1392 /*
1393 * get the nearest common ancestor.
1394 */
1395 while (depth1 > depth2) {
1396 depth1--;
1397 node1 = node1->parent;
1398 }
1399 while (depth2 > depth1) {
1400 depth2--;
1401 node2 = node2->parent;
1402 }
1403 while (node1->parent != node2->parent) {
1404 node1 = node1->parent;
1405 node2 = node2->parent;
1406 /* should not happen but just in case ... */
1407 if ((node1 == NULL) || (node2 == NULL))
1408 return(-2);
1409 }
1410 /*
1411 * Find who's first.
1412 */
1413 if (node1 == node2->next)
1414 return(-1);
1415 for (cur = node1->next;cur != NULL;cur = cur->next)
1416 if (cur == node2)
1417 return(1);
1418 return(-1); /* assume there is no sibling list corruption */
1419}
1420
1421/**
1422 * xmlXPathNodeSetSort:
1423 * @set: the node set
1424 *
1425 * Sort the node set in document order
1426 */
1427void
1428xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001429 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001430 xmlNodePtr tmp;
1431
1432 if (set == NULL)
1433 return;
1434
1435 /* Use Shell's sort to sort the node-set */
1436 len = set->nodeNr;
1437 for (incr = len / 2; incr > 0; incr /= 2) {
1438 for (i = incr; i < len; i++) {
1439 j = i - incr;
1440 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001441 if (xmlXPathCmpNodes(set->nodeTab[j],
1442 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001443 tmp = set->nodeTab[j];
1444 set->nodeTab[j] = set->nodeTab[j + incr];
1445 set->nodeTab[j + incr] = tmp;
1446 j -= incr;
1447 } else
1448 break;
1449 }
1450 }
1451 }
1452}
1453
1454#define XML_NODESET_DEFAULT 10
1455/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001456 * xmlXPathNodeSetDupNs:
1457 * @node: the parent node of the namespace XPath node
1458 * @ns: the libxml namespace declaration node.
1459 *
1460 * Namespace node in libxml don't match the XPath semantic. In a node set
1461 * the namespace nodes are duplicated and the next pointer is set to the
1462 * parent node in the XPath semantic.
1463 *
1464 * Returns the newly created object.
1465 */
1466static xmlNodePtr
1467xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1468 xmlNsPtr cur;
1469
1470 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1471 return(NULL);
1472 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1473 return((xmlNodePtr) ns);
1474
1475 /*
1476 * Allocate a new Namespace and fill the fields.
1477 */
1478 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1479 if (cur == NULL) {
1480 xmlGenericError(xmlGenericErrorContext,
1481 "xmlXPathNodeSetDupNs : malloc failed\n");
1482 return(NULL);
1483 }
1484 memset(cur, 0, sizeof(xmlNs));
1485 cur->type = XML_NAMESPACE_DECL;
1486 if (ns->href != NULL)
1487 cur->href = xmlStrdup(ns->href);
1488 if (ns->prefix != NULL)
1489 cur->prefix = xmlStrdup(ns->prefix);
1490 cur->next = (xmlNsPtr) node;
1491 return((xmlNodePtr) cur);
1492}
1493
1494/**
1495 * xmlXPathNodeSetFreeNs:
1496 * @ns: the XPath namespace node found in a nodeset.
1497 *
1498 * Namespace node in libxml don't match the XPath semantic. In a node set
1499 * the namespace nodes are duplicated and the next pointer is set to the
1500 * parent node in the XPath semantic. Check if such a node need to be freed
1501 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001502void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001503xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1504 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1505 return;
1506
1507 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1508 if (ns->href != NULL)
1509 xmlFree((xmlChar *)ns->href);
1510 if (ns->prefix != NULL)
1511 xmlFree((xmlChar *)ns->prefix);
1512 xmlFree(ns);
1513 }
1514}
1515
1516/**
Owen Taylor3473f882001-02-23 17:55:21 +00001517 * xmlXPathNodeSetCreate:
1518 * @val: an initial xmlNodePtr, or NULL
1519 *
1520 * Create a new xmlNodeSetPtr of type double and of value @val
1521 *
1522 * Returns the newly created object.
1523 */
1524xmlNodeSetPtr
1525xmlXPathNodeSetCreate(xmlNodePtr val) {
1526 xmlNodeSetPtr ret;
1527
1528 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1529 if (ret == NULL) {
1530 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001531 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001532 return(NULL);
1533 }
1534 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1535 if (val != NULL) {
1536 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1537 sizeof(xmlNodePtr));
1538 if (ret->nodeTab == NULL) {
1539 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001540 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001541 return(NULL);
1542 }
1543 memset(ret->nodeTab, 0 ,
1544 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1545 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001546 if (val->type == XML_NAMESPACE_DECL) {
1547 xmlNsPtr ns = (xmlNsPtr) val;
1548
1549 ret->nodeTab[ret->nodeNr++] =
1550 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1551 } else
1552 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001553 }
1554 return(ret);
1555}
1556
1557/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001558 * xmlXPathNodeSetContains:
1559 * @cur: the node-set
1560 * @val: the node
1561 *
1562 * checks whether @cur contains @val
1563 *
1564 * Returns true (1) if @cur contains @val, false (0) otherwise
1565 */
1566int
1567xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1568 int i;
1569
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001570 if (val->type == XML_NAMESPACE_DECL) {
1571 for (i = 0; i < cur->nodeNr; i++) {
1572 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1573 xmlNsPtr ns1, ns2;
1574
1575 ns1 = (xmlNsPtr) val;
1576 ns2 = (xmlNsPtr) cur->nodeTab[i];
1577 if (ns1 == ns2)
1578 return(1);
1579 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1580 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1581 return(1);
1582 }
1583 }
1584 } else {
1585 for (i = 0; i < cur->nodeNr; i++) {
1586 if (cur->nodeTab[i] == val)
1587 return(1);
1588 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001589 }
1590 return(0);
1591}
1592
1593/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001594 * xmlXPathNodeSetAddNs:
1595 * @cur: the initial node set
1596 * @node: the hosting node
1597 * @ns: a the namespace node
1598 *
1599 * add a new namespace node to an existing NodeSet
1600 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001601void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001602xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1603 int i;
1604
1605 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1606 (node->type != XML_ELEMENT_NODE))
1607 return;
1608
1609 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1610 /*
1611 * check against doublons
1612 */
1613 for (i = 0;i < cur->nodeNr;i++) {
1614 if ((cur->nodeTab[i] != NULL) &&
1615 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001616 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001617 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1618 return;
1619 }
1620
1621 /*
1622 * grow the nodeTab if needed
1623 */
1624 if (cur->nodeMax == 0) {
1625 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1626 sizeof(xmlNodePtr));
1627 if (cur->nodeTab == NULL) {
1628 xmlGenericError(xmlGenericErrorContext,
1629 "xmlXPathNodeSetAdd: out of memory\n");
1630 return;
1631 }
1632 memset(cur->nodeTab, 0 ,
1633 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1634 cur->nodeMax = XML_NODESET_DEFAULT;
1635 } else if (cur->nodeNr == cur->nodeMax) {
1636 xmlNodePtr *temp;
1637
1638 cur->nodeMax *= 2;
1639 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1640 sizeof(xmlNodePtr));
1641 if (temp == NULL) {
1642 xmlGenericError(xmlGenericErrorContext,
1643 "xmlXPathNodeSetAdd: out of memory\n");
1644 return;
1645 }
1646 cur->nodeTab = temp;
1647 }
1648 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1649}
1650
1651/**
Owen Taylor3473f882001-02-23 17:55:21 +00001652 * xmlXPathNodeSetAdd:
1653 * @cur: the initial node set
1654 * @val: a new xmlNodePtr
1655 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001656 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001657 */
1658void
1659xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1660 int i;
1661
1662 if (val == NULL) return;
1663
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001664 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001665 /*
1666 * check against doublons
1667 */
1668 for (i = 0;i < cur->nodeNr;i++)
1669 if (cur->nodeTab[i] == val) return;
1670
1671 /*
1672 * grow the nodeTab if needed
1673 */
1674 if (cur->nodeMax == 0) {
1675 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1676 sizeof(xmlNodePtr));
1677 if (cur->nodeTab == NULL) {
1678 xmlGenericError(xmlGenericErrorContext,
1679 "xmlXPathNodeSetAdd: out of memory\n");
1680 return;
1681 }
1682 memset(cur->nodeTab, 0 ,
1683 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1684 cur->nodeMax = XML_NODESET_DEFAULT;
1685 } else if (cur->nodeNr == cur->nodeMax) {
1686 xmlNodePtr *temp;
1687
1688 cur->nodeMax *= 2;
1689 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1690 sizeof(xmlNodePtr));
1691 if (temp == NULL) {
1692 xmlGenericError(xmlGenericErrorContext,
1693 "xmlXPathNodeSetAdd: out of memory\n");
1694 return;
1695 }
1696 cur->nodeTab = temp;
1697 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001698 if (val->type == XML_NAMESPACE_DECL) {
1699 xmlNsPtr ns = (xmlNsPtr) val;
1700
1701 cur->nodeTab[cur->nodeNr++] =
1702 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1703 } else
1704 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001705}
1706
1707/**
1708 * xmlXPathNodeSetAddUnique:
1709 * @cur: the initial node set
1710 * @val: a new xmlNodePtr
1711 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001712 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001713 * when we are sure the node is not already in the set.
1714 */
1715void
1716xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1717 if (val == NULL) return;
1718
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001719 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001720 /*
1721 * grow the nodeTab if needed
1722 */
1723 if (cur->nodeMax == 0) {
1724 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1725 sizeof(xmlNodePtr));
1726 if (cur->nodeTab == NULL) {
1727 xmlGenericError(xmlGenericErrorContext,
1728 "xmlXPathNodeSetAddUnique: out of memory\n");
1729 return;
1730 }
1731 memset(cur->nodeTab, 0 ,
1732 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1733 cur->nodeMax = XML_NODESET_DEFAULT;
1734 } else if (cur->nodeNr == cur->nodeMax) {
1735 xmlNodePtr *temp;
1736
1737 cur->nodeMax *= 2;
1738 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1739 sizeof(xmlNodePtr));
1740 if (temp == NULL) {
1741 xmlGenericError(xmlGenericErrorContext,
1742 "xmlXPathNodeSetAddUnique: out of memory\n");
1743 return;
1744 }
1745 cur->nodeTab = temp;
1746 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001747 if (val->type == XML_NAMESPACE_DECL) {
1748 xmlNsPtr ns = (xmlNsPtr) val;
1749
1750 cur->nodeTab[cur->nodeNr++] =
1751 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1752 } else
1753 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001754}
1755
1756/**
1757 * xmlXPathNodeSetMerge:
1758 * @val1: the first NodeSet or NULL
1759 * @val2: the second NodeSet
1760 *
1761 * Merges two nodesets, all nodes from @val2 are added to @val1
1762 * if @val1 is NULL, a new set is created and copied from @val2
1763 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001764 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001765 */
1766xmlNodeSetPtr
1767xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001768 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001769
1770 if (val2 == NULL) return(val1);
1771 if (val1 == NULL) {
1772 val1 = xmlXPathNodeSetCreate(NULL);
1773 }
1774
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001775 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001776 initNr = val1->nodeNr;
1777
1778 for (i = 0;i < val2->nodeNr;i++) {
1779 /*
1780 * check against doublons
1781 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001782 skip = 0;
1783 for (j = 0; j < initNr; j++) {
1784 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1785 skip = 1;
1786 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001787 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1788 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1789 xmlNsPtr ns1, ns2;
1790 ns1 = (xmlNsPtr) val1->nodeTab[j];
1791 ns2 = (xmlNsPtr) val2->nodeTab[i];
1792 if ((ns1->next == ns2->next) &&
1793 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1794 skip = 1;
1795 break;
1796 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001797 }
1798 }
1799 if (skip)
1800 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001801
1802 /*
1803 * grow the nodeTab if needed
1804 */
1805 if (val1->nodeMax == 0) {
1806 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1807 sizeof(xmlNodePtr));
1808 if (val1->nodeTab == NULL) {
1809 xmlGenericError(xmlGenericErrorContext,
1810 "xmlXPathNodeSetMerge: out of memory\n");
1811 return(NULL);
1812 }
1813 memset(val1->nodeTab, 0 ,
1814 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1815 val1->nodeMax = XML_NODESET_DEFAULT;
1816 } else if (val1->nodeNr == val1->nodeMax) {
1817 xmlNodePtr *temp;
1818
1819 val1->nodeMax *= 2;
1820 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1821 sizeof(xmlNodePtr));
1822 if (temp == NULL) {
1823 xmlGenericError(xmlGenericErrorContext,
1824 "xmlXPathNodeSetMerge: out of memory\n");
1825 return(NULL);
1826 }
1827 val1->nodeTab = temp;
1828 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001829 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1830 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1831
1832 val1->nodeTab[val1->nodeNr++] =
1833 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1834 } else
1835 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001836 }
1837
1838 return(val1);
1839}
1840
1841/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001842 * xmlXPathNodeSetMergeUnique:
1843 * @val1: the first NodeSet or NULL
1844 * @val2: the second NodeSet
1845 *
1846 * Merges two nodesets, all nodes from @val2 are added to @val1
1847 * if @val1 is NULL, a new set is created and copied from @val2
1848 *
1849 * Returns @val1 once extended or NULL in case of error.
1850 */
1851static xmlNodeSetPtr
1852xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1853 int i, initNr;
1854
1855 if (val2 == NULL) return(val1);
1856 if (val1 == NULL) {
1857 val1 = xmlXPathNodeSetCreate(NULL);
1858 }
1859
1860 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1861 initNr = val1->nodeNr;
1862
1863 for (i = 0;i < val2->nodeNr;i++) {
1864 /*
1865 * grow the nodeTab if needed
1866 */
1867 if (val1->nodeMax == 0) {
1868 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1869 sizeof(xmlNodePtr));
1870 if (val1->nodeTab == NULL) {
1871 xmlGenericError(xmlGenericErrorContext,
1872 "xmlXPathNodeSetMerge: out of memory\n");
1873 return(NULL);
1874 }
1875 memset(val1->nodeTab, 0 ,
1876 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1877 val1->nodeMax = XML_NODESET_DEFAULT;
1878 } else if (val1->nodeNr == val1->nodeMax) {
1879 xmlNodePtr *temp;
1880
1881 val1->nodeMax *= 2;
1882 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1883 sizeof(xmlNodePtr));
1884 if (temp == NULL) {
1885 xmlGenericError(xmlGenericErrorContext,
1886 "xmlXPathNodeSetMerge: out of memory\n");
1887 return(NULL);
1888 }
1889 val1->nodeTab = temp;
1890 }
1891 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1892 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1893
1894 val1->nodeTab[val1->nodeNr++] =
1895 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1896 } else
1897 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1898 }
1899
1900 return(val1);
1901}
1902
1903/**
Owen Taylor3473f882001-02-23 17:55:21 +00001904 * xmlXPathNodeSetDel:
1905 * @cur: the initial node set
1906 * @val: an xmlNodePtr
1907 *
1908 * Removes an xmlNodePtr from an existing NodeSet
1909 */
1910void
1911xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1912 int i;
1913
1914 if (cur == NULL) return;
1915 if (val == NULL) return;
1916
1917 /*
1918 * check against doublons
1919 */
1920 for (i = 0;i < cur->nodeNr;i++)
1921 if (cur->nodeTab[i] == val) break;
1922
1923 if (i >= cur->nodeNr) {
1924#ifdef DEBUG
1925 xmlGenericError(xmlGenericErrorContext,
1926 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1927 val->name);
1928#endif
1929 return;
1930 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001931 if ((cur->nodeTab[i] != NULL) &&
1932 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1933 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001934 cur->nodeNr--;
1935 for (;i < cur->nodeNr;i++)
1936 cur->nodeTab[i] = cur->nodeTab[i + 1];
1937 cur->nodeTab[cur->nodeNr] = NULL;
1938}
1939
1940/**
1941 * xmlXPathNodeSetRemove:
1942 * @cur: the initial node set
1943 * @val: the index to remove
1944 *
1945 * Removes an entry from an existing NodeSet list.
1946 */
1947void
1948xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1949 if (cur == NULL) return;
1950 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001951 if ((cur->nodeTab[val] != NULL) &&
1952 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1953 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001954 cur->nodeNr--;
1955 for (;val < cur->nodeNr;val++)
1956 cur->nodeTab[val] = cur->nodeTab[val + 1];
1957 cur->nodeTab[cur->nodeNr] = NULL;
1958}
1959
1960/**
1961 * xmlXPathFreeNodeSet:
1962 * @obj: the xmlNodeSetPtr to free
1963 *
1964 * Free the NodeSet compound (not the actual nodes !).
1965 */
1966void
1967xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1968 if (obj == NULL) return;
1969 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001970 int i;
1971
1972 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1973 for (i = 0;i < obj->nodeNr;i++)
1974 if ((obj->nodeTab[i] != NULL) &&
1975 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1976 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001977 xmlFree(obj->nodeTab);
1978 }
Owen Taylor3473f882001-02-23 17:55:21 +00001979 xmlFree(obj);
1980}
1981
1982/**
1983 * xmlXPathFreeValueTree:
1984 * @obj: the xmlNodeSetPtr to free
1985 *
1986 * Free the NodeSet compound and the actual tree, this is different
1987 * from xmlXPathFreeNodeSet()
1988 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001989static void
Owen Taylor3473f882001-02-23 17:55:21 +00001990xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1991 int i;
1992
1993 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001994
1995 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001996 for (i = 0;i < obj->nodeNr;i++) {
1997 if (obj->nodeTab[i] != NULL) {
1998 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1999 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2000 } else {
2001 xmlFreeNodeList(obj->nodeTab[i]);
2002 }
2003 }
2004 }
Owen Taylor3473f882001-02-23 17:55:21 +00002005 xmlFree(obj->nodeTab);
2006 }
Owen Taylor3473f882001-02-23 17:55:21 +00002007 xmlFree(obj);
2008}
2009
2010#if defined(DEBUG) || defined(DEBUG_STEP)
2011/**
2012 * xmlGenericErrorContextNodeSet:
2013 * @output: a FILE * for the output
2014 * @obj: the xmlNodeSetPtr to free
2015 *
2016 * Quick display of a NodeSet
2017 */
2018void
2019xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2020 int i;
2021
2022 if (output == NULL) output = xmlGenericErrorContext;
2023 if (obj == NULL) {
2024 fprintf(output, "NodeSet == NULL !\n");
2025 return;
2026 }
2027 if (obj->nodeNr == 0) {
2028 fprintf(output, "NodeSet is empty\n");
2029 return;
2030 }
2031 if (obj->nodeTab == NULL) {
2032 fprintf(output, " nodeTab == NULL !\n");
2033 return;
2034 }
2035 for (i = 0; i < obj->nodeNr; i++) {
2036 if (obj->nodeTab[i] == NULL) {
2037 fprintf(output, " NULL !\n");
2038 return;
2039 }
2040 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2041 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2042 fprintf(output, " /");
2043 else if (obj->nodeTab[i]->name == NULL)
2044 fprintf(output, " noname!");
2045 else fprintf(output, " %s", obj->nodeTab[i]->name);
2046 }
2047 fprintf(output, "\n");
2048}
2049#endif
2050
2051/**
2052 * xmlXPathNewNodeSet:
2053 * @val: the NodePtr value
2054 *
2055 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2056 * it with the single Node @val
2057 *
2058 * Returns the newly created object.
2059 */
2060xmlXPathObjectPtr
2061xmlXPathNewNodeSet(xmlNodePtr val) {
2062 xmlXPathObjectPtr ret;
2063
2064 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2065 if (ret == NULL) {
2066 xmlGenericError(xmlGenericErrorContext,
2067 "xmlXPathNewNodeSet: out of memory\n");
2068 return(NULL);
2069 }
2070 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2071 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002072 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002073 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002074 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002075 return(ret);
2076}
2077
2078/**
2079 * xmlXPathNewValueTree:
2080 * @val: the NodePtr value
2081 *
2082 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2083 * it with the tree root @val
2084 *
2085 * Returns the newly created object.
2086 */
2087xmlXPathObjectPtr
2088xmlXPathNewValueTree(xmlNodePtr val) {
2089 xmlXPathObjectPtr ret;
2090
2091 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2092 if (ret == NULL) {
2093 xmlGenericError(xmlGenericErrorContext,
2094 "xmlXPathNewNodeSet: out of memory\n");
2095 return(NULL);
2096 }
2097 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2098 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002099 ret->boolval = 1;
2100 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002101 ret->nodesetval = xmlXPathNodeSetCreate(val);
2102 return(ret);
2103}
2104
2105/**
2106 * xmlXPathNewNodeSetList:
2107 * @val: an existing NodeSet
2108 *
2109 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2110 * it with the Nodeset @val
2111 *
2112 * Returns the newly created object.
2113 */
2114xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002115xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2116{
Owen Taylor3473f882001-02-23 17:55:21 +00002117 xmlXPathObjectPtr ret;
2118 int i;
2119
2120 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002121 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002122 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002123 ret = xmlXPathNewNodeSet(NULL);
2124 else {
2125 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2126 for (i = 1; i < val->nodeNr; ++i)
2127 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2128 }
Owen Taylor3473f882001-02-23 17:55:21 +00002129
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002130 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002131}
2132
2133/**
2134 * xmlXPathWrapNodeSet:
2135 * @val: the NodePtr value
2136 *
2137 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2138 *
2139 * Returns the newly created object.
2140 */
2141xmlXPathObjectPtr
2142xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2143 xmlXPathObjectPtr ret;
2144
2145 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2146 if (ret == NULL) {
2147 xmlGenericError(xmlGenericErrorContext,
2148 "xmlXPathWrapNodeSet: out of memory\n");
2149 return(NULL);
2150 }
2151 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2152 ret->type = XPATH_NODESET;
2153 ret->nodesetval = val;
2154 return(ret);
2155}
2156
2157/**
2158 * xmlXPathFreeNodeSetList:
2159 * @obj: an existing NodeSetList object
2160 *
2161 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2162 * the list contrary to xmlXPathFreeObject().
2163 */
2164void
2165xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2166 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002167 xmlFree(obj);
2168}
2169
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002170/**
2171 * xmlXPathDifference:
2172 * @nodes1: a node-set
2173 * @nodes2: a node-set
2174 *
2175 * Implements the EXSLT - Sets difference() function:
2176 * node-set set:difference (node-set, node-set)
2177 *
2178 * Returns the difference between the two node sets, or nodes1 if
2179 * nodes2 is empty
2180 */
2181xmlNodeSetPtr
2182xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2183 xmlNodeSetPtr ret;
2184 int i, l1;
2185 xmlNodePtr cur;
2186
2187 if (xmlXPathNodeSetIsEmpty(nodes2))
2188 return(nodes1);
2189
2190 ret = xmlXPathNodeSetCreate(NULL);
2191 if (xmlXPathNodeSetIsEmpty(nodes1))
2192 return(ret);
2193
2194 l1 = xmlXPathNodeSetGetLength(nodes1);
2195
2196 for (i = 0; i < l1; i++) {
2197 cur = xmlXPathNodeSetItem(nodes1, i);
2198 if (!xmlXPathNodeSetContains(nodes2, cur))
2199 xmlXPathNodeSetAddUnique(ret, cur);
2200 }
2201 return(ret);
2202}
2203
2204/**
2205 * xmlXPathIntersection:
2206 * @nodes1: a node-set
2207 * @nodes2: a node-set
2208 *
2209 * Implements the EXSLT - Sets intersection() function:
2210 * node-set set:intersection (node-set, node-set)
2211 *
2212 * Returns a node set comprising the nodes that are within both the
2213 * node sets passed as arguments
2214 */
2215xmlNodeSetPtr
2216xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2217 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2218 int i, l1;
2219 xmlNodePtr cur;
2220
2221 if (xmlXPathNodeSetIsEmpty(nodes1))
2222 return(ret);
2223 if (xmlXPathNodeSetIsEmpty(nodes2))
2224 return(ret);
2225
2226 l1 = xmlXPathNodeSetGetLength(nodes1);
2227
2228 for (i = 0; i < l1; i++) {
2229 cur = xmlXPathNodeSetItem(nodes1, i);
2230 if (xmlXPathNodeSetContains(nodes2, cur))
2231 xmlXPathNodeSetAddUnique(ret, cur);
2232 }
2233 return(ret);
2234}
2235
2236/**
2237 * xmlXPathDistinctSorted:
2238 * @nodes: a node-set, sorted by document order
2239 *
2240 * Implements the EXSLT - Sets distinct() function:
2241 * node-set set:distinct (node-set)
2242 *
2243 * Returns a subset of the nodes contained in @nodes, or @nodes if
2244 * it is empty
2245 */
2246xmlNodeSetPtr
2247xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2248 xmlNodeSetPtr ret;
2249 xmlHashTablePtr hash;
2250 int i, l;
2251 xmlChar * strval;
2252 xmlNodePtr cur;
2253
2254 if (xmlXPathNodeSetIsEmpty(nodes))
2255 return(nodes);
2256
2257 ret = xmlXPathNodeSetCreate(NULL);
2258 l = xmlXPathNodeSetGetLength(nodes);
2259 hash = xmlHashCreate (l);
2260 for (i = 0; i < l; i++) {
2261 cur = xmlXPathNodeSetItem(nodes, i);
2262 strval = xmlXPathCastNodeToString(cur);
2263 if (xmlHashLookup(hash, strval) == NULL) {
2264 xmlHashAddEntry(hash, strval, strval);
2265 xmlXPathNodeSetAddUnique(ret, cur);
2266 } else {
2267 xmlFree(strval);
2268 }
2269 }
2270 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2271 return(ret);
2272}
2273
2274/**
2275 * xmlXPathDistinct:
2276 * @nodes: a node-set
2277 *
2278 * Implements the EXSLT - Sets distinct() function:
2279 * node-set set:distinct (node-set)
2280 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2281 * is called with the sorted node-set
2282 *
2283 * Returns a subset of the nodes contained in @nodes, or @nodes if
2284 * it is empty
2285 */
2286xmlNodeSetPtr
2287xmlXPathDistinct (xmlNodeSetPtr nodes) {
2288 if (xmlXPathNodeSetIsEmpty(nodes))
2289 return(nodes);
2290
2291 xmlXPathNodeSetSort(nodes);
2292 return(xmlXPathDistinctSorted(nodes));
2293}
2294
2295/**
2296 * xmlXPathHasSameNodes:
2297 * @nodes1: a node-set
2298 * @nodes2: a node-set
2299 *
2300 * Implements the EXSLT - Sets has-same-nodes function:
2301 * boolean set:has-same-node(node-set, node-set)
2302 *
2303 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2304 * otherwise
2305 */
2306int
2307xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2308 int i, l;
2309 xmlNodePtr cur;
2310
2311 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2312 xmlXPathNodeSetIsEmpty(nodes2))
2313 return(0);
2314
2315 l = xmlXPathNodeSetGetLength(nodes1);
2316 for (i = 0; i < l; i++) {
2317 cur = xmlXPathNodeSetItem(nodes1, i);
2318 if (xmlXPathNodeSetContains(nodes2, cur))
2319 return(1);
2320 }
2321 return(0);
2322}
2323
2324/**
2325 * xmlXPathNodeLeadingSorted:
2326 * @nodes: a node-set, sorted by document order
2327 * @node: a node
2328 *
2329 * Implements the EXSLT - Sets leading() function:
2330 * node-set set:leading (node-set, node-set)
2331 *
2332 * Returns the nodes in @nodes that precede @node in document order,
2333 * @nodes if @node is NULL or an empty node-set if @nodes
2334 * doesn't contain @node
2335 */
2336xmlNodeSetPtr
2337xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2338 int i, l;
2339 xmlNodePtr cur;
2340 xmlNodeSetPtr ret;
2341
2342 if (node == NULL)
2343 return(nodes);
2344
2345 ret = xmlXPathNodeSetCreate(NULL);
2346 if (xmlXPathNodeSetIsEmpty(nodes) ||
2347 (!xmlXPathNodeSetContains(nodes, node)))
2348 return(ret);
2349
2350 l = xmlXPathNodeSetGetLength(nodes);
2351 for (i = 0; i < l; i++) {
2352 cur = xmlXPathNodeSetItem(nodes, i);
2353 if (cur == node)
2354 break;
2355 xmlXPathNodeSetAddUnique(ret, cur);
2356 }
2357 return(ret);
2358}
2359
2360/**
2361 * xmlXPathNodeLeading:
2362 * @nodes: a node-set
2363 * @node: a node
2364 *
2365 * Implements the EXSLT - Sets leading() function:
2366 * node-set set:leading (node-set, node-set)
2367 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2368 * is called.
2369 *
2370 * Returns the nodes in @nodes that precede @node in document order,
2371 * @nodes if @node is NULL or an empty node-set if @nodes
2372 * doesn't contain @node
2373 */
2374xmlNodeSetPtr
2375xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2376 xmlXPathNodeSetSort(nodes);
2377 return(xmlXPathNodeLeadingSorted(nodes, node));
2378}
2379
2380/**
2381 * xmlXPathLeadingSorted:
2382 * @nodes1: a node-set, sorted by document order
2383 * @nodes2: a node-set, sorted by document order
2384 *
2385 * Implements the EXSLT - Sets leading() function:
2386 * node-set set:leading (node-set, node-set)
2387 *
2388 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2389 * in document order, @nodes1 if @nodes2 is NULL or empty or
2390 * an empty node-set if @nodes1 doesn't contain @nodes2
2391 */
2392xmlNodeSetPtr
2393xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2394 if (xmlXPathNodeSetIsEmpty(nodes2))
2395 return(nodes1);
2396 return(xmlXPathNodeLeadingSorted(nodes1,
2397 xmlXPathNodeSetItem(nodes2, 1)));
2398}
2399
2400/**
2401 * xmlXPathLeading:
2402 * @nodes1: a node-set
2403 * @nodes2: a node-set
2404 *
2405 * Implements the EXSLT - Sets leading() function:
2406 * node-set set:leading (node-set, node-set)
2407 * @nodes1 and @nodes2 are sorted by document order, then
2408 * #exslSetsLeadingSorted is called.
2409 *
2410 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2411 * in document order, @nodes1 if @nodes2 is NULL or empty or
2412 * an empty node-set if @nodes1 doesn't contain @nodes2
2413 */
2414xmlNodeSetPtr
2415xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2416 if (xmlXPathNodeSetIsEmpty(nodes2))
2417 return(nodes1);
2418 if (xmlXPathNodeSetIsEmpty(nodes1))
2419 return(xmlXPathNodeSetCreate(NULL));
2420 xmlXPathNodeSetSort(nodes1);
2421 xmlXPathNodeSetSort(nodes2);
2422 return(xmlXPathNodeLeadingSorted(nodes1,
2423 xmlXPathNodeSetItem(nodes2, 1)));
2424}
2425
2426/**
2427 * xmlXPathNodeTrailingSorted:
2428 * @nodes: a node-set, sorted by document order
2429 * @node: a node
2430 *
2431 * Implements the EXSLT - Sets trailing() function:
2432 * node-set set:trailing (node-set, node-set)
2433 *
2434 * Returns the nodes in @nodes that follow @node in document order,
2435 * @nodes if @node is NULL or an empty node-set if @nodes
2436 * doesn't contain @node
2437 */
2438xmlNodeSetPtr
2439xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2440 int i, l;
2441 xmlNodePtr cur;
2442 xmlNodeSetPtr ret;
2443
2444 if (node == NULL)
2445 return(nodes);
2446
2447 ret = xmlXPathNodeSetCreate(NULL);
2448 if (xmlXPathNodeSetIsEmpty(nodes) ||
2449 (!xmlXPathNodeSetContains(nodes, node)))
2450 return(ret);
2451
2452 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002453 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002454 cur = xmlXPathNodeSetItem(nodes, i);
2455 if (cur == node)
2456 break;
2457 xmlXPathNodeSetAddUnique(ret, cur);
2458 }
2459 return(ret);
2460}
2461
2462/**
2463 * xmlXPathNodeTrailing:
2464 * @nodes: a node-set
2465 * @node: a node
2466 *
2467 * Implements the EXSLT - Sets trailing() function:
2468 * node-set set:trailing (node-set, node-set)
2469 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2470 * is called.
2471 *
2472 * Returns the nodes in @nodes that follow @node in document order,
2473 * @nodes if @node is NULL or an empty node-set if @nodes
2474 * doesn't contain @node
2475 */
2476xmlNodeSetPtr
2477xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2478 xmlXPathNodeSetSort(nodes);
2479 return(xmlXPathNodeTrailingSorted(nodes, node));
2480}
2481
2482/**
2483 * xmlXPathTrailingSorted:
2484 * @nodes1: a node-set, sorted by document order
2485 * @nodes2: a node-set, sorted by document order
2486 *
2487 * Implements the EXSLT - Sets trailing() function:
2488 * node-set set:trailing (node-set, node-set)
2489 *
2490 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2491 * in document order, @nodes1 if @nodes2 is NULL or empty or
2492 * an empty node-set if @nodes1 doesn't contain @nodes2
2493 */
2494xmlNodeSetPtr
2495xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2496 if (xmlXPathNodeSetIsEmpty(nodes2))
2497 return(nodes1);
2498 return(xmlXPathNodeTrailingSorted(nodes1,
2499 xmlXPathNodeSetItem(nodes2, 0)));
2500}
2501
2502/**
2503 * xmlXPathTrailing:
2504 * @nodes1: a node-set
2505 * @nodes2: a node-set
2506 *
2507 * Implements the EXSLT - Sets trailing() function:
2508 * node-set set:trailing (node-set, node-set)
2509 * @nodes1 and @nodes2 are sorted by document order, then
2510 * #xmlXPathTrailingSorted is called.
2511 *
2512 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2513 * in document order, @nodes1 if @nodes2 is NULL or empty or
2514 * an empty node-set if @nodes1 doesn't contain @nodes2
2515 */
2516xmlNodeSetPtr
2517xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2518 if (xmlXPathNodeSetIsEmpty(nodes2))
2519 return(nodes1);
2520 if (xmlXPathNodeSetIsEmpty(nodes1))
2521 return(xmlXPathNodeSetCreate(NULL));
2522 xmlXPathNodeSetSort(nodes1);
2523 xmlXPathNodeSetSort(nodes2);
2524 return(xmlXPathNodeTrailingSorted(nodes1,
2525 xmlXPathNodeSetItem(nodes2, 0)));
2526}
2527
Owen Taylor3473f882001-02-23 17:55:21 +00002528/************************************************************************
2529 * *
2530 * Routines to handle extra functions *
2531 * *
2532 ************************************************************************/
2533
2534/**
2535 * xmlXPathRegisterFunc:
2536 * @ctxt: the XPath context
2537 * @name: the function name
2538 * @f: the function implementation or NULL
2539 *
2540 * Register a new function. If @f is NULL it unregisters the function
2541 *
2542 * Returns 0 in case of success, -1 in case of error
2543 */
2544int
2545xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2546 xmlXPathFunction f) {
2547 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2548}
2549
2550/**
2551 * xmlXPathRegisterFuncNS:
2552 * @ctxt: the XPath context
2553 * @name: the function name
2554 * @ns_uri: the function namespace URI
2555 * @f: the function implementation or NULL
2556 *
2557 * Register a new function. If @f is NULL it unregisters the function
2558 *
2559 * Returns 0 in case of success, -1 in case of error
2560 */
2561int
2562xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2563 const xmlChar *ns_uri, xmlXPathFunction f) {
2564 if (ctxt == NULL)
2565 return(-1);
2566 if (name == NULL)
2567 return(-1);
2568
2569 if (ctxt->funcHash == NULL)
2570 ctxt->funcHash = xmlHashCreate(0);
2571 if (ctxt->funcHash == NULL)
2572 return(-1);
2573 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2574}
2575
2576/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002577 * xmlXPathRegisterFuncLookup:
2578 * @ctxt: the XPath context
2579 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002580 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002581 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002582 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002583 */
2584void
2585xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2586 xmlXPathFuncLookupFunc f,
2587 void *funcCtxt) {
2588 if (ctxt == NULL)
2589 return;
2590 ctxt->funcLookupFunc = (void *) f;
2591 ctxt->funcLookupData = funcCtxt;
2592}
2593
2594/**
Owen Taylor3473f882001-02-23 17:55:21 +00002595 * xmlXPathFunctionLookup:
2596 * @ctxt: the XPath context
2597 * @name: the function name
2598 *
2599 * Search in the Function array of the context for the given
2600 * function.
2601 *
2602 * Returns the xmlXPathFunction or NULL if not found
2603 */
2604xmlXPathFunction
2605xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002606 if (ctxt == NULL)
2607 return (NULL);
2608
2609 if (ctxt->funcLookupFunc != NULL) {
2610 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002611 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002612
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002613 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002614 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002615 if (ret != NULL)
2616 return(ret);
2617 }
Owen Taylor3473f882001-02-23 17:55:21 +00002618 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2619}
2620
2621/**
2622 * xmlXPathFunctionLookupNS:
2623 * @ctxt: the XPath context
2624 * @name: the function name
2625 * @ns_uri: the function namespace URI
2626 *
2627 * Search in the Function array of the context for the given
2628 * function.
2629 *
2630 * Returns the xmlXPathFunction or NULL if not found
2631 */
2632xmlXPathFunction
2633xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2634 const xmlChar *ns_uri) {
2635 if (ctxt == NULL)
2636 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002637 if (name == NULL)
2638 return(NULL);
2639
Thomas Broyerba4ad322001-07-26 16:55:21 +00002640 if (ctxt->funcLookupFunc != NULL) {
2641 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002642 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002643
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002644 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002645 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002646 if (ret != NULL)
2647 return(ret);
2648 }
2649
2650 if (ctxt->funcHash == NULL)
2651 return(NULL);
2652
Owen Taylor3473f882001-02-23 17:55:21 +00002653 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2654}
2655
2656/**
2657 * xmlXPathRegisteredFuncsCleanup:
2658 * @ctxt: the XPath context
2659 *
2660 * Cleanup the XPath context data associated to registered functions
2661 */
2662void
2663xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2664 if (ctxt == NULL)
2665 return;
2666
2667 xmlHashFree(ctxt->funcHash, NULL);
2668 ctxt->funcHash = NULL;
2669}
2670
2671/************************************************************************
2672 * *
2673 * Routines to handle Variable *
2674 * *
2675 ************************************************************************/
2676
2677/**
2678 * xmlXPathRegisterVariable:
2679 * @ctxt: the XPath context
2680 * @name: the variable name
2681 * @value: the variable value or NULL
2682 *
2683 * Register a new variable value. If @value is NULL it unregisters
2684 * the variable
2685 *
2686 * Returns 0 in case of success, -1 in case of error
2687 */
2688int
2689xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2690 xmlXPathObjectPtr value) {
2691 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2692}
2693
2694/**
2695 * xmlXPathRegisterVariableNS:
2696 * @ctxt: the XPath context
2697 * @name: the variable name
2698 * @ns_uri: the variable namespace URI
2699 * @value: the variable value or NULL
2700 *
2701 * Register a new variable value. If @value is NULL it unregisters
2702 * the variable
2703 *
2704 * Returns 0 in case of success, -1 in case of error
2705 */
2706int
2707xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2708 const xmlChar *ns_uri,
2709 xmlXPathObjectPtr value) {
2710 if (ctxt == NULL)
2711 return(-1);
2712 if (name == NULL)
2713 return(-1);
2714
2715 if (ctxt->varHash == NULL)
2716 ctxt->varHash = xmlHashCreate(0);
2717 if (ctxt->varHash == NULL)
2718 return(-1);
2719 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2720 (void *) value,
2721 (xmlHashDeallocator)xmlXPathFreeObject));
2722}
2723
2724/**
2725 * xmlXPathRegisterVariableLookup:
2726 * @ctxt: the XPath context
2727 * @f: the lookup function
2728 * @data: the lookup data
2729 *
2730 * register an external mechanism to do variable lookup
2731 */
2732void
2733xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2734 xmlXPathVariableLookupFunc f, void *data) {
2735 if (ctxt == NULL)
2736 return;
2737 ctxt->varLookupFunc = (void *) f;
2738 ctxt->varLookupData = data;
2739}
2740
2741/**
2742 * xmlXPathVariableLookup:
2743 * @ctxt: the XPath context
2744 * @name: the variable name
2745 *
2746 * Search in the Variable array of the context for the given
2747 * variable value.
2748 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002749 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002750 */
2751xmlXPathObjectPtr
2752xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2753 if (ctxt == NULL)
2754 return(NULL);
2755
2756 if (ctxt->varLookupFunc != NULL) {
2757 xmlXPathObjectPtr ret;
2758
2759 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2760 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002761 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002762 }
2763 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2764}
2765
2766/**
2767 * xmlXPathVariableLookupNS:
2768 * @ctxt: the XPath context
2769 * @name: the variable name
2770 * @ns_uri: the variable namespace URI
2771 *
2772 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002773 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002774 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002775 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002776 */
2777xmlXPathObjectPtr
2778xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2779 const xmlChar *ns_uri) {
2780 if (ctxt == NULL)
2781 return(NULL);
2782
2783 if (ctxt->varLookupFunc != NULL) {
2784 xmlXPathObjectPtr ret;
2785
2786 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2787 (ctxt->varLookupData, name, ns_uri);
2788 if (ret != NULL) return(ret);
2789 }
2790
2791 if (ctxt->varHash == NULL)
2792 return(NULL);
2793 if (name == NULL)
2794 return(NULL);
2795
Daniel Veillard8c357d52001-07-03 23:43:33 +00002796 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2797 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002798}
2799
2800/**
2801 * xmlXPathRegisteredVariablesCleanup:
2802 * @ctxt: the XPath context
2803 *
2804 * Cleanup the XPath context data associated to registered variables
2805 */
2806void
2807xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2808 if (ctxt == NULL)
2809 return;
2810
Daniel Veillard76d66f42001-05-16 21:05:17 +00002811 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002812 ctxt->varHash = NULL;
2813}
2814
2815/**
2816 * xmlXPathRegisterNs:
2817 * @ctxt: the XPath context
2818 * @prefix: the namespace prefix
2819 * @ns_uri: the namespace name
2820 *
2821 * Register a new namespace. If @ns_uri is NULL it unregisters
2822 * the namespace
2823 *
2824 * Returns 0 in case of success, -1 in case of error
2825 */
2826int
2827xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2828 const xmlChar *ns_uri) {
2829 if (ctxt == NULL)
2830 return(-1);
2831 if (prefix == NULL)
2832 return(-1);
2833
2834 if (ctxt->nsHash == NULL)
2835 ctxt->nsHash = xmlHashCreate(10);
2836 if (ctxt->nsHash == NULL)
2837 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002838 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002839 (xmlHashDeallocator)xmlFree));
2840}
2841
2842/**
2843 * xmlXPathNsLookup:
2844 * @ctxt: the XPath context
2845 * @prefix: the namespace prefix value
2846 *
2847 * Search in the namespace declaration array of the context for the given
2848 * namespace name associated to the given prefix
2849 *
2850 * Returns the value or NULL if not found
2851 */
2852const xmlChar *
2853xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2854 if (ctxt == NULL)
2855 return(NULL);
2856 if (prefix == NULL)
2857 return(NULL);
2858
2859#ifdef XML_XML_NAMESPACE
2860 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2861 return(XML_XML_NAMESPACE);
2862#endif
2863
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002864 if (ctxt->namespaces != NULL) {
2865 int i;
2866
2867 for (i = 0;i < ctxt->nsNr;i++) {
2868 if ((ctxt->namespaces[i] != NULL) &&
2869 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2870 return(ctxt->namespaces[i]->href);
2871 }
2872 }
Owen Taylor3473f882001-02-23 17:55:21 +00002873
2874 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2875}
2876
2877/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002878 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002879 * @ctxt: the XPath context
2880 *
2881 * Cleanup the XPath context data associated to registered variables
2882 */
2883void
2884xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2885 if (ctxt == NULL)
2886 return;
2887
Daniel Veillard42766c02002-08-22 20:52:17 +00002888 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002889 ctxt->nsHash = NULL;
2890}
2891
2892/************************************************************************
2893 * *
2894 * Routines to handle Values *
2895 * *
2896 ************************************************************************/
2897
2898/* Allocations are terrible, one need to optimize all this !!! */
2899
2900/**
2901 * xmlXPathNewFloat:
2902 * @val: the double value
2903 *
2904 * Create a new xmlXPathObjectPtr of type double and of value @val
2905 *
2906 * Returns the newly created object.
2907 */
2908xmlXPathObjectPtr
2909xmlXPathNewFloat(double val) {
2910 xmlXPathObjectPtr ret;
2911
2912 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2913 if (ret == NULL) {
2914 xmlGenericError(xmlGenericErrorContext,
2915 "xmlXPathNewFloat: out of memory\n");
2916 return(NULL);
2917 }
2918 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2919 ret->type = XPATH_NUMBER;
2920 ret->floatval = val;
2921 return(ret);
2922}
2923
2924/**
2925 * xmlXPathNewBoolean:
2926 * @val: the boolean value
2927 *
2928 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2929 *
2930 * Returns the newly created object.
2931 */
2932xmlXPathObjectPtr
2933xmlXPathNewBoolean(int val) {
2934 xmlXPathObjectPtr ret;
2935
2936 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2937 if (ret == NULL) {
2938 xmlGenericError(xmlGenericErrorContext,
2939 "xmlXPathNewBoolean: out of memory\n");
2940 return(NULL);
2941 }
2942 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2943 ret->type = XPATH_BOOLEAN;
2944 ret->boolval = (val != 0);
2945 return(ret);
2946}
2947
2948/**
2949 * xmlXPathNewString:
2950 * @val: the xmlChar * value
2951 *
2952 * Create a new xmlXPathObjectPtr of type string and of value @val
2953 *
2954 * Returns the newly created object.
2955 */
2956xmlXPathObjectPtr
2957xmlXPathNewString(const xmlChar *val) {
2958 xmlXPathObjectPtr ret;
2959
2960 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2961 if (ret == NULL) {
2962 xmlGenericError(xmlGenericErrorContext,
2963 "xmlXPathNewString: out of memory\n");
2964 return(NULL);
2965 }
2966 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2967 ret->type = XPATH_STRING;
2968 if (val != NULL)
2969 ret->stringval = xmlStrdup(val);
2970 else
2971 ret->stringval = xmlStrdup((const xmlChar *)"");
2972 return(ret);
2973}
2974
2975/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002976 * xmlXPathWrapString:
2977 * @val: the xmlChar * value
2978 *
2979 * Wraps the @val string into an XPath object.
2980 *
2981 * Returns the newly created object.
2982 */
2983xmlXPathObjectPtr
2984xmlXPathWrapString (xmlChar *val) {
2985 xmlXPathObjectPtr ret;
2986
2987 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2988 if (ret == NULL) {
2989 xmlGenericError(xmlGenericErrorContext,
2990 "xmlXPathWrapString: out of memory\n");
2991 return(NULL);
2992 }
2993 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2994 ret->type = XPATH_STRING;
2995 ret->stringval = val;
2996 return(ret);
2997}
2998
2999/**
Owen Taylor3473f882001-02-23 17:55:21 +00003000 * xmlXPathNewCString:
3001 * @val: the char * value
3002 *
3003 * Create a new xmlXPathObjectPtr of type string and of value @val
3004 *
3005 * Returns the newly created object.
3006 */
3007xmlXPathObjectPtr
3008xmlXPathNewCString(const char *val) {
3009 xmlXPathObjectPtr ret;
3010
3011 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3012 if (ret == NULL) {
3013 xmlGenericError(xmlGenericErrorContext,
3014 "xmlXPathNewCString: out of memory\n");
3015 return(NULL);
3016 }
3017 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3018 ret->type = XPATH_STRING;
3019 ret->stringval = xmlStrdup(BAD_CAST val);
3020 return(ret);
3021}
3022
3023/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003024 * xmlXPathWrapCString:
3025 * @val: the char * value
3026 *
3027 * Wraps a string into an XPath object.
3028 *
3029 * Returns the newly created object.
3030 */
3031xmlXPathObjectPtr
3032xmlXPathWrapCString (char * val) {
3033 return(xmlXPathWrapString((xmlChar *)(val)));
3034}
3035
3036/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003037 * xmlXPathWrapExternal:
3038 * @val: the user data
3039 *
3040 * Wraps the @val data into an XPath object.
3041 *
3042 * Returns the newly created object.
3043 */
3044xmlXPathObjectPtr
3045xmlXPathWrapExternal (void *val) {
3046 xmlXPathObjectPtr ret;
3047
3048 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3049 if (ret == NULL) {
3050 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003051 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003052 return(NULL);
3053 }
3054 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3055 ret->type = XPATH_USERS;
3056 ret->user = val;
3057 return(ret);
3058}
3059
3060/**
Owen Taylor3473f882001-02-23 17:55:21 +00003061 * xmlXPathObjectCopy:
3062 * @val: the original object
3063 *
3064 * allocate a new copy of a given object
3065 *
3066 * Returns the newly created object.
3067 */
3068xmlXPathObjectPtr
3069xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3070 xmlXPathObjectPtr ret;
3071
3072 if (val == NULL)
3073 return(NULL);
3074
3075 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3076 if (ret == NULL) {
3077 xmlGenericError(xmlGenericErrorContext,
3078 "xmlXPathObjectCopy: out of memory\n");
3079 return(NULL);
3080 }
3081 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3082 switch (val->type) {
3083 case XPATH_BOOLEAN:
3084 case XPATH_NUMBER:
3085 case XPATH_POINT:
3086 case XPATH_RANGE:
3087 break;
3088 case XPATH_STRING:
3089 ret->stringval = xmlStrdup(val->stringval);
3090 break;
3091 case XPATH_XSLT_TREE:
3092 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003093 (val->nodesetval->nodeTab != NULL)) {
3094 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003095 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3096 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003097 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003098 (xmlNodePtr) ret->user);
3099 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003100 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003101 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003102 break;
3103 case XPATH_NODESET:
3104 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003105 /* Do not deallocate the copied tree value */
3106 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003107 break;
3108 case XPATH_LOCATIONSET:
3109#ifdef LIBXML_XPTR_ENABLED
3110 {
3111 xmlLocationSetPtr loc = val->user;
3112 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3113 break;
3114 }
3115#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003116 case XPATH_USERS:
3117 ret->user = val->user;
3118 break;
3119 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003120 xmlGenericError(xmlGenericErrorContext,
3121 "xmlXPathObjectCopy: unsupported type %d\n",
3122 val->type);
3123 break;
3124 }
3125 return(ret);
3126}
3127
3128/**
3129 * xmlXPathFreeObject:
3130 * @obj: the object to free
3131 *
3132 * Free up an xmlXPathObjectPtr object.
3133 */
3134void
3135xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3136 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003137 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003138 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003139 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003140 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003141 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003142 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003143 xmlXPathFreeValueTree(obj->nodesetval);
3144 } else {
3145 if (obj->nodesetval != NULL)
3146 xmlXPathFreeNodeSet(obj->nodesetval);
3147 }
Owen Taylor3473f882001-02-23 17:55:21 +00003148#ifdef LIBXML_XPTR_ENABLED
3149 } else if (obj->type == XPATH_LOCATIONSET) {
3150 if (obj->user != NULL)
3151 xmlXPtrFreeLocationSet(obj->user);
3152#endif
3153 } else if (obj->type == XPATH_STRING) {
3154 if (obj->stringval != NULL)
3155 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003156 }
3157
Owen Taylor3473f882001-02-23 17:55:21 +00003158 xmlFree(obj);
3159}
3160
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003161
3162/************************************************************************
3163 * *
3164 * Type Casting Routines *
3165 * *
3166 ************************************************************************/
3167
3168/**
3169 * xmlXPathCastBooleanToString:
3170 * @val: a boolean
3171 *
3172 * Converts a boolean to its string value.
3173 *
3174 * Returns a newly allocated string.
3175 */
3176xmlChar *
3177xmlXPathCastBooleanToString (int val) {
3178 xmlChar *ret;
3179 if (val)
3180 ret = xmlStrdup((const xmlChar *) "true");
3181 else
3182 ret = xmlStrdup((const xmlChar *) "false");
3183 return(ret);
3184}
3185
3186/**
3187 * xmlXPathCastNumberToString:
3188 * @val: a number
3189 *
3190 * Converts a number to its string value.
3191 *
3192 * Returns a newly allocated string.
3193 */
3194xmlChar *
3195xmlXPathCastNumberToString (double val) {
3196 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003197 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003198 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003199 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003200 break;
3201 case -1:
3202 ret = xmlStrdup((const xmlChar *) "-Infinity");
3203 break;
3204 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003205 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003206 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003207 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3208 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003209 } else {
3210 /* could be improved */
3211 char buf[100];
3212 xmlXPathFormatNumber(val, buf, 100);
3213 ret = xmlStrdup((const xmlChar *) buf);
3214 }
3215 }
3216 return(ret);
3217}
3218
3219/**
3220 * xmlXPathCastNodeToString:
3221 * @node: a node
3222 *
3223 * Converts a node to its string value.
3224 *
3225 * Returns a newly allocated string.
3226 */
3227xmlChar *
3228xmlXPathCastNodeToString (xmlNodePtr node) {
Daniel Veillard23b1f372002-04-18 15:50:05 +00003229 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE))
3230 node = xmlDocGetRootElement((xmlDocPtr) node);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003231 return(xmlNodeGetContent(node));
3232}
3233
3234/**
3235 * xmlXPathCastNodeSetToString:
3236 * @ns: a node-set
3237 *
3238 * Converts a node-set to its string value.
3239 *
3240 * Returns a newly allocated string.
3241 */
3242xmlChar *
3243xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3244 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3245 return(xmlStrdup((const xmlChar *) ""));
3246
3247 xmlXPathNodeSetSort(ns);
3248 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3249}
3250
3251/**
3252 * xmlXPathCastToString:
3253 * @val: an XPath object
3254 *
3255 * Converts an existing object to its string() equivalent
3256 *
3257 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003258 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003259 * string object).
3260 */
3261xmlChar *
3262xmlXPathCastToString(xmlXPathObjectPtr val) {
3263 xmlChar *ret = NULL;
3264
3265 if (val == NULL)
3266 return(xmlStrdup((const xmlChar *) ""));
3267 switch (val->type) {
3268 case XPATH_UNDEFINED:
3269#ifdef DEBUG_EXPR
3270 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3271#endif
3272 ret = xmlStrdup((const xmlChar *) "");
3273 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003274 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003275 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003276 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3277 break;
3278 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003279 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003280 case XPATH_BOOLEAN:
3281 ret = xmlXPathCastBooleanToString(val->boolval);
3282 break;
3283 case XPATH_NUMBER: {
3284 ret = xmlXPathCastNumberToString(val->floatval);
3285 break;
3286 }
3287 case XPATH_USERS:
3288 case XPATH_POINT:
3289 case XPATH_RANGE:
3290 case XPATH_LOCATIONSET:
3291 TODO
3292 ret = xmlStrdup((const xmlChar *) "");
3293 break;
3294 }
3295 return(ret);
3296}
3297
3298/**
3299 * xmlXPathConvertString:
3300 * @val: an XPath object
3301 *
3302 * Converts an existing object to its string() equivalent
3303 *
3304 * Returns the new object, the old one is freed (or the operation
3305 * is done directly on @val)
3306 */
3307xmlXPathObjectPtr
3308xmlXPathConvertString(xmlXPathObjectPtr val) {
3309 xmlChar *res = NULL;
3310
3311 if (val == NULL)
3312 return(xmlXPathNewCString(""));
3313
3314 switch (val->type) {
3315 case XPATH_UNDEFINED:
3316#ifdef DEBUG_EXPR
3317 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3318#endif
3319 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003320 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003321 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003322 res = xmlXPathCastNodeSetToString(val->nodesetval);
3323 break;
3324 case XPATH_STRING:
3325 return(val);
3326 case XPATH_BOOLEAN:
3327 res = xmlXPathCastBooleanToString(val->boolval);
3328 break;
3329 case XPATH_NUMBER:
3330 res = xmlXPathCastNumberToString(val->floatval);
3331 break;
3332 case XPATH_USERS:
3333 case XPATH_POINT:
3334 case XPATH_RANGE:
3335 case XPATH_LOCATIONSET:
3336 TODO;
3337 break;
3338 }
3339 xmlXPathFreeObject(val);
3340 if (res == NULL)
3341 return(xmlXPathNewCString(""));
3342 return(xmlXPathWrapString(res));
3343}
3344
3345/**
3346 * xmlXPathCastBooleanToNumber:
3347 * @val: a boolean
3348 *
3349 * Converts a boolean to its number value
3350 *
3351 * Returns the number value
3352 */
3353double
3354xmlXPathCastBooleanToNumber(int val) {
3355 if (val)
3356 return(1.0);
3357 return(0.0);
3358}
3359
3360/**
3361 * xmlXPathCastStringToNumber:
3362 * @val: a string
3363 *
3364 * Converts a string to its number value
3365 *
3366 * Returns the number value
3367 */
3368double
3369xmlXPathCastStringToNumber(const xmlChar * val) {
3370 return(xmlXPathStringEvalNumber(val));
3371}
3372
3373/**
3374 * xmlXPathCastNodeToNumber:
3375 * @node: a node
3376 *
3377 * Converts a node to its number value
3378 *
3379 * Returns the number value
3380 */
3381double
3382xmlXPathCastNodeToNumber (xmlNodePtr node) {
3383 xmlChar *strval;
3384 double ret;
3385
3386 if (node == NULL)
3387 return(xmlXPathNAN);
3388 strval = xmlXPathCastNodeToString(node);
3389 if (strval == NULL)
3390 return(xmlXPathNAN);
3391 ret = xmlXPathCastStringToNumber(strval);
3392 xmlFree(strval);
3393
3394 return(ret);
3395}
3396
3397/**
3398 * xmlXPathCastNodeSetToNumber:
3399 * @ns: a node-set
3400 *
3401 * Converts a node-set to its number value
3402 *
3403 * Returns the number value
3404 */
3405double
3406xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3407 xmlChar *str;
3408 double ret;
3409
3410 if (ns == NULL)
3411 return(xmlXPathNAN);
3412 str = xmlXPathCastNodeSetToString(ns);
3413 ret = xmlXPathCastStringToNumber(str);
3414 xmlFree(str);
3415 return(ret);
3416}
3417
3418/**
3419 * xmlXPathCastToNumber:
3420 * @val: an XPath object
3421 *
3422 * Converts an XPath object to its number value
3423 *
3424 * Returns the number value
3425 */
3426double
3427xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3428 double ret = 0.0;
3429
3430 if (val == NULL)
3431 return(xmlXPathNAN);
3432 switch (val->type) {
3433 case XPATH_UNDEFINED:
3434#ifdef DEGUB_EXPR
3435 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3436#endif
3437 ret = xmlXPathNAN;
3438 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003439 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003440 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003441 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3442 break;
3443 case XPATH_STRING:
3444 ret = xmlXPathCastStringToNumber(val->stringval);
3445 break;
3446 case XPATH_NUMBER:
3447 ret = val->floatval;
3448 break;
3449 case XPATH_BOOLEAN:
3450 ret = xmlXPathCastBooleanToNumber(val->boolval);
3451 break;
3452 case XPATH_USERS:
3453 case XPATH_POINT:
3454 case XPATH_RANGE:
3455 case XPATH_LOCATIONSET:
3456 TODO;
3457 ret = xmlXPathNAN;
3458 break;
3459 }
3460 return(ret);
3461}
3462
3463/**
3464 * xmlXPathConvertNumber:
3465 * @val: an XPath object
3466 *
3467 * Converts an existing object to its number() equivalent
3468 *
3469 * Returns the new object, the old one is freed (or the operation
3470 * is done directly on @val)
3471 */
3472xmlXPathObjectPtr
3473xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3474 xmlXPathObjectPtr ret;
3475
3476 if (val == NULL)
3477 return(xmlXPathNewFloat(0.0));
3478 if (val->type == XPATH_NUMBER)
3479 return(val);
3480 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3481 xmlXPathFreeObject(val);
3482 return(ret);
3483}
3484
3485/**
3486 * xmlXPathCastNumberToBoolean:
3487 * @val: a number
3488 *
3489 * Converts a number to its boolean value
3490 *
3491 * Returns the boolean value
3492 */
3493int
3494xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003495 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003496 return(0);
3497 return(1);
3498}
3499
3500/**
3501 * xmlXPathCastStringToBoolean:
3502 * @val: a string
3503 *
3504 * Converts a string to its boolean value
3505 *
3506 * Returns the boolean value
3507 */
3508int
3509xmlXPathCastStringToBoolean (const xmlChar *val) {
3510 if ((val == NULL) || (xmlStrlen(val) == 0))
3511 return(0);
3512 return(1);
3513}
3514
3515/**
3516 * xmlXPathCastNodeSetToBoolean:
3517 * @ns: a node-set
3518 *
3519 * Converts a node-set to its boolean value
3520 *
3521 * Returns the boolean value
3522 */
3523int
3524xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3525 if ((ns == NULL) || (ns->nodeNr == 0))
3526 return(0);
3527 return(1);
3528}
3529
3530/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003531 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003532 * @val: an XPath object
3533 *
3534 * Converts an XPath object to its boolean value
3535 *
3536 * Returns the boolean value
3537 */
3538int
3539xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3540 int ret = 0;
3541
3542 if (val == NULL)
3543 return(0);
3544 switch (val->type) {
3545 case XPATH_UNDEFINED:
3546#ifdef DEBUG_EXPR
3547 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3548#endif
3549 ret = 0;
3550 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003551 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003552 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003553 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3554 break;
3555 case XPATH_STRING:
3556 ret = xmlXPathCastStringToBoolean(val->stringval);
3557 break;
3558 case XPATH_NUMBER:
3559 ret = xmlXPathCastNumberToBoolean(val->floatval);
3560 break;
3561 case XPATH_BOOLEAN:
3562 ret = val->boolval;
3563 break;
3564 case XPATH_USERS:
3565 case XPATH_POINT:
3566 case XPATH_RANGE:
3567 case XPATH_LOCATIONSET:
3568 TODO;
3569 ret = 0;
3570 break;
3571 }
3572 return(ret);
3573}
3574
3575
3576/**
3577 * xmlXPathConvertBoolean:
3578 * @val: an XPath object
3579 *
3580 * Converts an existing object to its boolean() equivalent
3581 *
3582 * Returns the new object, the old one is freed (or the operation
3583 * is done directly on @val)
3584 */
3585xmlXPathObjectPtr
3586xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3587 xmlXPathObjectPtr ret;
3588
3589 if (val == NULL)
3590 return(xmlXPathNewBoolean(0));
3591 if (val->type == XPATH_BOOLEAN)
3592 return(val);
3593 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3594 xmlXPathFreeObject(val);
3595 return(ret);
3596}
3597
Owen Taylor3473f882001-02-23 17:55:21 +00003598/************************************************************************
3599 * *
3600 * Routines to handle XPath contexts *
3601 * *
3602 ************************************************************************/
3603
3604/**
3605 * xmlXPathNewContext:
3606 * @doc: the XML document
3607 *
3608 * Create a new xmlXPathContext
3609 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003610 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003611 */
3612xmlXPathContextPtr
3613xmlXPathNewContext(xmlDocPtr doc) {
3614 xmlXPathContextPtr ret;
3615
3616 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3617 if (ret == NULL) {
3618 xmlGenericError(xmlGenericErrorContext,
3619 "xmlXPathNewContext: out of memory\n");
3620 return(NULL);
3621 }
3622 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3623 ret->doc = doc;
3624 ret->node = NULL;
3625
3626 ret->varHash = NULL;
3627
3628 ret->nb_types = 0;
3629 ret->max_types = 0;
3630 ret->types = NULL;
3631
3632 ret->funcHash = xmlHashCreate(0);
3633
3634 ret->nb_axis = 0;
3635 ret->max_axis = 0;
3636 ret->axis = NULL;
3637
3638 ret->nsHash = NULL;
3639 ret->user = NULL;
3640
3641 ret->contextSize = -1;
3642 ret->proximityPosition = -1;
3643
3644 xmlXPathRegisterAllFunctions(ret);
3645
3646 return(ret);
3647}
3648
3649/**
3650 * xmlXPathFreeContext:
3651 * @ctxt: the context to free
3652 *
3653 * Free up an xmlXPathContext
3654 */
3655void
3656xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3657 xmlXPathRegisteredNsCleanup(ctxt);
3658 xmlXPathRegisteredFuncsCleanup(ctxt);
3659 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003660 xmlFree(ctxt);
3661}
3662
3663/************************************************************************
3664 * *
3665 * Routines to handle XPath parser contexts *
3666 * *
3667 ************************************************************************/
3668
3669#define CHECK_CTXT(ctxt) \
3670 if (ctxt == NULL) { \
3671 xmlGenericError(xmlGenericErrorContext, \
3672 "%s:%d Internal error: ctxt == NULL\n", \
3673 __FILE__, __LINE__); \
3674 } \
3675
3676
3677#define CHECK_CONTEXT(ctxt) \
3678 if (ctxt == NULL) { \
3679 xmlGenericError(xmlGenericErrorContext, \
3680 "%s:%d Internal error: no context\n", \
3681 __FILE__, __LINE__); \
3682 } \
3683 else if (ctxt->doc == NULL) { \
3684 xmlGenericError(xmlGenericErrorContext, \
3685 "%s:%d Internal error: no document\n", \
3686 __FILE__, __LINE__); \
3687 } \
3688 else if (ctxt->doc->children == NULL) { \
3689 xmlGenericError(xmlGenericErrorContext, \
3690 "%s:%d Internal error: document without root\n", \
3691 __FILE__, __LINE__); \
3692 } \
3693
3694
3695/**
3696 * xmlXPathNewParserContext:
3697 * @str: the XPath expression
3698 * @ctxt: the XPath context
3699 *
3700 * Create a new xmlXPathParserContext
3701 *
3702 * Returns the xmlXPathParserContext just allocated.
3703 */
3704xmlXPathParserContextPtr
3705xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3706 xmlXPathParserContextPtr ret;
3707
3708 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3709 if (ret == NULL) {
3710 xmlGenericError(xmlGenericErrorContext,
3711 "xmlXPathNewParserContext: out of memory\n");
3712 return(NULL);
3713 }
3714 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3715 ret->cur = ret->base = str;
3716 ret->context = ctxt;
3717
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003718 ret->comp = xmlXPathNewCompExpr();
3719 if (ret->comp == NULL) {
3720 xmlFree(ret->valueTab);
3721 xmlFree(ret);
3722 return(NULL);
3723 }
3724
3725 return(ret);
3726}
3727
3728/**
3729 * xmlXPathCompParserContext:
3730 * @comp: the XPath compiled expression
3731 * @ctxt: the XPath context
3732 *
3733 * Create a new xmlXPathParserContext when processing a compiled expression
3734 *
3735 * Returns the xmlXPathParserContext just allocated.
3736 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003737static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003738xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3739 xmlXPathParserContextPtr ret;
3740
3741 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3742 if (ret == NULL) {
3743 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003744 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003745 return(NULL);
3746 }
3747 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3748
Owen Taylor3473f882001-02-23 17:55:21 +00003749 /* Allocate the value stack */
3750 ret->valueTab = (xmlXPathObjectPtr *)
3751 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003752 if (ret->valueTab == NULL) {
3753 xmlFree(ret);
3754 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003755 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003756 return(NULL);
3757 }
Owen Taylor3473f882001-02-23 17:55:21 +00003758 ret->valueNr = 0;
3759 ret->valueMax = 10;
3760 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003761
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003762 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003763 ret->comp = comp;
3764
Owen Taylor3473f882001-02-23 17:55:21 +00003765 return(ret);
3766}
3767
3768/**
3769 * xmlXPathFreeParserContext:
3770 * @ctxt: the context to free
3771 *
3772 * Free up an xmlXPathParserContext
3773 */
3774void
3775xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3776 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003777 xmlFree(ctxt->valueTab);
3778 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003779 if (ctxt->comp)
3780 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003781 xmlFree(ctxt);
3782}
3783
3784/************************************************************************
3785 * *
3786 * The implicit core function library *
3787 * *
3788 ************************************************************************/
3789
Owen Taylor3473f882001-02-23 17:55:21 +00003790/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003791 * xmlXPathNodeStringHash:
3792 * @node: a node pointer
3793 *
3794 * Function computing the beginning of the string value of the node,
3795 * used to speed up comparisons
3796 *
3797 * Returns an int usable as a hash
3798 */
3799static unsigned int
3800xmlXPathNodeValHash(xmlNodePtr node) {
3801 int len = 2;
3802 const xmlChar * string = NULL;
3803 xmlNodePtr tmp = NULL;
3804 unsigned int ret = 0;
3805
3806 if (node == NULL)
3807 return(0);
3808
3809
3810 switch (node->type) {
3811 case XML_COMMENT_NODE:
3812 case XML_PI_NODE:
3813 case XML_CDATA_SECTION_NODE:
3814 case XML_TEXT_NODE:
3815 string = node->content;
3816 if (string == NULL)
3817 return(0);
3818 if (string[0] == 0)
3819 return(0);
3820 return(((unsigned int) string[0]) +
3821 (((unsigned int) string[1]) << 8));
3822 case XML_NAMESPACE_DECL:
3823 string = ((xmlNsPtr)node)->href;
3824 if (string == NULL)
3825 return(0);
3826 if (string[0] == 0)
3827 return(0);
3828 return(((unsigned int) string[0]) +
3829 (((unsigned int) string[1]) << 8));
3830 case XML_ATTRIBUTE_NODE:
3831 tmp = ((xmlAttrPtr) node)->children;
3832 break;
3833 case XML_ELEMENT_NODE:
3834 tmp = node->children;
3835 break;
3836 default:
3837 return(0);
3838 }
3839 while (tmp != NULL) {
3840 switch (tmp->type) {
3841 case XML_COMMENT_NODE:
3842 case XML_PI_NODE:
3843 case XML_CDATA_SECTION_NODE:
3844 case XML_TEXT_NODE:
3845 string = tmp->content;
3846 break;
3847 case XML_NAMESPACE_DECL:
3848 string = ((xmlNsPtr)tmp)->href;
3849 break;
3850 default:
3851 break;
3852 }
3853 if ((string != NULL) && (string[0] != 0)) {
3854 if (string[0] == 0)
3855 return(0);
3856 if (len == 1) {
3857 return(ret + (((unsigned int) string[0]) << 8));
3858 }
3859 if (string[1] == 0) {
3860 len = 1;
3861 ret = (unsigned int) string[0];
3862 } else {
3863 return(((unsigned int) string[0]) +
3864 (((unsigned int) string[1]) << 8));
3865 }
3866 }
3867 /*
3868 * Skip to next node
3869 */
3870 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3871 if (tmp->children->type != XML_ENTITY_DECL) {
3872 tmp = tmp->children;
3873 continue;
3874 }
3875 }
3876 if (tmp == node)
3877 break;
3878
3879 if (tmp->next != NULL) {
3880 tmp = tmp->next;
3881 continue;
3882 }
3883
3884 do {
3885 tmp = tmp->parent;
3886 if (tmp == NULL)
3887 break;
3888 if (tmp == node) {
3889 tmp = NULL;
3890 break;
3891 }
3892 if (tmp->next != NULL) {
3893 tmp = tmp->next;
3894 break;
3895 }
3896 } while (tmp != NULL);
3897 }
3898 return(ret);
3899}
3900
3901/**
3902 * xmlXPathStringHash:
3903 * @string: a string
3904 *
3905 * Function computing the beginning of the string value of the node,
3906 * used to speed up comparisons
3907 *
3908 * Returns an int usable as a hash
3909 */
3910static unsigned int
3911xmlXPathStringHash(const xmlChar * string) {
3912 if (string == NULL)
3913 return((unsigned int) 0);
3914 if (string[0] == 0)
3915 return(0);
3916 return(((unsigned int) string[0]) +
3917 (((unsigned int) string[1]) << 8));
3918}
3919
3920/**
Owen Taylor3473f882001-02-23 17:55:21 +00003921 * xmlXPathCompareNodeSetFloat:
3922 * @ctxt: the XPath Parser context
3923 * @inf: less than (1) or greater than (0)
3924 * @strict: is the comparison strict
3925 * @arg: the node set
3926 * @f: the value
3927 *
3928 * Implement the compare operation between a nodeset and a number
3929 * @ns < @val (1, 1, ...
3930 * @ns <= @val (1, 0, ...
3931 * @ns > @val (0, 1, ...
3932 * @ns >= @val (0, 0, ...
3933 *
3934 * If one object to be compared is a node-set and the other is a number,
3935 * then the comparison will be true if and only if there is a node in the
3936 * node-set such that the result of performing the comparison on the number
3937 * to be compared and on the result of converting the string-value of that
3938 * node to a number using the number function is true.
3939 *
3940 * Returns 0 or 1 depending on the results of the test.
3941 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003942static int
Owen Taylor3473f882001-02-23 17:55:21 +00003943xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3944 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3945 int i, ret = 0;
3946 xmlNodeSetPtr ns;
3947 xmlChar *str2;
3948
3949 if ((f == NULL) || (arg == NULL) ||
3950 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3951 xmlXPathFreeObject(arg);
3952 xmlXPathFreeObject(f);
3953 return(0);
3954 }
3955 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003956 if (ns != NULL) {
3957 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003958 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003959 if (str2 != NULL) {
3960 valuePush(ctxt,
3961 xmlXPathNewString(str2));
3962 xmlFree(str2);
3963 xmlXPathNumberFunction(ctxt, 1);
3964 valuePush(ctxt, xmlXPathObjectCopy(f));
3965 ret = xmlXPathCompareValues(ctxt, inf, strict);
3966 if (ret)
3967 break;
3968 }
3969 }
Owen Taylor3473f882001-02-23 17:55:21 +00003970 }
3971 xmlXPathFreeObject(arg);
3972 xmlXPathFreeObject(f);
3973 return(ret);
3974}
3975
3976/**
3977 * xmlXPathCompareNodeSetString:
3978 * @ctxt: the XPath Parser context
3979 * @inf: less than (1) or greater than (0)
3980 * @strict: is the comparison strict
3981 * @arg: the node set
3982 * @s: the value
3983 *
3984 * Implement the compare operation between a nodeset and a string
3985 * @ns < @val (1, 1, ...
3986 * @ns <= @val (1, 0, ...
3987 * @ns > @val (0, 1, ...
3988 * @ns >= @val (0, 0, ...
3989 *
3990 * If one object to be compared is a node-set and the other is a string,
3991 * then the comparison will be true if and only if there is a node in
3992 * the node-set such that the result of performing the comparison on the
3993 * string-value of the node and the other string is true.
3994 *
3995 * Returns 0 or 1 depending on the results of the test.
3996 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003997static int
Owen Taylor3473f882001-02-23 17:55:21 +00003998xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3999 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4000 int i, ret = 0;
4001 xmlNodeSetPtr ns;
4002 xmlChar *str2;
4003
4004 if ((s == NULL) || (arg == NULL) ||
4005 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4006 xmlXPathFreeObject(arg);
4007 xmlXPathFreeObject(s);
4008 return(0);
4009 }
4010 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004011 if (ns != NULL) {
4012 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004013 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004014 if (str2 != NULL) {
4015 valuePush(ctxt,
4016 xmlXPathNewString(str2));
4017 xmlFree(str2);
4018 valuePush(ctxt, xmlXPathObjectCopy(s));
4019 ret = xmlXPathCompareValues(ctxt, inf, strict);
4020 if (ret)
4021 break;
4022 }
4023 }
Owen Taylor3473f882001-02-23 17:55:21 +00004024 }
4025 xmlXPathFreeObject(arg);
4026 xmlXPathFreeObject(s);
4027 return(ret);
4028}
4029
4030/**
4031 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004032 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004033 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004034 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004035 * @arg2: the second node set object
4036 *
4037 * Implement the compare operation on nodesets:
4038 *
4039 * If both objects to be compared are node-sets, then the comparison
4040 * will be true if and only if there is a node in the first node-set
4041 * and a node in the second node-set such that the result of performing
4042 * the comparison on the string-values of the two nodes is true.
4043 * ....
4044 * When neither object to be compared is a node-set and the operator
4045 * is <=, <, >= or >, then the objects are compared by converting both
4046 * objects to numbers and comparing the numbers according to IEEE 754.
4047 * ....
4048 * The number function converts its argument to a number as follows:
4049 * - a string that consists of optional whitespace followed by an
4050 * optional minus sign followed by a Number followed by whitespace
4051 * is converted to the IEEE 754 number that is nearest (according
4052 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4053 * represented by the string; any other string is converted to NaN
4054 *
4055 * Conclusion all nodes need to be converted first to their string value
4056 * and then the comparison must be done when possible
4057 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004058static int
4059xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004060 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4061 int i, j, init = 0;
4062 double val1;
4063 double *values2;
4064 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004065 xmlNodeSetPtr ns1;
4066 xmlNodeSetPtr ns2;
4067
4068 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004069 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4070 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004071 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004072 }
Owen Taylor3473f882001-02-23 17:55:21 +00004073 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004074 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4075 xmlXPathFreeObject(arg1);
4076 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004077 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004078 }
Owen Taylor3473f882001-02-23 17:55:21 +00004079
4080 ns1 = arg1->nodesetval;
4081 ns2 = arg2->nodesetval;
4082
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004083 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004084 xmlXPathFreeObject(arg1);
4085 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004086 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004087 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004088 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004089 xmlXPathFreeObject(arg1);
4090 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004091 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004092 }
Owen Taylor3473f882001-02-23 17:55:21 +00004093
4094 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4095 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004096 xmlXPathFreeObject(arg1);
4097 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004098 return(0);
4099 }
4100 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004101 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004102 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004103 continue;
4104 for (j = 0;j < ns2->nodeNr;j++) {
4105 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004106 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004107 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004108 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004109 continue;
4110 if (inf && strict)
4111 ret = (val1 < values2[j]);
4112 else if (inf && !strict)
4113 ret = (val1 <= values2[j]);
4114 else if (!inf && strict)
4115 ret = (val1 > values2[j]);
4116 else if (!inf && !strict)
4117 ret = (val1 >= values2[j]);
4118 if (ret)
4119 break;
4120 }
4121 if (ret)
4122 break;
4123 init = 1;
4124 }
4125 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004126 xmlXPathFreeObject(arg1);
4127 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004128 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004129}
4130
4131/**
4132 * xmlXPathCompareNodeSetValue:
4133 * @ctxt: the XPath Parser context
4134 * @inf: less than (1) or greater than (0)
4135 * @strict: is the comparison strict
4136 * @arg: the node set
4137 * @val: the value
4138 *
4139 * Implement the compare operation between a nodeset and a value
4140 * @ns < @val (1, 1, ...
4141 * @ns <= @val (1, 0, ...
4142 * @ns > @val (0, 1, ...
4143 * @ns >= @val (0, 0, ...
4144 *
4145 * If one object to be compared is a node-set and the other is a boolean,
4146 * then the comparison will be true if and only if the result of performing
4147 * the comparison on the boolean and on the result of converting
4148 * the node-set to a boolean using the boolean function is true.
4149 *
4150 * Returns 0 or 1 depending on the results of the test.
4151 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004152static int
Owen Taylor3473f882001-02-23 17:55:21 +00004153xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4154 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4155 if ((val == NULL) || (arg == NULL) ||
4156 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4157 return(0);
4158
4159 switch(val->type) {
4160 case XPATH_NUMBER:
4161 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4162 case XPATH_NODESET:
4163 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004164 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004165 case XPATH_STRING:
4166 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4167 case XPATH_BOOLEAN:
4168 valuePush(ctxt, arg);
4169 xmlXPathBooleanFunction(ctxt, 1);
4170 valuePush(ctxt, val);
4171 return(xmlXPathCompareValues(ctxt, inf, strict));
4172 default:
4173 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004174 }
4175 return(0);
4176}
4177
4178/**
4179 * xmlXPathEqualNodeSetString
4180 * @arg: the nodeset object argument
4181 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004182 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004183 *
4184 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4185 * If one object to be compared is a node-set and the other is a string,
4186 * then the comparison will be true if and only if there is a node in
4187 * the node-set such that the result of performing the comparison on the
4188 * string-value of the node and the other string is true.
4189 *
4190 * Returns 0 or 1 depending on the results of the test.
4191 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004192static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004193xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004194{
Owen Taylor3473f882001-02-23 17:55:21 +00004195 int i;
4196 xmlNodeSetPtr ns;
4197 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004198 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004199
4200 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004201 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4202 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004203 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004204 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004205 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004206 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004207 if (ns->nodeNr <= 0) {
4208 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004209 return(neq ^ 1);
4210 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004211 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004212 for (i = 0; i < ns->nodeNr; i++) {
4213 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4214 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4215 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4216 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004217 if (neq)
4218 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004219 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004220 } else if (neq) {
4221 if (str2 != NULL)
4222 xmlFree(str2);
4223 return (1);
4224 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004225 if (str2 != NULL)
4226 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004227 } else if (neq)
4228 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004229 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004230 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004231}
4232
4233/**
4234 * xmlXPathEqualNodeSetFloat
4235 * @arg: the nodeset object argument
4236 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004237 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004238 *
4239 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4240 * If one object to be compared is a node-set and the other is a number,
4241 * then the comparison will be true if and only if there is a node in
4242 * the node-set such that the result of performing the comparison on the
4243 * number to be compared and on the result of converting the string-value
4244 * of that node to a number using the number function is true.
4245 *
4246 * Returns 0 or 1 depending on the results of the test.
4247 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004248static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004249xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4250 xmlXPathObjectPtr arg, double f, int neq) {
4251 int i, ret=0;
4252 xmlNodeSetPtr ns;
4253 xmlChar *str2;
4254 xmlXPathObjectPtr val;
4255 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004256
4257 if ((arg == NULL) ||
4258 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4259 return(0);
4260
William M. Brack0c022ad2002-07-12 00:56:01 +00004261 ns = arg->nodesetval;
4262 if (ns != NULL) {
4263 for (i=0;i<ns->nodeNr;i++) {
4264 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4265 if (str2 != NULL) {
4266 valuePush(ctxt, xmlXPathNewString(str2));
4267 xmlFree(str2);
4268 xmlXPathNumberFunction(ctxt, 1);
4269 val = valuePop(ctxt);
4270 v = val->floatval;
4271 xmlXPathFreeObject(val);
4272 if (!xmlXPathIsNaN(v)) {
4273 if ((!neq) && (v==f)) {
4274 ret = 1;
4275 break;
4276 } else if ((neq) && (v!=f)) {
4277 ret = 1;
4278 break;
4279 }
4280 }
4281 }
4282 }
4283 }
4284
4285 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004286}
4287
4288
4289/**
4290 * xmlXPathEqualNodeSets
4291 * @arg1: first nodeset object argument
4292 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004293 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004294 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004295 * Implement the equal / not equal operation on XPath nodesets:
4296 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004297 * If both objects to be compared are node-sets, then the comparison
4298 * will be true if and only if there is a node in the first node-set and
4299 * a node in the second node-set such that the result of performing the
4300 * comparison on the string-values of the two nodes is true.
4301 *
4302 * (needless to say, this is a costly operation)
4303 *
4304 * Returns 0 or 1 depending on the results of the test.
4305 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004306static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004307xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004308 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004309 unsigned int *hashs1;
4310 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004311 xmlChar **values1;
4312 xmlChar **values2;
4313 int ret = 0;
4314 xmlNodeSetPtr ns1;
4315 xmlNodeSetPtr ns2;
4316
4317 if ((arg1 == NULL) ||
4318 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4319 return(0);
4320 if ((arg2 == NULL) ||
4321 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4322 return(0);
4323
4324 ns1 = arg1->nodesetval;
4325 ns2 = arg2->nodesetval;
4326
Daniel Veillard911f49a2001-04-07 15:39:35 +00004327 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004328 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004329 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004330 return(0);
4331
4332 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004333 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004334 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004335 if (neq == 0)
4336 for (i = 0;i < ns1->nodeNr;i++)
4337 for (j = 0;j < ns2->nodeNr;j++)
4338 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4339 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004340
4341 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4342 if (values1 == NULL)
4343 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004344 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4345 if (hashs1 == NULL) {
4346 xmlFree(values1);
4347 return(0);
4348 }
Owen Taylor3473f882001-02-23 17:55:21 +00004349 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4350 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4351 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004352 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004353 xmlFree(values1);
4354 return(0);
4355 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004356 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4357 if (hashs2 == NULL) {
4358 xmlFree(hashs1);
4359 xmlFree(values1);
4360 xmlFree(values2);
4361 return(0);
4362 }
Owen Taylor3473f882001-02-23 17:55:21 +00004363 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4364 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004365 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004366 for (j = 0;j < ns2->nodeNr;j++) {
4367 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004368 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004369 if (hashs1[i] != hashs2[j]) {
4370 if (neq) {
4371 ret = 1;
4372 break;
4373 }
4374 }
4375 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004376 if (values1[i] == NULL)
4377 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4378 if (values2[j] == NULL)
4379 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004380 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004381 if (ret)
4382 break;
4383 }
Owen Taylor3473f882001-02-23 17:55:21 +00004384 }
4385 if (ret)
4386 break;
4387 }
4388 for (i = 0;i < ns1->nodeNr;i++)
4389 if (values1[i] != NULL)
4390 xmlFree(values1[i]);
4391 for (j = 0;j < ns2->nodeNr;j++)
4392 if (values2[j] != NULL)
4393 xmlFree(values2[j]);
4394 xmlFree(values1);
4395 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004396 xmlFree(hashs1);
4397 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004398 return(ret);
4399}
4400
William M. Brack0c022ad2002-07-12 00:56:01 +00004401static int
4402xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4403 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004404 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004405 /*
4406 *At this point we are assured neither arg1 nor arg2
4407 *is a nodeset, so we can just pick the appropriate routine.
4408 */
Owen Taylor3473f882001-02-23 17:55:21 +00004409 switch (arg1->type) {
4410 case XPATH_UNDEFINED:
4411#ifdef DEBUG_EXPR
4412 xmlGenericError(xmlGenericErrorContext,
4413 "Equal: undefined\n");
4414#endif
4415 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004416 case XPATH_BOOLEAN:
4417 switch (arg2->type) {
4418 case XPATH_UNDEFINED:
4419#ifdef DEBUG_EXPR
4420 xmlGenericError(xmlGenericErrorContext,
4421 "Equal: undefined\n");
4422#endif
4423 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004424 case XPATH_BOOLEAN:
4425#ifdef DEBUG_EXPR
4426 xmlGenericError(xmlGenericErrorContext,
4427 "Equal: %d boolean %d \n",
4428 arg1->boolval, arg2->boolval);
4429#endif
4430 ret = (arg1->boolval == arg2->boolval);
4431 break;
4432 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004433 ret = (arg1->boolval ==
4434 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004435 break;
4436 case XPATH_STRING:
4437 if ((arg2->stringval == NULL) ||
4438 (arg2->stringval[0] == 0)) ret = 0;
4439 else
4440 ret = 1;
4441 ret = (arg1->boolval == ret);
4442 break;
4443 case XPATH_USERS:
4444 case XPATH_POINT:
4445 case XPATH_RANGE:
4446 case XPATH_LOCATIONSET:
4447 TODO
4448 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004449 case XPATH_NODESET:
4450 case XPATH_XSLT_TREE:
4451 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004452 }
4453 break;
4454 case XPATH_NUMBER:
4455 switch (arg2->type) {
4456 case XPATH_UNDEFINED:
4457#ifdef DEBUG_EXPR
4458 xmlGenericError(xmlGenericErrorContext,
4459 "Equal: undefined\n");
4460#endif
4461 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004462 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004463 ret = (arg2->boolval==
4464 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004465 break;
4466 case XPATH_STRING:
4467 valuePush(ctxt, arg2);
4468 xmlXPathNumberFunction(ctxt, 1);
4469 arg2 = valuePop(ctxt);
4470 /* no break on purpose */
4471 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004472 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004473 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4474 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004475 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4476 if (xmlXPathIsInf(arg2->floatval) == 1)
4477 ret = 1;
4478 else
4479 ret = 0;
4480 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4481 if (xmlXPathIsInf(arg2->floatval) == -1)
4482 ret = 1;
4483 else
4484 ret = 0;
4485 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4486 if (xmlXPathIsInf(arg1->floatval) == 1)
4487 ret = 1;
4488 else
4489 ret = 0;
4490 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4491 if (xmlXPathIsInf(arg1->floatval) == -1)
4492 ret = 1;
4493 else
4494 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004495 } else {
4496 ret = (arg1->floatval == arg2->floatval);
4497 }
Owen Taylor3473f882001-02-23 17:55:21 +00004498 break;
4499 case XPATH_USERS:
4500 case XPATH_POINT:
4501 case XPATH_RANGE:
4502 case XPATH_LOCATIONSET:
4503 TODO
4504 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004505 case XPATH_NODESET:
4506 case XPATH_XSLT_TREE:
4507 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004508 }
4509 break;
4510 case XPATH_STRING:
4511 switch (arg2->type) {
4512 case XPATH_UNDEFINED:
4513#ifdef DEBUG_EXPR
4514 xmlGenericError(xmlGenericErrorContext,
4515 "Equal: undefined\n");
4516#endif
4517 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004518 case XPATH_BOOLEAN:
4519 if ((arg1->stringval == NULL) ||
4520 (arg1->stringval[0] == 0)) ret = 0;
4521 else
4522 ret = 1;
4523 ret = (arg2->boolval == ret);
4524 break;
4525 case XPATH_STRING:
4526 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4527 break;
4528 case XPATH_NUMBER:
4529 valuePush(ctxt, arg1);
4530 xmlXPathNumberFunction(ctxt, 1);
4531 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004532 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004533 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4534 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004535 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4536 if (xmlXPathIsInf(arg2->floatval) == 1)
4537 ret = 1;
4538 else
4539 ret = 0;
4540 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4541 if (xmlXPathIsInf(arg2->floatval) == -1)
4542 ret = 1;
4543 else
4544 ret = 0;
4545 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4546 if (xmlXPathIsInf(arg1->floatval) == 1)
4547 ret = 1;
4548 else
4549 ret = 0;
4550 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4551 if (xmlXPathIsInf(arg1->floatval) == -1)
4552 ret = 1;
4553 else
4554 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004555 } else {
4556 ret = (arg1->floatval == arg2->floatval);
4557 }
Owen Taylor3473f882001-02-23 17:55:21 +00004558 break;
4559 case XPATH_USERS:
4560 case XPATH_POINT:
4561 case XPATH_RANGE:
4562 case XPATH_LOCATIONSET:
4563 TODO
4564 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004565 case XPATH_NODESET:
4566 case XPATH_XSLT_TREE:
4567 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004568 }
4569 break;
4570 case XPATH_USERS:
4571 case XPATH_POINT:
4572 case XPATH_RANGE:
4573 case XPATH_LOCATIONSET:
4574 TODO
4575 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004576 case XPATH_NODESET:
4577 case XPATH_XSLT_TREE:
4578 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004579 }
4580 xmlXPathFreeObject(arg1);
4581 xmlXPathFreeObject(arg2);
4582 return(ret);
4583}
4584
William M. Brack0c022ad2002-07-12 00:56:01 +00004585/**
4586 * xmlXPathEqualValues:
4587 * @ctxt: the XPath Parser context
4588 *
4589 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4590 *
4591 * Returns 0 or 1 depending on the results of the test.
4592 */
4593int
4594xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4595 xmlXPathObjectPtr arg1, arg2, argtmp;
4596 int ret = 0;
4597
4598 arg2 = valuePop(ctxt);
4599 arg1 = valuePop(ctxt);
4600 if ((arg1 == NULL) || (arg2 == NULL)) {
4601 if (arg1 != NULL)
4602 xmlXPathFreeObject(arg1);
4603 else
4604 xmlXPathFreeObject(arg2);
4605 XP_ERROR0(XPATH_INVALID_OPERAND);
4606 }
4607
4608 if (arg1 == arg2) {
4609#ifdef DEBUG_EXPR
4610 xmlGenericError(xmlGenericErrorContext,
4611 "Equal: by pointer\n");
4612#endif
4613 return(1);
4614 }
4615
4616 /*
4617 *If either argument is a nodeset, it's a 'special case'
4618 */
4619 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4620 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4621 /*
4622 *Hack it to assure arg1 is the nodeset
4623 */
4624 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4625 argtmp = arg2;
4626 arg2 = arg1;
4627 arg1 = argtmp;
4628 }
4629 switch (arg2->type) {
4630 case XPATH_UNDEFINED:
4631#ifdef DEBUG_EXPR
4632 xmlGenericError(xmlGenericErrorContext,
4633 "Equal: undefined\n");
4634#endif
4635 break;
4636 case XPATH_NODESET:
4637 case XPATH_XSLT_TREE:
4638 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4639 break;
4640 case XPATH_BOOLEAN:
4641 if ((arg1->nodesetval == NULL) ||
4642 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4643 else
4644 ret = 1;
4645 ret = (ret == arg2->boolval);
4646 break;
4647 case XPATH_NUMBER:
4648 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4649 break;
4650 case XPATH_STRING:
4651 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4652 break;
4653 case XPATH_USERS:
4654 case XPATH_POINT:
4655 case XPATH_RANGE:
4656 case XPATH_LOCATIONSET:
4657 TODO
4658 break;
4659 }
4660 xmlXPathFreeObject(arg1);
4661 xmlXPathFreeObject(arg2);
4662 return(ret);
4663 }
4664
4665 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4666}
4667
4668/**
4669 * xmlXPathNotEqualValues:
4670 * @ctxt: the XPath Parser context
4671 *
4672 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4673 *
4674 * Returns 0 or 1 depending on the results of the test.
4675 */
4676int
4677xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4678 xmlXPathObjectPtr arg1, arg2, argtmp;
4679 int ret = 0;
4680
4681 arg2 = valuePop(ctxt);
4682 arg1 = valuePop(ctxt);
4683 if ((arg1 == NULL) || (arg2 == NULL)) {
4684 if (arg1 != NULL)
4685 xmlXPathFreeObject(arg1);
4686 else
4687 xmlXPathFreeObject(arg2);
4688 XP_ERROR0(XPATH_INVALID_OPERAND);
4689 }
4690
4691 if (arg1 == arg2) {
4692#ifdef DEBUG_EXPR
4693 xmlGenericError(xmlGenericErrorContext,
4694 "NotEqual: by pointer\n");
4695#endif
4696 return(0);
4697 }
4698
4699 /*
4700 *If either argument is a nodeset, it's a 'special case'
4701 */
4702 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4703 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4704 /*
4705 *Hack it to assure arg1 is the nodeset
4706 */
4707 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4708 argtmp = arg2;
4709 arg2 = arg1;
4710 arg1 = argtmp;
4711 }
4712 switch (arg2->type) {
4713 case XPATH_UNDEFINED:
4714#ifdef DEBUG_EXPR
4715 xmlGenericError(xmlGenericErrorContext,
4716 "NotEqual: undefined\n");
4717#endif
4718 break;
4719 case XPATH_NODESET:
4720 case XPATH_XSLT_TREE:
4721 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4722 break;
4723 case XPATH_BOOLEAN:
4724 if ((arg1->nodesetval == NULL) ||
4725 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4726 else
4727 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004728 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004729 break;
4730 case XPATH_NUMBER:
4731 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4732 break;
4733 case XPATH_STRING:
4734 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4735 break;
4736 case XPATH_USERS:
4737 case XPATH_POINT:
4738 case XPATH_RANGE:
4739 case XPATH_LOCATIONSET:
4740 TODO
4741 break;
4742 }
4743 xmlXPathFreeObject(arg1);
4744 xmlXPathFreeObject(arg2);
4745 return(ret);
4746 }
4747
4748 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4749}
Owen Taylor3473f882001-02-23 17:55:21 +00004750
4751/**
4752 * xmlXPathCompareValues:
4753 * @ctxt: the XPath Parser context
4754 * @inf: less than (1) or greater than (0)
4755 * @strict: is the comparison strict
4756 *
4757 * Implement the compare operation on XPath objects:
4758 * @arg1 < @arg2 (1, 1, ...
4759 * @arg1 <= @arg2 (1, 0, ...
4760 * @arg1 > @arg2 (0, 1, ...
4761 * @arg1 >= @arg2 (0, 0, ...
4762 *
4763 * When neither object to be compared is a node-set and the operator is
4764 * <=, <, >=, >, then the objects are compared by converted both objects
4765 * to numbers and comparing the numbers according to IEEE 754. The <
4766 * comparison will be true if and only if the first number is less than the
4767 * second number. The <= comparison will be true if and only if the first
4768 * number is less than or equal to the second number. The > comparison
4769 * will be true if and only if the first number is greater than the second
4770 * number. The >= comparison will be true if and only if the first number
4771 * is greater than or equal to the second number.
4772 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004773 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004774 */
4775int
4776xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004777 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004778 xmlXPathObjectPtr arg1, arg2;
4779
William M. Brack0c022ad2002-07-12 00:56:01 +00004780 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004781 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004782 if ((arg1 == NULL) || (arg2 == NULL)) {
4783 if (arg1 != NULL)
4784 xmlXPathFreeObject(arg1);
4785 else
4786 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004787 XP_ERROR0(XPATH_INVALID_OPERAND);
4788 }
4789
William M. Brack0c022ad2002-07-12 00:56:01 +00004790 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4791 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4792 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4793 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004794 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004795 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004796 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004797 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4798 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004799 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004800 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4801 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004802 }
4803 }
4804 return(ret);
4805 }
4806
4807 if (arg1->type != XPATH_NUMBER) {
4808 valuePush(ctxt, arg1);
4809 xmlXPathNumberFunction(ctxt, 1);
4810 arg1 = valuePop(ctxt);
4811 }
4812 if (arg1->type != XPATH_NUMBER) {
4813 xmlXPathFreeObject(arg1);
4814 xmlXPathFreeObject(arg2);
4815 XP_ERROR0(XPATH_INVALID_OPERAND);
4816 }
4817 if (arg2->type != XPATH_NUMBER) {
4818 valuePush(ctxt, arg2);
4819 xmlXPathNumberFunction(ctxt, 1);
4820 arg2 = valuePop(ctxt);
4821 }
4822 if (arg2->type != XPATH_NUMBER) {
4823 xmlXPathFreeObject(arg1);
4824 xmlXPathFreeObject(arg2);
4825 XP_ERROR0(XPATH_INVALID_OPERAND);
4826 }
4827 /*
4828 * Add tests for infinity and nan
4829 * => feedback on 3.4 for Inf and NaN
4830 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004831 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004832 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004833 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004834 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004835 arg1i=xmlXPathIsInf(arg1->floatval);
4836 arg2i=xmlXPathIsInf(arg2->floatval);
4837 if (inf && strict) {
4838 if ((arg1i == -1 && arg2i != -1) ||
4839 (arg2i == 1 && arg1i != 1)) {
4840 ret = 1;
4841 } else if (arg1i == 0 && arg2i == 0) {
4842 ret = (arg1->floatval < arg2->floatval);
4843 } else {
4844 ret = 0;
4845 }
4846 }
4847 else if (inf && !strict) {
4848 if (arg1i == -1 || arg2i == 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 (arg2i == -1 && arg1i != -1)) {
4859 ret = 1;
4860 } else if (arg1i == 0 && arg2i == 0) {
4861 ret = (arg1->floatval > arg2->floatval);
4862 } else {
4863 ret = 0;
4864 }
4865 }
4866 else if (!inf && !strict) {
4867 if (arg1i == 1 || arg2i == -1) {
4868 ret = 1;
4869 } else if (arg1i == 0 && arg2i == 0) {
4870 ret = (arg1->floatval >= arg2->floatval);
4871 } else {
4872 ret = 0;
4873 }
4874 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004875 }
Owen Taylor3473f882001-02-23 17:55:21 +00004876 xmlXPathFreeObject(arg1);
4877 xmlXPathFreeObject(arg2);
4878 return(ret);
4879}
4880
4881/**
4882 * xmlXPathValueFlipSign:
4883 * @ctxt: the XPath Parser context
4884 *
4885 * Implement the unary - operation on an XPath object
4886 * The numeric operators convert their operands to numbers as if
4887 * by calling the number function.
4888 */
4889void
4890xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004891 CAST_TO_NUMBER;
4892 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004893 if (xmlXPathIsNaN(ctxt->value->floatval))
4894 ctxt->value->floatval=xmlXPathNAN;
4895 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4896 ctxt->value->floatval=xmlXPathNINF;
4897 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4898 ctxt->value->floatval=xmlXPathPINF;
4899 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004900 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4901 ctxt->value->floatval = xmlXPathNZERO;
4902 else
4903 ctxt->value->floatval = 0;
4904 }
4905 else
4906 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004907}
4908
4909/**
4910 * xmlXPathAddValues:
4911 * @ctxt: the XPath Parser context
4912 *
4913 * Implement the add operation on XPath objects:
4914 * The numeric operators convert their operands to numbers as if
4915 * by calling the number function.
4916 */
4917void
4918xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4919 xmlXPathObjectPtr arg;
4920 double val;
4921
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004922 arg = valuePop(ctxt);
4923 if (arg == NULL)
4924 XP_ERROR(XPATH_INVALID_OPERAND);
4925 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004926 xmlXPathFreeObject(arg);
4927
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004928 CAST_TO_NUMBER;
4929 CHECK_TYPE(XPATH_NUMBER);
4930 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004931}
4932
4933/**
4934 * xmlXPathSubValues:
4935 * @ctxt: the XPath Parser context
4936 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004937 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004938 * The numeric operators convert their operands to numbers as if
4939 * by calling the number function.
4940 */
4941void
4942xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4943 xmlXPathObjectPtr arg;
4944 double val;
4945
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004946 arg = valuePop(ctxt);
4947 if (arg == NULL)
4948 XP_ERROR(XPATH_INVALID_OPERAND);
4949 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004950 xmlXPathFreeObject(arg);
4951
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004952 CAST_TO_NUMBER;
4953 CHECK_TYPE(XPATH_NUMBER);
4954 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004955}
4956
4957/**
4958 * xmlXPathMultValues:
4959 * @ctxt: the XPath Parser context
4960 *
4961 * Implement the multiply operation on XPath objects:
4962 * The numeric operators convert their operands to numbers as if
4963 * by calling the number function.
4964 */
4965void
4966xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4967 xmlXPathObjectPtr arg;
4968 double val;
4969
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004970 arg = valuePop(ctxt);
4971 if (arg == NULL)
4972 XP_ERROR(XPATH_INVALID_OPERAND);
4973 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004974 xmlXPathFreeObject(arg);
4975
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004976 CAST_TO_NUMBER;
4977 CHECK_TYPE(XPATH_NUMBER);
4978 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004979}
4980
4981/**
4982 * xmlXPathDivValues:
4983 * @ctxt: the XPath Parser context
4984 *
4985 * Implement the div operation on XPath objects @arg1 / @arg2:
4986 * The numeric operators convert their operands to numbers as if
4987 * by calling the number function.
4988 */
4989void
4990xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4991 xmlXPathObjectPtr arg;
4992 double val;
4993
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004994 arg = valuePop(ctxt);
4995 if (arg == NULL)
4996 XP_ERROR(XPATH_INVALID_OPERAND);
4997 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004998 xmlXPathFreeObject(arg);
4999
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005000 CAST_TO_NUMBER;
5001 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005002 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5003 ctxt->value->floatval = xmlXPathNAN;
5004 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005005 if (ctxt->value->floatval == 0)
5006 ctxt->value->floatval = xmlXPathNAN;
5007 else if (ctxt->value->floatval > 0)
5008 ctxt->value->floatval = xmlXPathNINF;
5009 else if (ctxt->value->floatval < 0)
5010 ctxt->value->floatval = xmlXPathPINF;
5011 }
5012 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005013 if (ctxt->value->floatval == 0)
5014 ctxt->value->floatval = xmlXPathNAN;
5015 else if (ctxt->value->floatval > 0)
5016 ctxt->value->floatval = xmlXPathPINF;
5017 else if (ctxt->value->floatval < 0)
5018 ctxt->value->floatval = xmlXPathNINF;
5019 } else
5020 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005021}
5022
5023/**
5024 * xmlXPathModValues:
5025 * @ctxt: the XPath Parser context
5026 *
5027 * Implement the mod operation on XPath objects: @arg1 / @arg2
5028 * The numeric operators convert their operands to numbers as if
5029 * by calling the number function.
5030 */
5031void
5032xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5033 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005034 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005035
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005036 arg = valuePop(ctxt);
5037 if (arg == NULL)
5038 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005039 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005040 xmlXPathFreeObject(arg);
5041
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005042 CAST_TO_NUMBER;
5043 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005044 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005045 if (arg2 == 0)
5046 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005047 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005048 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005049 }
Owen Taylor3473f882001-02-23 17:55:21 +00005050}
5051
5052/************************************************************************
5053 * *
5054 * The traversal functions *
5055 * *
5056 ************************************************************************/
5057
Owen Taylor3473f882001-02-23 17:55:21 +00005058/*
5059 * A traversal function enumerates nodes along an axis.
5060 * Initially it must be called with NULL, and it indicates
5061 * termination on the axis by returning NULL.
5062 */
5063typedef xmlNodePtr (*xmlXPathTraversalFunction)
5064 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5065
5066/**
5067 * xmlXPathNextSelf:
5068 * @ctxt: the XPath Parser context
5069 * @cur: the current node in the traversal
5070 *
5071 * Traversal function for the "self" direction
5072 * The self axis contains just the context node itself
5073 *
5074 * Returns the next element following that axis
5075 */
5076xmlNodePtr
5077xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5078 if (cur == NULL)
5079 return(ctxt->context->node);
5080 return(NULL);
5081}
5082
5083/**
5084 * xmlXPathNextChild:
5085 * @ctxt: the XPath Parser context
5086 * @cur: the current node in the traversal
5087 *
5088 * Traversal function for the "child" direction
5089 * The child axis contains the children of the context node in document order.
5090 *
5091 * Returns the next element following that axis
5092 */
5093xmlNodePtr
5094xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5095 if (cur == NULL) {
5096 if (ctxt->context->node == NULL) return(NULL);
5097 switch (ctxt->context->node->type) {
5098 case XML_ELEMENT_NODE:
5099 case XML_TEXT_NODE:
5100 case XML_CDATA_SECTION_NODE:
5101 case XML_ENTITY_REF_NODE:
5102 case XML_ENTITY_NODE:
5103 case XML_PI_NODE:
5104 case XML_COMMENT_NODE:
5105 case XML_NOTATION_NODE:
5106 case XML_DTD_NODE:
5107 return(ctxt->context->node->children);
5108 case XML_DOCUMENT_NODE:
5109 case XML_DOCUMENT_TYPE_NODE:
5110 case XML_DOCUMENT_FRAG_NODE:
5111 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005112#ifdef LIBXML_DOCB_ENABLED
5113 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005114#endif
5115 return(((xmlDocPtr) ctxt->context->node)->children);
5116 case XML_ELEMENT_DECL:
5117 case XML_ATTRIBUTE_DECL:
5118 case XML_ENTITY_DECL:
5119 case XML_ATTRIBUTE_NODE:
5120 case XML_NAMESPACE_DECL:
5121 case XML_XINCLUDE_START:
5122 case XML_XINCLUDE_END:
5123 return(NULL);
5124 }
5125 return(NULL);
5126 }
5127 if ((cur->type == XML_DOCUMENT_NODE) ||
5128 (cur->type == XML_HTML_DOCUMENT_NODE))
5129 return(NULL);
5130 return(cur->next);
5131}
5132
5133/**
5134 * xmlXPathNextDescendant:
5135 * @ctxt: the XPath Parser context
5136 * @cur: the current node in the traversal
5137 *
5138 * Traversal function for the "descendant" direction
5139 * the descendant axis contains the descendants of the context node in document
5140 * order; a descendant is a child or a child of a child and so on.
5141 *
5142 * Returns the next element following that axis
5143 */
5144xmlNodePtr
5145xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5146 if (cur == NULL) {
5147 if (ctxt->context->node == NULL)
5148 return(NULL);
5149 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5150 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5151 return(NULL);
5152
5153 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5154 return(ctxt->context->doc->children);
5155 return(ctxt->context->node->children);
5156 }
5157
Daniel Veillard567e1b42001-08-01 15:53:47 +00005158 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005159 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00005160 return(cur->children);
5161 }
5162
5163 if (cur == ctxt->context->node) return(NULL);
5164
Owen Taylor3473f882001-02-23 17:55:21 +00005165 if (cur->next != NULL) return(cur->next);
5166
5167 do {
5168 cur = cur->parent;
5169 if (cur == NULL) return(NULL);
5170 if (cur == ctxt->context->node) return(NULL);
5171 if (cur->next != NULL) {
5172 cur = cur->next;
5173 return(cur);
5174 }
5175 } while (cur != NULL);
5176 return(cur);
5177}
5178
5179/**
5180 * xmlXPathNextDescendantOrSelf:
5181 * @ctxt: the XPath Parser context
5182 * @cur: the current node in the traversal
5183 *
5184 * Traversal function for the "descendant-or-self" direction
5185 * the descendant-or-self axis contains the context node and the descendants
5186 * of the context node in document order; thus the context node is the first
5187 * node on the axis, and the first child of the context node is the second node
5188 * on the axis
5189 *
5190 * Returns the next element following that axis
5191 */
5192xmlNodePtr
5193xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5194 if (cur == NULL) {
5195 if (ctxt->context->node == NULL)
5196 return(NULL);
5197 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5198 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5199 return(NULL);
5200 return(ctxt->context->node);
5201 }
5202
5203 return(xmlXPathNextDescendant(ctxt, cur));
5204}
5205
5206/**
5207 * xmlXPathNextParent:
5208 * @ctxt: the XPath Parser context
5209 * @cur: the current node in the traversal
5210 *
5211 * Traversal function for the "parent" direction
5212 * The parent axis contains the parent of the context node, if there is one.
5213 *
5214 * Returns the next element following that axis
5215 */
5216xmlNodePtr
5217xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5218 /*
5219 * the parent of an attribute or namespace node is the element
5220 * to which the attribute or namespace node is attached
5221 * Namespace handling !!!
5222 */
5223 if (cur == NULL) {
5224 if (ctxt->context->node == NULL) return(NULL);
5225 switch (ctxt->context->node->type) {
5226 case XML_ELEMENT_NODE:
5227 case XML_TEXT_NODE:
5228 case XML_CDATA_SECTION_NODE:
5229 case XML_ENTITY_REF_NODE:
5230 case XML_ENTITY_NODE:
5231 case XML_PI_NODE:
5232 case XML_COMMENT_NODE:
5233 case XML_NOTATION_NODE:
5234 case XML_DTD_NODE:
5235 case XML_ELEMENT_DECL:
5236 case XML_ATTRIBUTE_DECL:
5237 case XML_XINCLUDE_START:
5238 case XML_XINCLUDE_END:
5239 case XML_ENTITY_DECL:
5240 if (ctxt->context->node->parent == NULL)
5241 return((xmlNodePtr) ctxt->context->doc);
5242 return(ctxt->context->node->parent);
5243 case XML_ATTRIBUTE_NODE: {
5244 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5245
5246 return(att->parent);
5247 }
5248 case XML_DOCUMENT_NODE:
5249 case XML_DOCUMENT_TYPE_NODE:
5250 case XML_DOCUMENT_FRAG_NODE:
5251 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005252#ifdef LIBXML_DOCB_ENABLED
5253 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005254#endif
5255 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005256 case XML_NAMESPACE_DECL: {
5257 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5258
5259 if ((ns->next != NULL) &&
5260 (ns->next->type != XML_NAMESPACE_DECL))
5261 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005262 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005263 }
Owen Taylor3473f882001-02-23 17:55:21 +00005264 }
5265 }
5266 return(NULL);
5267}
5268
5269/**
5270 * xmlXPathNextAncestor:
5271 * @ctxt: the XPath Parser context
5272 * @cur: the current node in the traversal
5273 *
5274 * Traversal function for the "ancestor" direction
5275 * the ancestor axis contains the ancestors of the context node; the ancestors
5276 * of the context node consist of the parent of context node and the parent's
5277 * parent and so on; the nodes are ordered in reverse document order; thus the
5278 * parent is the first node on the axis, and the parent's parent is the second
5279 * node on the axis
5280 *
5281 * Returns the next element following that axis
5282 */
5283xmlNodePtr
5284xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5285 /*
5286 * the parent of an attribute or namespace node is the element
5287 * to which the attribute or namespace node is attached
5288 * !!!!!!!!!!!!!
5289 */
5290 if (cur == NULL) {
5291 if (ctxt->context->node == NULL) return(NULL);
5292 switch (ctxt->context->node->type) {
5293 case XML_ELEMENT_NODE:
5294 case XML_TEXT_NODE:
5295 case XML_CDATA_SECTION_NODE:
5296 case XML_ENTITY_REF_NODE:
5297 case XML_ENTITY_NODE:
5298 case XML_PI_NODE:
5299 case XML_COMMENT_NODE:
5300 case XML_DTD_NODE:
5301 case XML_ELEMENT_DECL:
5302 case XML_ATTRIBUTE_DECL:
5303 case XML_ENTITY_DECL:
5304 case XML_NOTATION_NODE:
5305 case XML_XINCLUDE_START:
5306 case XML_XINCLUDE_END:
5307 if (ctxt->context->node->parent == NULL)
5308 return((xmlNodePtr) ctxt->context->doc);
5309 return(ctxt->context->node->parent);
5310 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005311 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005312
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005313 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005314 }
5315 case XML_DOCUMENT_NODE:
5316 case XML_DOCUMENT_TYPE_NODE:
5317 case XML_DOCUMENT_FRAG_NODE:
5318 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005319#ifdef LIBXML_DOCB_ENABLED
5320 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005321#endif
5322 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005323 case XML_NAMESPACE_DECL: {
5324 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5325
5326 if ((ns->next != NULL) &&
5327 (ns->next->type != XML_NAMESPACE_DECL))
5328 return((xmlNodePtr) ns->next);
5329 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005330 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005331 }
Owen Taylor3473f882001-02-23 17:55:21 +00005332 }
5333 return(NULL);
5334 }
5335 if (cur == ctxt->context->doc->children)
5336 return((xmlNodePtr) ctxt->context->doc);
5337 if (cur == (xmlNodePtr) ctxt->context->doc)
5338 return(NULL);
5339 switch (cur->type) {
5340 case XML_ELEMENT_NODE:
5341 case XML_TEXT_NODE:
5342 case XML_CDATA_SECTION_NODE:
5343 case XML_ENTITY_REF_NODE:
5344 case XML_ENTITY_NODE:
5345 case XML_PI_NODE:
5346 case XML_COMMENT_NODE:
5347 case XML_NOTATION_NODE:
5348 case XML_DTD_NODE:
5349 case XML_ELEMENT_DECL:
5350 case XML_ATTRIBUTE_DECL:
5351 case XML_ENTITY_DECL:
5352 case XML_XINCLUDE_START:
5353 case XML_XINCLUDE_END:
5354 return(cur->parent);
5355 case XML_ATTRIBUTE_NODE: {
5356 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5357
5358 return(att->parent);
5359 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005360 case XML_NAMESPACE_DECL: {
5361 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5362
5363 if ((ns->next != NULL) &&
5364 (ns->next->type != XML_NAMESPACE_DECL))
5365 return((xmlNodePtr) ns->next);
5366 /* Bad, how did that namespace ended-up there ? */
5367 return(NULL);
5368 }
Owen Taylor3473f882001-02-23 17:55:21 +00005369 case XML_DOCUMENT_NODE:
5370 case XML_DOCUMENT_TYPE_NODE:
5371 case XML_DOCUMENT_FRAG_NODE:
5372 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005373#ifdef LIBXML_DOCB_ENABLED
5374 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005375#endif
5376 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005377 }
5378 return(NULL);
5379}
5380
5381/**
5382 * xmlXPathNextAncestorOrSelf:
5383 * @ctxt: the XPath Parser context
5384 * @cur: the current node in the traversal
5385 *
5386 * Traversal function for the "ancestor-or-self" direction
5387 * he ancestor-or-self axis contains the context node and ancestors of
5388 * the context node in reverse document order; thus the context node is
5389 * the first node on the axis, and the context node's parent the second;
5390 * parent here is defined the same as with the parent axis.
5391 *
5392 * Returns the next element following that axis
5393 */
5394xmlNodePtr
5395xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5396 if (cur == NULL)
5397 return(ctxt->context->node);
5398 return(xmlXPathNextAncestor(ctxt, cur));
5399}
5400
5401/**
5402 * xmlXPathNextFollowingSibling:
5403 * @ctxt: the XPath Parser context
5404 * @cur: the current node in the traversal
5405 *
5406 * Traversal function for the "following-sibling" direction
5407 * The following-sibling axis contains the following siblings of the context
5408 * node in document order.
5409 *
5410 * Returns the next element following that axis
5411 */
5412xmlNodePtr
5413xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5414 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5415 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5416 return(NULL);
5417 if (cur == (xmlNodePtr) ctxt->context->doc)
5418 return(NULL);
5419 if (cur == NULL)
5420 return(ctxt->context->node->next);
5421 return(cur->next);
5422}
5423
5424/**
5425 * xmlXPathNextPrecedingSibling:
5426 * @ctxt: the XPath Parser context
5427 * @cur: the current node in the traversal
5428 *
5429 * Traversal function for the "preceding-sibling" direction
5430 * The preceding-sibling axis contains the preceding siblings of the context
5431 * node in reverse document order; the first preceding sibling is first on the
5432 * axis; the sibling preceding that node is the second on the axis and so on.
5433 *
5434 * Returns the next element following that axis
5435 */
5436xmlNodePtr
5437xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5438 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5439 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5440 return(NULL);
5441 if (cur == (xmlNodePtr) ctxt->context->doc)
5442 return(NULL);
5443 if (cur == NULL)
5444 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005445 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5446 cur = cur->prev;
5447 if (cur == NULL)
5448 return(ctxt->context->node->prev);
5449 }
Owen Taylor3473f882001-02-23 17:55:21 +00005450 return(cur->prev);
5451}
5452
5453/**
5454 * xmlXPathNextFollowing:
5455 * @ctxt: the XPath Parser context
5456 * @cur: the current node in the traversal
5457 *
5458 * Traversal function for the "following" direction
5459 * The following axis contains all nodes in the same document as the context
5460 * node that are after the context node in document order, excluding any
5461 * descendants and excluding attribute nodes and namespace nodes; the nodes
5462 * are ordered in document order
5463 *
5464 * Returns the next element following that axis
5465 */
5466xmlNodePtr
5467xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5468 if (cur != NULL && cur->children != NULL)
5469 return cur->children ;
5470 if (cur == NULL) cur = ctxt->context->node;
5471 if (cur == NULL) return(NULL) ; /* ERROR */
5472 if (cur->next != NULL) return(cur->next) ;
5473 do {
5474 cur = cur->parent;
5475 if (cur == NULL) return(NULL);
5476 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5477 if (cur->next != NULL) return(cur->next);
5478 } while (cur != NULL);
5479 return(cur);
5480}
5481
5482/*
5483 * xmlXPathIsAncestor:
5484 * @ancestor: the ancestor node
5485 * @node: the current node
5486 *
5487 * Check that @ancestor is a @node's ancestor
5488 *
5489 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5490 */
5491static int
5492xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5493 if ((ancestor == NULL) || (node == NULL)) return(0);
5494 /* nodes need to be in the same document */
5495 if (ancestor->doc != node->doc) return(0);
5496 /* avoid searching if ancestor or node is the root node */
5497 if (ancestor == (xmlNodePtr) node->doc) return(1);
5498 if (node == (xmlNodePtr) ancestor->doc) return(0);
5499 while (node->parent != NULL) {
5500 if (node->parent == ancestor)
5501 return(1);
5502 node = node->parent;
5503 }
5504 return(0);
5505}
5506
5507/**
5508 * xmlXPathNextPreceding:
5509 * @ctxt: the XPath Parser context
5510 * @cur: the current node in the traversal
5511 *
5512 * Traversal function for the "preceding" direction
5513 * the preceding axis contains all nodes in the same document as the context
5514 * node that are before the context node in document order, excluding any
5515 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5516 * ordered in reverse document order
5517 *
5518 * Returns the next element following that axis
5519 */
5520xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005521xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5522{
Owen Taylor3473f882001-02-23 17:55:21 +00005523 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005524 cur = ctxt->context->node;
5525 if (cur == NULL)
5526 return (NULL);
5527 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5528 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005529 do {
5530 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005531 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5532 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005533 }
5534
5535 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005536 if (cur == NULL)
5537 return (NULL);
5538 if (cur == ctxt->context->doc->children)
5539 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005540 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005541 return (cur);
5542}
5543
5544/**
5545 * xmlXPathNextPrecedingInternal:
5546 * @ctxt: the XPath Parser context
5547 * @cur: the current node in the traversal
5548 *
5549 * Traversal function for the "preceding" direction
5550 * the preceding axis contains all nodes in the same document as the context
5551 * node that are before the context node in document order, excluding any
5552 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5553 * ordered in reverse document order
5554 * This is a faster implementation but internal only since it requires a
5555 * state kept in the parser context: ctxt->ancestor.
5556 *
5557 * Returns the next element following that axis
5558 */
5559static xmlNodePtr
5560xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5561 xmlNodePtr cur)
5562{
5563 if (cur == NULL) {
5564 cur = ctxt->context->node;
5565 if (cur == NULL)
5566 return (NULL);
5567 ctxt->ancestor = cur->parent;
5568 }
5569 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5570 cur = cur->prev;
5571 while (cur->prev == NULL) {
5572 cur = cur->parent;
5573 if (cur == NULL)
5574 return (NULL);
5575 if (cur == ctxt->context->doc->children)
5576 return (NULL);
5577 if (cur != ctxt->ancestor)
5578 return (cur);
5579 ctxt->ancestor = cur->parent;
5580 }
5581 cur = cur->prev;
5582 while (cur->last != NULL)
5583 cur = cur->last;
5584 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005585}
5586
5587/**
5588 * xmlXPathNextNamespace:
5589 * @ctxt: the XPath Parser context
5590 * @cur: the current attribute in the traversal
5591 *
5592 * Traversal function for the "namespace" direction
5593 * the namespace axis contains the namespace nodes of the context node;
5594 * the order of nodes on this axis is implementation-defined; the axis will
5595 * be empty unless the context node is an element
5596 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005597 * We keep the XML namespace node at the end of the list.
5598 *
Owen Taylor3473f882001-02-23 17:55:21 +00005599 * Returns the next element following that axis
5600 */
5601xmlNodePtr
5602xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5603 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005604 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005605 if (ctxt->context->tmpNsList != NULL)
5606 xmlFree(ctxt->context->tmpNsList);
5607 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005608 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005609 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005610 if (ctxt->context->tmpNsList != NULL) {
5611 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5612 ctxt->context->tmpNsNr++;
5613 }
5614 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005615 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005616 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005617 if (ctxt->context->tmpNsNr > 0) {
5618 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5619 } else {
5620 if (ctxt->context->tmpNsList != NULL)
5621 xmlFree(ctxt->context->tmpNsList);
5622 ctxt->context->tmpNsList = NULL;
5623 return(NULL);
5624 }
Owen Taylor3473f882001-02-23 17:55:21 +00005625}
5626
5627/**
5628 * xmlXPathNextAttribute:
5629 * @ctxt: the XPath Parser context
5630 * @cur: the current attribute in the traversal
5631 *
5632 * Traversal function for the "attribute" direction
5633 * TODO: support DTD inherited default attributes
5634 *
5635 * Returns the next element following that axis
5636 */
5637xmlNodePtr
5638xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005639 if (ctxt->context->node == NULL)
5640 return(NULL);
5641 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5642 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005643 if (cur == NULL) {
5644 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5645 return(NULL);
5646 return((xmlNodePtr)ctxt->context->node->properties);
5647 }
5648 return((xmlNodePtr)cur->next);
5649}
5650
5651/************************************************************************
5652 * *
5653 * NodeTest Functions *
5654 * *
5655 ************************************************************************/
5656
Owen Taylor3473f882001-02-23 17:55:21 +00005657#define IS_FUNCTION 200
5658
Owen Taylor3473f882001-02-23 17:55:21 +00005659
5660/************************************************************************
5661 * *
5662 * Implicit tree core function library *
5663 * *
5664 ************************************************************************/
5665
5666/**
5667 * xmlXPathRoot:
5668 * @ctxt: the XPath Parser context
5669 *
5670 * Initialize the context to the root of the document
5671 */
5672void
5673xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5674 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5675 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5676}
5677
5678/************************************************************************
5679 * *
5680 * The explicit core function library *
5681 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5682 * *
5683 ************************************************************************/
5684
5685
5686/**
5687 * xmlXPathLastFunction:
5688 * @ctxt: the XPath Parser context
5689 * @nargs: the number of arguments
5690 *
5691 * Implement the last() XPath function
5692 * number last()
5693 * The last function returns the number of nodes in the context node list.
5694 */
5695void
5696xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5697 CHECK_ARITY(0);
5698 if (ctxt->context->contextSize >= 0) {
5699 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5700#ifdef DEBUG_EXPR
5701 xmlGenericError(xmlGenericErrorContext,
5702 "last() : %d\n", ctxt->context->contextSize);
5703#endif
5704 } else {
5705 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5706 }
5707}
5708
5709/**
5710 * xmlXPathPositionFunction:
5711 * @ctxt: the XPath Parser context
5712 * @nargs: the number of arguments
5713 *
5714 * Implement the position() XPath function
5715 * number position()
5716 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005717 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005718 * will be equal to last().
5719 */
5720void
5721xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5722 CHECK_ARITY(0);
5723 if (ctxt->context->proximityPosition >= 0) {
5724 valuePush(ctxt,
5725 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5726#ifdef DEBUG_EXPR
5727 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5728 ctxt->context->proximityPosition);
5729#endif
5730 } else {
5731 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5732 }
5733}
5734
5735/**
5736 * xmlXPathCountFunction:
5737 * @ctxt: the XPath Parser context
5738 * @nargs: the number of arguments
5739 *
5740 * Implement the count() XPath function
5741 * number count(node-set)
5742 */
5743void
5744xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5745 xmlXPathObjectPtr cur;
5746
5747 CHECK_ARITY(1);
5748 if ((ctxt->value == NULL) ||
5749 ((ctxt->value->type != XPATH_NODESET) &&
5750 (ctxt->value->type != XPATH_XSLT_TREE)))
5751 XP_ERROR(XPATH_INVALID_TYPE);
5752 cur = valuePop(ctxt);
5753
Daniel Veillard911f49a2001-04-07 15:39:35 +00005754 if ((cur == NULL) || (cur->nodesetval == NULL))
5755 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005756 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005757 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005758 } else {
5759 if ((cur->nodesetval->nodeNr != 1) ||
5760 (cur->nodesetval->nodeTab == NULL)) {
5761 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5762 } else {
5763 xmlNodePtr tmp;
5764 int i = 0;
5765
5766 tmp = cur->nodesetval->nodeTab[0];
5767 if (tmp != NULL) {
5768 tmp = tmp->children;
5769 while (tmp != NULL) {
5770 tmp = tmp->next;
5771 i++;
5772 }
5773 }
5774 valuePush(ctxt, xmlXPathNewFloat((double) i));
5775 }
5776 }
Owen Taylor3473f882001-02-23 17:55:21 +00005777 xmlXPathFreeObject(cur);
5778}
5779
5780/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005781 * xmlXPathGetElementsByIds:
5782 * @doc: the document
5783 * @ids: a whitespace separated list of IDs
5784 *
5785 * Selects elements by their unique ID.
5786 *
5787 * Returns a node-set of selected elements.
5788 */
5789static xmlNodeSetPtr
5790xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5791 xmlNodeSetPtr ret;
5792 const xmlChar *cur = ids;
5793 xmlChar *ID;
5794 xmlAttrPtr attr;
5795 xmlNodePtr elem = NULL;
5796
5797 ret = xmlXPathNodeSetCreate(NULL);
5798
5799 while (IS_BLANK(*cur)) cur++;
5800 while (*cur != 0) {
5801 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5802 (*cur == '.') || (*cur == '-') ||
5803 (*cur == '_') || (*cur == ':') ||
5804 (IS_COMBINING(*cur)) ||
5805 (IS_EXTENDER(*cur)))
5806 cur++;
5807
5808 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5809
5810 ID = xmlStrndup(ids, cur - ids);
5811 attr = xmlGetID(doc, ID);
5812 if (attr != NULL) {
5813 elem = attr->parent;
5814 xmlXPathNodeSetAdd(ret, elem);
5815 }
5816 if (ID != NULL)
5817 xmlFree(ID);
5818
5819 while (IS_BLANK(*cur)) cur++;
5820 ids = cur;
5821 }
5822 return(ret);
5823}
5824
5825/**
Owen Taylor3473f882001-02-23 17:55:21 +00005826 * xmlXPathIdFunction:
5827 * @ctxt: the XPath Parser context
5828 * @nargs: the number of arguments
5829 *
5830 * Implement the id() XPath function
5831 * node-set id(object)
5832 * The id function selects elements by their unique ID
5833 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5834 * then the result is the union of the result of applying id to the
5835 * string value of each of the nodes in the argument node-set. When the
5836 * argument to id is of any other type, the argument is converted to a
5837 * string as if by a call to the string function; the string is split
5838 * into a whitespace-separated list of tokens (whitespace is any sequence
5839 * of characters matching the production S); the result is a node-set
5840 * containing the elements in the same document as the context node that
5841 * have a unique ID equal to any of the tokens in the list.
5842 */
5843void
5844xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005845 xmlChar *tokens;
5846 xmlNodeSetPtr ret;
5847 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005848
5849 CHECK_ARITY(1);
5850 obj = valuePop(ctxt);
5851 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005852 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005853 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005854 int i;
5855
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005856 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005857
Daniel Veillard911f49a2001-04-07 15:39:35 +00005858 if (obj->nodesetval != NULL) {
5859 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005860 tokens =
5861 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5862 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5863 ret = xmlXPathNodeSetMerge(ret, ns);
5864 xmlXPathFreeNodeSet(ns);
5865 if (tokens != NULL)
5866 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005867 }
Owen Taylor3473f882001-02-23 17:55:21 +00005868 }
5869
5870 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005871 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005872 return;
5873 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005874 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005875
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005876 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5877 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005878
Owen Taylor3473f882001-02-23 17:55:21 +00005879 xmlXPathFreeObject(obj);
5880 return;
5881}
5882
5883/**
5884 * xmlXPathLocalNameFunction:
5885 * @ctxt: the XPath Parser context
5886 * @nargs: the number of arguments
5887 *
5888 * Implement the local-name() XPath function
5889 * string local-name(node-set?)
5890 * The local-name function returns a string containing the local part
5891 * of the name of the node in the argument node-set that is first in
5892 * document order. If the node-set is empty or the first node has no
5893 * name, an empty string is returned. If the argument is omitted it
5894 * defaults to the context node.
5895 */
5896void
5897xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5898 xmlXPathObjectPtr cur;
5899
5900 if (nargs == 0) {
5901 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5902 nargs = 1;
5903 }
5904
5905 CHECK_ARITY(1);
5906 if ((ctxt->value == NULL) ||
5907 ((ctxt->value->type != XPATH_NODESET) &&
5908 (ctxt->value->type != XPATH_XSLT_TREE)))
5909 XP_ERROR(XPATH_INVALID_TYPE);
5910 cur = valuePop(ctxt);
5911
Daniel Veillard911f49a2001-04-07 15:39:35 +00005912 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005913 valuePush(ctxt, xmlXPathNewCString(""));
5914 } else {
5915 int i = 0; /* Should be first in document order !!!!! */
5916 switch (cur->nodesetval->nodeTab[i]->type) {
5917 case XML_ELEMENT_NODE:
5918 case XML_ATTRIBUTE_NODE:
5919 case XML_PI_NODE:
5920 valuePush(ctxt,
5921 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5922 break;
5923 case XML_NAMESPACE_DECL:
5924 valuePush(ctxt, xmlXPathNewString(
5925 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5926 break;
5927 default:
5928 valuePush(ctxt, xmlXPathNewCString(""));
5929 }
5930 }
5931 xmlXPathFreeObject(cur);
5932}
5933
5934/**
5935 * xmlXPathNamespaceURIFunction:
5936 * @ctxt: the XPath Parser context
5937 * @nargs: the number of arguments
5938 *
5939 * Implement the namespace-uri() XPath function
5940 * string namespace-uri(node-set?)
5941 * The namespace-uri function returns a string containing the
5942 * namespace URI of the expanded name of the node in the argument
5943 * node-set that is first in document order. If the node-set is empty,
5944 * the first node has no name, or the expanded name has no namespace
5945 * URI, an empty string is returned. If the argument is omitted it
5946 * defaults to the context node.
5947 */
5948void
5949xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5950 xmlXPathObjectPtr cur;
5951
5952 if (nargs == 0) {
5953 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5954 nargs = 1;
5955 }
5956 CHECK_ARITY(1);
5957 if ((ctxt->value == NULL) ||
5958 ((ctxt->value->type != XPATH_NODESET) &&
5959 (ctxt->value->type != XPATH_XSLT_TREE)))
5960 XP_ERROR(XPATH_INVALID_TYPE);
5961 cur = valuePop(ctxt);
5962
Daniel Veillard911f49a2001-04-07 15:39:35 +00005963 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005964 valuePush(ctxt, xmlXPathNewCString(""));
5965 } else {
5966 int i = 0; /* Should be first in document order !!!!! */
5967 switch (cur->nodesetval->nodeTab[i]->type) {
5968 case XML_ELEMENT_NODE:
5969 case XML_ATTRIBUTE_NODE:
5970 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5971 valuePush(ctxt, xmlXPathNewCString(""));
5972 else
5973 valuePush(ctxt, xmlXPathNewString(
5974 cur->nodesetval->nodeTab[i]->ns->href));
5975 break;
5976 default:
5977 valuePush(ctxt, xmlXPathNewCString(""));
5978 }
5979 }
5980 xmlXPathFreeObject(cur);
5981}
5982
5983/**
5984 * xmlXPathNameFunction:
5985 * @ctxt: the XPath Parser context
5986 * @nargs: the number of arguments
5987 *
5988 * Implement the name() XPath function
5989 * string name(node-set?)
5990 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005991 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005992 * order. The QName must represent the name with respect to the namespace
5993 * declarations in effect on the node whose name is being represented.
5994 * Typically, this will be the form in which the name occurred in the XML
5995 * source. This need not be the case if there are namespace declarations
5996 * in effect on the node that associate multiple prefixes with the same
5997 * namespace. However, an implementation may include information about
5998 * the original prefix in its representation of nodes; in this case, an
5999 * implementation can ensure that the returned string is always the same
6000 * as the QName used in the XML source. If the argument it omitted it
6001 * defaults to the context node.
6002 * Libxml keep the original prefix so the "real qualified name" used is
6003 * returned.
6004 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006005static void
Daniel Veillard04383752001-07-08 14:27:15 +00006006xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6007{
Owen Taylor3473f882001-02-23 17:55:21 +00006008 xmlXPathObjectPtr cur;
6009
6010 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006011 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6012 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006013 }
6014
6015 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006016 if ((ctxt->value == NULL) ||
6017 ((ctxt->value->type != XPATH_NODESET) &&
6018 (ctxt->value->type != XPATH_XSLT_TREE)))
6019 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006020 cur = valuePop(ctxt);
6021
Daniel Veillard911f49a2001-04-07 15:39:35 +00006022 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006023 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006024 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006025 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006026
Daniel Veillard04383752001-07-08 14:27:15 +00006027 switch (cur->nodesetval->nodeTab[i]->type) {
6028 case XML_ELEMENT_NODE:
6029 case XML_ATTRIBUTE_NODE:
6030 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6031 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
6032 valuePush(ctxt,
6033 xmlXPathNewString(cur->nodesetval->
6034 nodeTab[i]->name));
6035
6036 else {
6037 char name[2000];
6038
6039 snprintf(name, sizeof(name), "%s:%s",
6040 (char *) cur->nodesetval->nodeTab[i]->ns->
6041 prefix,
6042 (char *) cur->nodesetval->nodeTab[i]->name);
6043 name[sizeof(name) - 1] = 0;
6044 valuePush(ctxt, xmlXPathNewCString(name));
6045 }
6046 break;
6047 default:
6048 valuePush(ctxt,
6049 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6050 xmlXPathLocalNameFunction(ctxt, 1);
6051 }
Owen Taylor3473f882001-02-23 17:55:21 +00006052 }
6053 xmlXPathFreeObject(cur);
6054}
6055
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006056
6057/**
Owen Taylor3473f882001-02-23 17:55:21 +00006058 * xmlXPathStringFunction:
6059 * @ctxt: the XPath Parser context
6060 * @nargs: the number of arguments
6061 *
6062 * Implement the string() XPath function
6063 * string string(object?)
6064 * he string function converts an object to a string as follows:
6065 * - A node-set is converted to a string by returning the value of
6066 * the node in the node-set that is first in document order.
6067 * If the node-set is empty, an empty string is returned.
6068 * - A number is converted to a string as follows
6069 * + NaN is converted to the string NaN
6070 * + positive zero is converted to the string 0
6071 * + negative zero is converted to the string 0
6072 * + positive infinity is converted to the string Infinity
6073 * + negative infinity is converted to the string -Infinity
6074 * + if the number is an integer, the number is represented in
6075 * decimal form as a Number with no decimal point and no leading
6076 * zeros, preceded by a minus sign (-) if the number is negative
6077 * + otherwise, the number is represented in decimal form as a
6078 * Number including a decimal point with at least one digit
6079 * before the decimal point and at least one digit after the
6080 * decimal point, preceded by a minus sign (-) if the number
6081 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006082 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006083 * before the decimal point; beyond the one required digit
6084 * after the decimal point there must be as many, but only as
6085 * many, more digits as are needed to uniquely distinguish the
6086 * number from all other IEEE 754 numeric values.
6087 * - The boolean false value is converted to the string false.
6088 * The boolean true value is converted to the string true.
6089 *
6090 * If the argument is omitted, it defaults to a node-set with the
6091 * context node as its only member.
6092 */
6093void
6094xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6095 xmlXPathObjectPtr cur;
6096
6097 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006098 valuePush(ctxt,
6099 xmlXPathWrapString(
6100 xmlXPathCastNodeToString(ctxt->context->node)));
6101 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006102 }
6103
6104 CHECK_ARITY(1);
6105 cur = valuePop(ctxt);
6106 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006107 cur = xmlXPathConvertString(cur);
6108 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006109}
6110
6111/**
6112 * xmlXPathStringLengthFunction:
6113 * @ctxt: the XPath Parser context
6114 * @nargs: the number of arguments
6115 *
6116 * Implement the string-length() XPath function
6117 * number string-length(string?)
6118 * The string-length returns the number of characters in the string
6119 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6120 * the context node converted to a string, in other words the value
6121 * of the context node.
6122 */
6123void
6124xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6125 xmlXPathObjectPtr cur;
6126
6127 if (nargs == 0) {
6128 if (ctxt->context->node == NULL) {
6129 valuePush(ctxt, xmlXPathNewFloat(0));
6130 } else {
6131 xmlChar *content;
6132
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006133 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006134 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006135 xmlFree(content);
6136 }
6137 return;
6138 }
6139 CHECK_ARITY(1);
6140 CAST_TO_STRING;
6141 CHECK_TYPE(XPATH_STRING);
6142 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006143 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006144 xmlXPathFreeObject(cur);
6145}
6146
6147/**
6148 * xmlXPathConcatFunction:
6149 * @ctxt: the XPath Parser context
6150 * @nargs: the number of arguments
6151 *
6152 * Implement the concat() XPath function
6153 * string concat(string, string, string*)
6154 * The concat function returns the concatenation of its arguments.
6155 */
6156void
6157xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6158 xmlXPathObjectPtr cur, newobj;
6159 xmlChar *tmp;
6160
6161 if (nargs < 2) {
6162 CHECK_ARITY(2);
6163 }
6164
6165 CAST_TO_STRING;
6166 cur = valuePop(ctxt);
6167 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6168 xmlXPathFreeObject(cur);
6169 return;
6170 }
6171 nargs--;
6172
6173 while (nargs > 0) {
6174 CAST_TO_STRING;
6175 newobj = valuePop(ctxt);
6176 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6177 xmlXPathFreeObject(newobj);
6178 xmlXPathFreeObject(cur);
6179 XP_ERROR(XPATH_INVALID_TYPE);
6180 }
6181 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6182 newobj->stringval = cur->stringval;
6183 cur->stringval = tmp;
6184
6185 xmlXPathFreeObject(newobj);
6186 nargs--;
6187 }
6188 valuePush(ctxt, cur);
6189}
6190
6191/**
6192 * xmlXPathContainsFunction:
6193 * @ctxt: the XPath Parser context
6194 * @nargs: the number of arguments
6195 *
6196 * Implement the contains() XPath function
6197 * boolean contains(string, string)
6198 * The contains function returns true if the first argument string
6199 * contains the second argument string, and otherwise returns false.
6200 */
6201void
6202xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6203 xmlXPathObjectPtr hay, needle;
6204
6205 CHECK_ARITY(2);
6206 CAST_TO_STRING;
6207 CHECK_TYPE(XPATH_STRING);
6208 needle = valuePop(ctxt);
6209 CAST_TO_STRING;
6210 hay = valuePop(ctxt);
6211 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6212 xmlXPathFreeObject(hay);
6213 xmlXPathFreeObject(needle);
6214 XP_ERROR(XPATH_INVALID_TYPE);
6215 }
6216 if (xmlStrstr(hay->stringval, needle->stringval))
6217 valuePush(ctxt, xmlXPathNewBoolean(1));
6218 else
6219 valuePush(ctxt, xmlXPathNewBoolean(0));
6220 xmlXPathFreeObject(hay);
6221 xmlXPathFreeObject(needle);
6222}
6223
6224/**
6225 * xmlXPathStartsWithFunction:
6226 * @ctxt: the XPath Parser context
6227 * @nargs: the number of arguments
6228 *
6229 * Implement the starts-with() XPath function
6230 * boolean starts-with(string, string)
6231 * The starts-with function returns true if the first argument string
6232 * starts with the second argument string, and otherwise returns false.
6233 */
6234void
6235xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6236 xmlXPathObjectPtr hay, needle;
6237 int n;
6238
6239 CHECK_ARITY(2);
6240 CAST_TO_STRING;
6241 CHECK_TYPE(XPATH_STRING);
6242 needle = valuePop(ctxt);
6243 CAST_TO_STRING;
6244 hay = valuePop(ctxt);
6245 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6246 xmlXPathFreeObject(hay);
6247 xmlXPathFreeObject(needle);
6248 XP_ERROR(XPATH_INVALID_TYPE);
6249 }
6250 n = xmlStrlen(needle->stringval);
6251 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6252 valuePush(ctxt, xmlXPathNewBoolean(0));
6253 else
6254 valuePush(ctxt, xmlXPathNewBoolean(1));
6255 xmlXPathFreeObject(hay);
6256 xmlXPathFreeObject(needle);
6257}
6258
6259/**
6260 * xmlXPathSubstringFunction:
6261 * @ctxt: the XPath Parser context
6262 * @nargs: the number of arguments
6263 *
6264 * Implement the substring() XPath function
6265 * string substring(string, number, number?)
6266 * The substring function returns the substring of the first argument
6267 * starting at the position specified in the second argument with
6268 * length specified in the third argument. For example,
6269 * substring("12345",2,3) returns "234". If the third argument is not
6270 * specified, it returns the substring starting at the position specified
6271 * in the second argument and continuing to the end of the string. For
6272 * example, substring("12345",2) returns "2345". More precisely, each
6273 * character in the string (see [3.6 Strings]) is considered to have a
6274 * numeric position: the position of the first character is 1, the position
6275 * of the second character is 2 and so on. The returned substring contains
6276 * those characters for which the position of the character is greater than
6277 * or equal to the second argument and, if the third argument is specified,
6278 * less than the sum of the second and third arguments; the comparisons
6279 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6280 * - substring("12345", 1.5, 2.6) returns "234"
6281 * - substring("12345", 0, 3) returns "12"
6282 * - substring("12345", 0 div 0, 3) returns ""
6283 * - substring("12345", 1, 0 div 0) returns ""
6284 * - substring("12345", -42, 1 div 0) returns "12345"
6285 * - substring("12345", -1 div 0, 1 div 0) returns ""
6286 */
6287void
6288xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6289 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006290 double le=0, in;
6291 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006292 xmlChar *ret;
6293
Owen Taylor3473f882001-02-23 17:55:21 +00006294 if (nargs < 2) {
6295 CHECK_ARITY(2);
6296 }
6297 if (nargs > 3) {
6298 CHECK_ARITY(3);
6299 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006300 /*
6301 * take care of possible last (position) argument
6302 */
Owen Taylor3473f882001-02-23 17:55:21 +00006303 if (nargs == 3) {
6304 CAST_TO_NUMBER;
6305 CHECK_TYPE(XPATH_NUMBER);
6306 len = valuePop(ctxt);
6307 le = len->floatval;
6308 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006309 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006310
Owen Taylor3473f882001-02-23 17:55:21 +00006311 CAST_TO_NUMBER;
6312 CHECK_TYPE(XPATH_NUMBER);
6313 start = valuePop(ctxt);
6314 in = start->floatval;
6315 xmlXPathFreeObject(start);
6316 CAST_TO_STRING;
6317 CHECK_TYPE(XPATH_STRING);
6318 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006319 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006320
Daniel Veillard97ac1312001-05-30 19:14:17 +00006321 /*
6322 * If last pos not present, calculate last position
6323 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006324 if (nargs != 3) {
6325 le = (double)m;
6326 if (in < 1.0)
6327 in = 1.0;
6328 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006329
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006330 /* Need to check for the special cases where either
6331 * the index is NaN, the length is NaN, or both
6332 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006333 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006334 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006335 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006336 * To meet the requirements of the spec, the arguments
6337 * must be converted to integer format before
6338 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006339 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006340 * First we go to integer form, rounding up
6341 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006342 */
6343 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006344 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006345
Daniel Veillard9e412302002-06-10 15:59:44 +00006346 if (xmlXPathIsInf(le) == 1) {
6347 l = m;
6348 if (i < 1)
6349 i = 1;
6350 }
6351 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6352 l = 0;
6353 else {
6354 l = (int) le;
6355 if (((double)l)+0.5 <= le) l++;
6356 }
6357
6358 /* Now we normalize inidices */
6359 i -= 1;
6360 l += i;
6361 if (i < 0)
6362 i = 0;
6363 if (l > m)
6364 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006365
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006366 /* number of chars to copy */
6367 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006368
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006369 ret = xmlUTF8Strsub(str->stringval, i, l);
6370 }
6371 else {
6372 ret = NULL;
6373 }
6374
Owen Taylor3473f882001-02-23 17:55:21 +00006375 if (ret == NULL)
6376 valuePush(ctxt, xmlXPathNewCString(""));
6377 else {
6378 valuePush(ctxt, xmlXPathNewString(ret));
6379 xmlFree(ret);
6380 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006381
Owen Taylor3473f882001-02-23 17:55:21 +00006382 xmlXPathFreeObject(str);
6383}
6384
6385/**
6386 * xmlXPathSubstringBeforeFunction:
6387 * @ctxt: the XPath Parser context
6388 * @nargs: the number of arguments
6389 *
6390 * Implement the substring-before() XPath function
6391 * string substring-before(string, string)
6392 * The substring-before function returns the substring of the first
6393 * argument string that precedes the first occurrence of the second
6394 * argument string in the first argument string, or the empty string
6395 * if the first argument string does not contain the second argument
6396 * string. For example, substring-before("1999/04/01","/") returns 1999.
6397 */
6398void
6399xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6400 xmlXPathObjectPtr str;
6401 xmlXPathObjectPtr find;
6402 xmlBufferPtr target;
6403 const xmlChar *point;
6404 int offset;
6405
6406 CHECK_ARITY(2);
6407 CAST_TO_STRING;
6408 find = valuePop(ctxt);
6409 CAST_TO_STRING;
6410 str = valuePop(ctxt);
6411
6412 target = xmlBufferCreate();
6413 if (target) {
6414 point = xmlStrstr(str->stringval, find->stringval);
6415 if (point) {
6416 offset = (int)(point - str->stringval);
6417 xmlBufferAdd(target, str->stringval, offset);
6418 }
6419 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6420 xmlBufferFree(target);
6421 }
6422
6423 xmlXPathFreeObject(str);
6424 xmlXPathFreeObject(find);
6425}
6426
6427/**
6428 * xmlXPathSubstringAfterFunction:
6429 * @ctxt: the XPath Parser context
6430 * @nargs: the number of arguments
6431 *
6432 * Implement the substring-after() XPath function
6433 * string substring-after(string, string)
6434 * The substring-after function returns the substring of the first
6435 * argument string that follows the first occurrence of the second
6436 * argument string in the first argument string, or the empty stringi
6437 * if the first argument string does not contain the second argument
6438 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6439 * and substring-after("1999/04/01","19") returns 99/04/01.
6440 */
6441void
6442xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6443 xmlXPathObjectPtr str;
6444 xmlXPathObjectPtr find;
6445 xmlBufferPtr target;
6446 const xmlChar *point;
6447 int offset;
6448
6449 CHECK_ARITY(2);
6450 CAST_TO_STRING;
6451 find = valuePop(ctxt);
6452 CAST_TO_STRING;
6453 str = valuePop(ctxt);
6454
6455 target = xmlBufferCreate();
6456 if (target) {
6457 point = xmlStrstr(str->stringval, find->stringval);
6458 if (point) {
6459 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6460 xmlBufferAdd(target, &str->stringval[offset],
6461 xmlStrlen(str->stringval) - offset);
6462 }
6463 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6464 xmlBufferFree(target);
6465 }
6466
6467 xmlXPathFreeObject(str);
6468 xmlXPathFreeObject(find);
6469}
6470
6471/**
6472 * xmlXPathNormalizeFunction:
6473 * @ctxt: the XPath Parser context
6474 * @nargs: the number of arguments
6475 *
6476 * Implement the normalize-space() XPath function
6477 * string normalize-space(string?)
6478 * The normalize-space function returns the argument string with white
6479 * space normalized by stripping leading and trailing whitespace
6480 * and replacing sequences of whitespace characters by a single
6481 * space. Whitespace characters are the same allowed by the S production
6482 * in XML. If the argument is omitted, it defaults to the context
6483 * node converted to a string, in other words the value of the context node.
6484 */
6485void
6486xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6487 xmlXPathObjectPtr obj = NULL;
6488 xmlChar *source = NULL;
6489 xmlBufferPtr target;
6490 xmlChar blank;
6491
6492 if (nargs == 0) {
6493 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006494 valuePush(ctxt,
6495 xmlXPathWrapString(
6496 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006497 nargs = 1;
6498 }
6499
6500 CHECK_ARITY(1);
6501 CAST_TO_STRING;
6502 CHECK_TYPE(XPATH_STRING);
6503 obj = valuePop(ctxt);
6504 source = obj->stringval;
6505
6506 target = xmlBufferCreate();
6507 if (target && source) {
6508
6509 /* Skip leading whitespaces */
6510 while (IS_BLANK(*source))
6511 source++;
6512
6513 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6514 blank = 0;
6515 while (*source) {
6516 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006517 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006518 } else {
6519 if (blank) {
6520 xmlBufferAdd(target, &blank, 1);
6521 blank = 0;
6522 }
6523 xmlBufferAdd(target, source, 1);
6524 }
6525 source++;
6526 }
6527
6528 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6529 xmlBufferFree(target);
6530 }
6531 xmlXPathFreeObject(obj);
6532}
6533
6534/**
6535 * xmlXPathTranslateFunction:
6536 * @ctxt: the XPath Parser context
6537 * @nargs: the number of arguments
6538 *
6539 * Implement the translate() XPath function
6540 * string translate(string, string, string)
6541 * The translate function returns the first argument string with
6542 * occurrences of characters in the second argument string replaced
6543 * by the character at the corresponding position in the third argument
6544 * string. For example, translate("bar","abc","ABC") returns the string
6545 * BAr. If there is a character in the second argument string with no
6546 * character at a corresponding position in the third argument string
6547 * (because the second argument string is longer than the third argument
6548 * string), then occurrences of that character in the first argument
6549 * string are removed. For example, translate("--aaa--","abc-","ABC")
6550 * returns "AAA". If a character occurs more than once in second
6551 * argument string, then the first occurrence determines the replacement
6552 * character. If the third argument string is longer than the second
6553 * argument string, then excess characters are ignored.
6554 */
6555void
6556xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006557 xmlXPathObjectPtr str;
6558 xmlXPathObjectPtr from;
6559 xmlXPathObjectPtr to;
6560 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006561 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006562 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006563 xmlChar *point;
6564 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006565
Daniel Veillarde043ee12001-04-16 14:08:07 +00006566 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006567
Daniel Veillarde043ee12001-04-16 14:08:07 +00006568 CAST_TO_STRING;
6569 to = valuePop(ctxt);
6570 CAST_TO_STRING;
6571 from = valuePop(ctxt);
6572 CAST_TO_STRING;
6573 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006574
Daniel Veillarde043ee12001-04-16 14:08:07 +00006575 target = xmlBufferCreate();
6576 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006577 max = xmlUTF8Strlen(to->stringval);
6578 for (cptr = str->stringval; (ch=*cptr); ) {
6579 offset = xmlUTF8Strloc(from->stringval, cptr);
6580 if (offset >= 0) {
6581 if (offset < max) {
6582 point = xmlUTF8Strpos(to->stringval, offset);
6583 if (point)
6584 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6585 }
6586 } else
6587 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6588
6589 /* Step to next character in input */
6590 cptr++;
6591 if ( ch & 0x80 ) {
6592 /* if not simple ascii, verify proper format */
6593 if ( (ch & 0xc0) != 0xc0 ) {
6594 xmlGenericError(xmlGenericErrorContext,
6595 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6596 break;
6597 }
6598 /* then skip over remaining bytes for this char */
6599 while ( (ch <<= 1) & 0x80 )
6600 if ( (*cptr++ & 0xc0) != 0x80 ) {
6601 xmlGenericError(xmlGenericErrorContext,
6602 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6603 break;
6604 }
6605 if (ch & 0x80) /* must have had error encountered */
6606 break;
6607 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006608 }
Owen Taylor3473f882001-02-23 17:55:21 +00006609 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006610 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6611 xmlBufferFree(target);
6612 xmlXPathFreeObject(str);
6613 xmlXPathFreeObject(from);
6614 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006615}
6616
6617/**
6618 * xmlXPathBooleanFunction:
6619 * @ctxt: the XPath Parser context
6620 * @nargs: the number of arguments
6621 *
6622 * Implement the boolean() XPath function
6623 * boolean boolean(object)
6624 * he boolean function converts its argument to a boolean as follows:
6625 * - a number is true if and only if it is neither positive or
6626 * negative zero nor NaN
6627 * - a node-set is true if and only if it is non-empty
6628 * - a string is true if and only if its length is non-zero
6629 */
6630void
6631xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6632 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006633
6634 CHECK_ARITY(1);
6635 cur = valuePop(ctxt);
6636 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006637 cur = xmlXPathConvertBoolean(cur);
6638 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006639}
6640
6641/**
6642 * xmlXPathNotFunction:
6643 * @ctxt: the XPath Parser context
6644 * @nargs: the number of arguments
6645 *
6646 * Implement the not() XPath function
6647 * boolean not(boolean)
6648 * The not function returns true if its argument is false,
6649 * and false otherwise.
6650 */
6651void
6652xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6653 CHECK_ARITY(1);
6654 CAST_TO_BOOLEAN;
6655 CHECK_TYPE(XPATH_BOOLEAN);
6656 ctxt->value->boolval = ! ctxt->value->boolval;
6657}
6658
6659/**
6660 * xmlXPathTrueFunction:
6661 * @ctxt: the XPath Parser context
6662 * @nargs: the number of arguments
6663 *
6664 * Implement the true() XPath function
6665 * boolean true()
6666 */
6667void
6668xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6669 CHECK_ARITY(0);
6670 valuePush(ctxt, xmlXPathNewBoolean(1));
6671}
6672
6673/**
6674 * xmlXPathFalseFunction:
6675 * @ctxt: the XPath Parser context
6676 * @nargs: the number of arguments
6677 *
6678 * Implement the false() XPath function
6679 * boolean false()
6680 */
6681void
6682xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6683 CHECK_ARITY(0);
6684 valuePush(ctxt, xmlXPathNewBoolean(0));
6685}
6686
6687/**
6688 * xmlXPathLangFunction:
6689 * @ctxt: the XPath Parser context
6690 * @nargs: the number of arguments
6691 *
6692 * Implement the lang() XPath function
6693 * boolean lang(string)
6694 * The lang function returns true or false depending on whether the
6695 * language of the context node as specified by xml:lang attributes
6696 * is the same as or is a sublanguage of the language specified by
6697 * the argument string. The language of the context node is determined
6698 * by the value of the xml:lang attribute on the context node, or, if
6699 * the context node has no xml:lang attribute, by the value of the
6700 * xml:lang attribute on the nearest ancestor of the context node that
6701 * has an xml:lang attribute. If there is no such attribute, then lang
6702 * returns false. If there is such an attribute, then lang returns
6703 * true if the attribute value is equal to the argument ignoring case,
6704 * or if there is some suffix starting with - such that the attribute
6705 * value is equal to the argument ignoring that suffix of the attribute
6706 * value and ignoring case.
6707 */
6708void
6709xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6710 xmlXPathObjectPtr val;
6711 const xmlChar *theLang;
6712 const xmlChar *lang;
6713 int ret = 0;
6714 int i;
6715
6716 CHECK_ARITY(1);
6717 CAST_TO_STRING;
6718 CHECK_TYPE(XPATH_STRING);
6719 val = valuePop(ctxt);
6720 lang = val->stringval;
6721 theLang = xmlNodeGetLang(ctxt->context->node);
6722 if ((theLang != NULL) && (lang != NULL)) {
6723 for (i = 0;lang[i] != 0;i++)
6724 if (toupper(lang[i]) != toupper(theLang[i]))
6725 goto not_equal;
6726 ret = 1;
6727 }
6728not_equal:
6729 xmlXPathFreeObject(val);
6730 valuePush(ctxt, xmlXPathNewBoolean(ret));
6731}
6732
6733/**
6734 * xmlXPathNumberFunction:
6735 * @ctxt: the XPath Parser context
6736 * @nargs: the number of arguments
6737 *
6738 * Implement the number() XPath function
6739 * number number(object?)
6740 */
6741void
6742xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6743 xmlXPathObjectPtr cur;
6744 double res;
6745
6746 if (nargs == 0) {
6747 if (ctxt->context->node == NULL) {
6748 valuePush(ctxt, xmlXPathNewFloat(0.0));
6749 } else {
6750 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6751
6752 res = xmlXPathStringEvalNumber(content);
6753 valuePush(ctxt, xmlXPathNewFloat(res));
6754 xmlFree(content);
6755 }
6756 return;
6757 }
6758
6759 CHECK_ARITY(1);
6760 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006761 cur = xmlXPathConvertNumber(cur);
6762 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006763}
6764
6765/**
6766 * xmlXPathSumFunction:
6767 * @ctxt: the XPath Parser context
6768 * @nargs: the number of arguments
6769 *
6770 * Implement the sum() XPath function
6771 * number sum(node-set)
6772 * The sum function returns the sum of the values of the nodes in
6773 * the argument node-set.
6774 */
6775void
6776xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6777 xmlXPathObjectPtr cur;
6778 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006779 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006780
6781 CHECK_ARITY(1);
6782 if ((ctxt->value == NULL) ||
6783 ((ctxt->value->type != XPATH_NODESET) &&
6784 (ctxt->value->type != XPATH_XSLT_TREE)))
6785 XP_ERROR(XPATH_INVALID_TYPE);
6786 cur = valuePop(ctxt);
6787
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006788 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006789 valuePush(ctxt, xmlXPathNewFloat(0.0));
6790 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006791 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6792 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006793 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006794 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006795 }
6796 xmlXPathFreeObject(cur);
6797}
6798
6799/**
6800 * xmlXPathFloorFunction:
6801 * @ctxt: the XPath Parser context
6802 * @nargs: the number of arguments
6803 *
6804 * Implement the floor() XPath function
6805 * number floor(number)
6806 * The floor function returns the largest (closest to positive infinity)
6807 * number that is not greater than the argument and that is an integer.
6808 */
6809void
6810xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006811 double f;
6812
Owen Taylor3473f882001-02-23 17:55:21 +00006813 CHECK_ARITY(1);
6814 CAST_TO_NUMBER;
6815 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006816
6817 f = (double)((int) ctxt->value->floatval);
6818 if (f != ctxt->value->floatval) {
6819 if (ctxt->value->floatval > 0)
6820 ctxt->value->floatval = f;
6821 else
6822 ctxt->value->floatval = f - 1;
6823 }
Owen Taylor3473f882001-02-23 17:55:21 +00006824}
6825
6826/**
6827 * xmlXPathCeilingFunction:
6828 * @ctxt: the XPath Parser context
6829 * @nargs: the number of arguments
6830 *
6831 * Implement the ceiling() XPath function
6832 * number ceiling(number)
6833 * The ceiling function returns the smallest (closest to negative infinity)
6834 * number that is not less than the argument and that is an integer.
6835 */
6836void
6837xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6838 double f;
6839
6840 CHECK_ARITY(1);
6841 CAST_TO_NUMBER;
6842 CHECK_TYPE(XPATH_NUMBER);
6843
6844#if 0
6845 ctxt->value->floatval = ceil(ctxt->value->floatval);
6846#else
6847 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006848 if (f != ctxt->value->floatval) {
6849 if (ctxt->value->floatval > 0)
6850 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006851 else {
6852 if (ctxt->value->floatval < 0 && f == 0)
6853 ctxt->value->floatval = xmlXPathNZERO;
6854 else
6855 ctxt->value->floatval = f;
6856 }
6857
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006858 }
Owen Taylor3473f882001-02-23 17:55:21 +00006859#endif
6860}
6861
6862/**
6863 * xmlXPathRoundFunction:
6864 * @ctxt: the XPath Parser context
6865 * @nargs: the number of arguments
6866 *
6867 * Implement the round() XPath function
6868 * number round(number)
6869 * The round function returns the number that is closest to the
6870 * argument and that is an integer. If there are two such numbers,
6871 * then the one that is even is returned.
6872 */
6873void
6874xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6875 double f;
6876
6877 CHECK_ARITY(1);
6878 CAST_TO_NUMBER;
6879 CHECK_TYPE(XPATH_NUMBER);
6880
Daniel Veillardcda96922001-08-21 10:56:31 +00006881 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6882 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6883 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006884 (ctxt->value->floatval == 0.0))
6885 return;
6886
Owen Taylor3473f882001-02-23 17:55:21 +00006887 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006888 if (ctxt->value->floatval < 0) {
6889 if (ctxt->value->floatval < f - 0.5)
6890 ctxt->value->floatval = f - 1;
6891 else
6892 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006893 if (ctxt->value->floatval == 0)
6894 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006895 } else {
6896 if (ctxt->value->floatval < f + 0.5)
6897 ctxt->value->floatval = f;
6898 else
6899 ctxt->value->floatval = f + 1;
6900 }
Owen Taylor3473f882001-02-23 17:55:21 +00006901}
6902
6903/************************************************************************
6904 * *
6905 * The Parser *
6906 * *
6907 ************************************************************************/
6908
6909/*
6910 * a couple of forward declarations since we use a recursive call based
6911 * implementation.
6912 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006913static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006914static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006915static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006916#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006917static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6918#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006919#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006920static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006921#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006922static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6923 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006924
6925/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006926 * xmlXPathCurrentChar:
6927 * @ctxt: the XPath parser context
6928 * @cur: pointer to the beginning of the char
6929 * @len: pointer to the length of the char read
6930 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006931 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006932 * bytes in the input buffer.
6933 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006934 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006935 */
6936
6937static int
6938xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6939 unsigned char c;
6940 unsigned int val;
6941 const xmlChar *cur;
6942
6943 if (ctxt == NULL)
6944 return(0);
6945 cur = ctxt->cur;
6946
6947 /*
6948 * We are supposed to handle UTF8, check it's valid
6949 * From rfc2044: encoding of the Unicode values on UTF-8:
6950 *
6951 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6952 * 0000 0000-0000 007F 0xxxxxxx
6953 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6954 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6955 *
6956 * Check for the 0x110000 limit too
6957 */
6958 c = *cur;
6959 if (c & 0x80) {
6960 if ((cur[1] & 0xc0) != 0x80)
6961 goto encoding_error;
6962 if ((c & 0xe0) == 0xe0) {
6963
6964 if ((cur[2] & 0xc0) != 0x80)
6965 goto encoding_error;
6966 if ((c & 0xf0) == 0xf0) {
6967 if (((c & 0xf8) != 0xf0) ||
6968 ((cur[3] & 0xc0) != 0x80))
6969 goto encoding_error;
6970 /* 4-byte code */
6971 *len = 4;
6972 val = (cur[0] & 0x7) << 18;
6973 val |= (cur[1] & 0x3f) << 12;
6974 val |= (cur[2] & 0x3f) << 6;
6975 val |= cur[3] & 0x3f;
6976 } else {
6977 /* 3-byte code */
6978 *len = 3;
6979 val = (cur[0] & 0xf) << 12;
6980 val |= (cur[1] & 0x3f) << 6;
6981 val |= cur[2] & 0x3f;
6982 }
6983 } else {
6984 /* 2-byte code */
6985 *len = 2;
6986 val = (cur[0] & 0x1f) << 6;
6987 val |= cur[1] & 0x3f;
6988 }
6989 if (!IS_CHAR(val)) {
6990 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6991 }
6992 return(val);
6993 } else {
6994 /* 1-byte code */
6995 *len = 1;
6996 return((int) *cur);
6997 }
6998encoding_error:
6999 /*
7000 * If we detect an UTF8 error that probably mean that the
7001 * input encoding didn't get properly advertized in the
7002 * declaration header. Report the error and switch the encoding
7003 * to ISO-Latin-1 (if you don't like this policy, just declare the
7004 * encoding !)
7005 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007006 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007007 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007008}
7009
7010/**
Owen Taylor3473f882001-02-23 17:55:21 +00007011 * xmlXPathParseNCName:
7012 * @ctxt: the XPath Parser context
7013 *
7014 * parse an XML namespace non qualified name.
7015 *
7016 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7017 *
7018 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7019 * CombiningChar | Extender
7020 *
7021 * Returns the namespace name or NULL
7022 */
7023
7024xmlChar *
7025xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007026 const xmlChar *in;
7027 xmlChar *ret;
7028 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007029
Daniel Veillard2156a562001-04-28 12:24:34 +00007030 /*
7031 * Accelerator for simple ASCII names
7032 */
7033 in = ctxt->cur;
7034 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7035 ((*in >= 0x41) && (*in <= 0x5A)) ||
7036 (*in == '_')) {
7037 in++;
7038 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7039 ((*in >= 0x41) && (*in <= 0x5A)) ||
7040 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007041 (*in == '_') || (*in == '.') ||
7042 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007043 in++;
7044 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7045 (*in == '[') || (*in == ']') || (*in == ':') ||
7046 (*in == '@') || (*in == '*')) {
7047 count = in - ctxt->cur;
7048 if (count == 0)
7049 return(NULL);
7050 ret = xmlStrndup(ctxt->cur, count);
7051 ctxt->cur = in;
7052 return(ret);
7053 }
7054 }
7055 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007056}
7057
Daniel Veillard2156a562001-04-28 12:24:34 +00007058
Owen Taylor3473f882001-02-23 17:55:21 +00007059/**
7060 * xmlXPathParseQName:
7061 * @ctxt: the XPath Parser context
7062 * @prefix: a xmlChar **
7063 *
7064 * parse an XML qualified name
7065 *
7066 * [NS 5] QName ::= (Prefix ':')? LocalPart
7067 *
7068 * [NS 6] Prefix ::= NCName
7069 *
7070 * [NS 7] LocalPart ::= NCName
7071 *
7072 * Returns the function returns the local part, and prefix is updated
7073 * to get the Prefix if any.
7074 */
7075
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007076static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007077xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7078 xmlChar *ret = NULL;
7079
7080 *prefix = NULL;
7081 ret = xmlXPathParseNCName(ctxt);
7082 if (CUR == ':') {
7083 *prefix = ret;
7084 NEXT;
7085 ret = xmlXPathParseNCName(ctxt);
7086 }
7087 return(ret);
7088}
7089
7090/**
7091 * xmlXPathParseName:
7092 * @ctxt: the XPath Parser context
7093 *
7094 * parse an XML name
7095 *
7096 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7097 * CombiningChar | Extender
7098 *
7099 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7100 *
7101 * Returns the namespace name or NULL
7102 */
7103
7104xmlChar *
7105xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007106 const xmlChar *in;
7107 xmlChar *ret;
7108 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007109
Daniel Veillard61d80a22001-04-27 17:13:01 +00007110 /*
7111 * Accelerator for simple ASCII names
7112 */
7113 in = ctxt->cur;
7114 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7115 ((*in >= 0x41) && (*in <= 0x5A)) ||
7116 (*in == '_') || (*in == ':')) {
7117 in++;
7118 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7119 ((*in >= 0x41) && (*in <= 0x5A)) ||
7120 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007121 (*in == '_') || (*in == '-') ||
7122 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007123 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007124 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007125 count = in - ctxt->cur;
7126 ret = xmlStrndup(ctxt->cur, count);
7127 ctxt->cur = in;
7128 return(ret);
7129 }
7130 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007131 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007132}
7133
Daniel Veillard61d80a22001-04-27 17:13:01 +00007134static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007135xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007136 xmlChar buf[XML_MAX_NAMELEN + 5];
7137 int len = 0, l;
7138 int c;
7139
7140 /*
7141 * Handler for more complex cases
7142 */
7143 c = CUR_CHAR(l);
7144 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007145 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7146 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007147 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007148 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007149 return(NULL);
7150 }
7151
7152 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7153 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7154 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007155 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007156 (IS_COMBINING(c)) ||
7157 (IS_EXTENDER(c)))) {
7158 COPY_BUF(l,buf,len,c);
7159 NEXTL(l);
7160 c = CUR_CHAR(l);
7161 if (len >= XML_MAX_NAMELEN) {
7162 /*
7163 * Okay someone managed to make a huge name, so he's ready to pay
7164 * for the processing speed.
7165 */
7166 xmlChar *buffer;
7167 int max = len * 2;
7168
7169 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7170 if (buffer == NULL) {
7171 XP_ERROR0(XPATH_MEMORY_ERROR);
7172 }
7173 memcpy(buffer, buf, len);
7174 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7175 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007176 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007177 (IS_COMBINING(c)) ||
7178 (IS_EXTENDER(c))) {
7179 if (len + 10 > max) {
7180 max *= 2;
7181 buffer = (xmlChar *) xmlRealloc(buffer,
7182 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007183 if (buffer == NULL) {
7184 XP_ERROR0(XPATH_MEMORY_ERROR);
7185 }
7186 }
7187 COPY_BUF(l,buffer,len,c);
7188 NEXTL(l);
7189 c = CUR_CHAR(l);
7190 }
7191 buffer[len] = 0;
7192 return(buffer);
7193 }
7194 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007195 if (len == 0)
7196 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007197 return(xmlStrndup(buf, len));
7198}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007199
7200#define MAX_FRAC 20
7201
7202static double my_pow10[MAX_FRAC] = {
7203 1.0, 10.0, 100.0, 1000.0, 10000.0,
7204 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7205 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7206 100000000000000.0,
7207 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7208 1000000000000000000.0, 10000000000000000000.0
7209};
7210
Owen Taylor3473f882001-02-23 17:55:21 +00007211/**
7212 * xmlXPathStringEvalNumber:
7213 * @str: A string to scan
7214 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007215 * [30a] Float ::= Number ('e' Digits?)?
7216 *
Owen Taylor3473f882001-02-23 17:55:21 +00007217 * [30] Number ::= Digits ('.' Digits?)?
7218 * | '.' Digits
7219 * [31] Digits ::= [0-9]+
7220 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007221 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007222 * In complement of the Number expression, this function also handles
7223 * negative values : '-' Number.
7224 *
7225 * Returns the double value.
7226 */
7227double
7228xmlXPathStringEvalNumber(const xmlChar *str) {
7229 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007230 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007231 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007232 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007233 int exponent = 0;
7234 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007235#ifdef __GNUC__
7236 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007237 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007238#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007239 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007240 while (IS_BLANK(*cur)) cur++;
7241 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7242 return(xmlXPathNAN);
7243 }
7244 if (*cur == '-') {
7245 isneg = 1;
7246 cur++;
7247 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007248
7249#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007250 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007251 * tmp/temp is a workaround against a gcc compiler bug
7252 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007253 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007254 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007255 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007256 ret = ret * 10;
7257 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007258 ok = 1;
7259 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007260 temp = (double) tmp;
7261 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007262 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007263#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007264 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007265 while ((*cur >= '0') && (*cur <= '9')) {
7266 ret = ret * 10 + (*cur - '0');
7267 ok = 1;
7268 cur++;
7269 }
7270#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007271
Owen Taylor3473f882001-02-23 17:55:21 +00007272 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007273 int v, frac = 0;
7274 double fraction = 0;
7275
Owen Taylor3473f882001-02-23 17:55:21 +00007276 cur++;
7277 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7278 return(xmlXPathNAN);
7279 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007280 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7281 v = (*cur - '0');
7282 fraction = fraction * 10 + v;
7283 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007284 cur++;
7285 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007286 fraction /= my_pow10[frac];
7287 ret = ret + fraction;
7288 while ((*cur >= '0') && (*cur <= '9'))
7289 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007290 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007291 if ((*cur == 'e') || (*cur == 'E')) {
7292 cur++;
7293 if (*cur == '-') {
7294 is_exponent_negative = 1;
7295 cur++;
7296 }
7297 while ((*cur >= '0') && (*cur <= '9')) {
7298 exponent = exponent * 10 + (*cur - '0');
7299 cur++;
7300 }
7301 }
Owen Taylor3473f882001-02-23 17:55:21 +00007302 while (IS_BLANK(*cur)) cur++;
7303 if (*cur != 0) return(xmlXPathNAN);
7304 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007305 if (is_exponent_negative) exponent = -exponent;
7306 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007307 return(ret);
7308}
7309
7310/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007311 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007312 * @ctxt: the XPath Parser context
7313 *
7314 * [30] Number ::= Digits ('.' Digits?)?
7315 * | '.' Digits
7316 * [31] Digits ::= [0-9]+
7317 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007318 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007319 *
7320 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007321static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007322xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7323{
Owen Taylor3473f882001-02-23 17:55:21 +00007324 double ret = 0.0;
7325 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007326 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007327 int exponent = 0;
7328 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007329#ifdef __GNUC__
7330 unsigned long tmp = 0;
7331 double temp;
7332#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007333
7334 CHECK_ERROR;
7335 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7336 XP_ERROR(XPATH_NUMBER_ERROR);
7337 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007338#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007339 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007340 * tmp/temp is a workaround against a gcc compiler bug
7341 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007342 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007343 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007344 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007345 ret = ret * 10;
7346 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007347 ok = 1;
7348 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007349 temp = (double) tmp;
7350 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007351 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007352#else
7353 ret = 0;
7354 while ((CUR >= '0') && (CUR <= '9')) {
7355 ret = ret * 10 + (CUR - '0');
7356 ok = 1;
7357 NEXT;
7358 }
7359#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007360 if (CUR == '.') {
7361 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007362 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7363 XP_ERROR(XPATH_NUMBER_ERROR);
7364 }
7365 while ((CUR >= '0') && (CUR <= '9')) {
7366 mult /= 10;
7367 ret = ret + (CUR - '0') * mult;
7368 NEXT;
7369 }
Owen Taylor3473f882001-02-23 17:55:21 +00007370 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007371 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007372 NEXT;
7373 if (CUR == '-') {
7374 is_exponent_negative = 1;
7375 NEXT;
7376 }
7377 while ((CUR >= '0') && (CUR <= '9')) {
7378 exponent = exponent * 10 + (CUR - '0');
7379 NEXT;
7380 }
7381 if (is_exponent_negative)
7382 exponent = -exponent;
7383 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007384 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007385 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007386 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007387}
7388
7389/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007390 * xmlXPathParseLiteral:
7391 * @ctxt: the XPath Parser context
7392 *
7393 * Parse a Literal
7394 *
7395 * [29] Literal ::= '"' [^"]* '"'
7396 * | "'" [^']* "'"
7397 *
7398 * Returns the value found or NULL in case of error
7399 */
7400static xmlChar *
7401xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7402 const xmlChar *q;
7403 xmlChar *ret = NULL;
7404
7405 if (CUR == '"') {
7406 NEXT;
7407 q = CUR_PTR;
7408 while ((IS_CHAR(CUR)) && (CUR != '"'))
7409 NEXT;
7410 if (!IS_CHAR(CUR)) {
7411 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7412 } else {
7413 ret = xmlStrndup(q, CUR_PTR - q);
7414 NEXT;
7415 }
7416 } else if (CUR == '\'') {
7417 NEXT;
7418 q = CUR_PTR;
7419 while ((IS_CHAR(CUR)) && (CUR != '\''))
7420 NEXT;
7421 if (!IS_CHAR(CUR)) {
7422 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7423 } else {
7424 ret = xmlStrndup(q, CUR_PTR - q);
7425 NEXT;
7426 }
7427 } else {
7428 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7429 }
7430 return(ret);
7431}
7432
7433/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007434 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007435 * @ctxt: the XPath Parser context
7436 *
7437 * Parse a Literal and push it on the stack.
7438 *
7439 * [29] Literal ::= '"' [^"]* '"'
7440 * | "'" [^']* "'"
7441 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007442 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007443 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007444static void
7445xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007446 const xmlChar *q;
7447 xmlChar *ret = NULL;
7448
7449 if (CUR == '"') {
7450 NEXT;
7451 q = CUR_PTR;
7452 while ((IS_CHAR(CUR)) && (CUR != '"'))
7453 NEXT;
7454 if (!IS_CHAR(CUR)) {
7455 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7456 } else {
7457 ret = xmlStrndup(q, CUR_PTR - q);
7458 NEXT;
7459 }
7460 } else if (CUR == '\'') {
7461 NEXT;
7462 q = CUR_PTR;
7463 while ((IS_CHAR(CUR)) && (CUR != '\''))
7464 NEXT;
7465 if (!IS_CHAR(CUR)) {
7466 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7467 } else {
7468 ret = xmlStrndup(q, CUR_PTR - q);
7469 NEXT;
7470 }
7471 } else {
7472 XP_ERROR(XPATH_START_LITERAL_ERROR);
7473 }
7474 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007475 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7476 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007477 xmlFree(ret);
7478}
7479
7480/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007481 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007482 * @ctxt: the XPath Parser context
7483 *
7484 * Parse a VariableReference, evaluate it and push it on the stack.
7485 *
7486 * The variable bindings consist of a mapping from variable names
7487 * to variable values. The value of a variable is an object, which
7488 * of any of the types that are possible for the value of an expression,
7489 * and may also be of additional types not specified here.
7490 *
7491 * Early evaluation is possible since:
7492 * The variable bindings [...] used to evaluate a subexpression are
7493 * always the same as those used to evaluate the containing expression.
7494 *
7495 * [36] VariableReference ::= '$' QName
7496 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007497static void
7498xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007499 xmlChar *name;
7500 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007501
7502 SKIP_BLANKS;
7503 if (CUR != '$') {
7504 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7505 }
7506 NEXT;
7507 name = xmlXPathParseQName(ctxt, &prefix);
7508 if (name == NULL) {
7509 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7510 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007511 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007512 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7513 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007514 SKIP_BLANKS;
7515}
7516
7517/**
7518 * xmlXPathIsNodeType:
7519 * @ctxt: the XPath Parser context
7520 * @name: a name string
7521 *
7522 * Is the name given a NodeType one.
7523 *
7524 * [38] NodeType ::= 'comment'
7525 * | 'text'
7526 * | 'processing-instruction'
7527 * | 'node'
7528 *
7529 * Returns 1 if true 0 otherwise
7530 */
7531int
7532xmlXPathIsNodeType(const xmlChar *name) {
7533 if (name == NULL)
7534 return(0);
7535
Daniel Veillard1971ee22002-01-31 20:29:19 +00007536 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007537 return(1);
7538 if (xmlStrEqual(name, BAD_CAST "text"))
7539 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007540 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007541 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007542 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007543 return(1);
7544 return(0);
7545}
7546
7547/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007548 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007549 * @ctxt: the XPath Parser context
7550 *
7551 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7552 * [17] Argument ::= Expr
7553 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007554 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007555 * pushed on the stack
7556 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007557static void
7558xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007559 xmlChar *name;
7560 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007561 int nbargs = 0;
7562
7563 name = xmlXPathParseQName(ctxt, &prefix);
7564 if (name == NULL) {
7565 XP_ERROR(XPATH_EXPR_ERROR);
7566 }
7567 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007568#ifdef DEBUG_EXPR
7569 if (prefix == NULL)
7570 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7571 name);
7572 else
7573 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7574 prefix, name);
7575#endif
7576
Owen Taylor3473f882001-02-23 17:55:21 +00007577 if (CUR != '(') {
7578 XP_ERROR(XPATH_EXPR_ERROR);
7579 }
7580 NEXT;
7581 SKIP_BLANKS;
7582
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007583 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007584 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007585 int op1 = ctxt->comp->last;
7586 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007587 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007588 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007589 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007590 nbargs++;
7591 if (CUR == ')') break;
7592 if (CUR != ',') {
7593 XP_ERROR(XPATH_EXPR_ERROR);
7594 }
7595 NEXT;
7596 SKIP_BLANKS;
7597 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007598 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7599 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007600 NEXT;
7601 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007602}
7603
7604/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007605 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007606 * @ctxt: the XPath Parser context
7607 *
7608 * [15] PrimaryExpr ::= VariableReference
7609 * | '(' Expr ')'
7610 * | Literal
7611 * | Number
7612 * | FunctionCall
7613 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007614 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007615 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007616static void
7617xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007618 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007619 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007620 else if (CUR == '(') {
7621 NEXT;
7622 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007623 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007624 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007625 if (CUR != ')') {
7626 XP_ERROR(XPATH_EXPR_ERROR);
7627 }
7628 NEXT;
7629 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007630 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007631 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007632 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007633 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007634 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007635 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007636 }
7637 SKIP_BLANKS;
7638}
7639
7640/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007641 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007642 * @ctxt: the XPath Parser context
7643 *
7644 * [20] FilterExpr ::= PrimaryExpr
7645 * | FilterExpr Predicate
7646 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007647 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007648 * Square brackets are used to filter expressions in the same way that
7649 * they are used in location paths. It is an error if the expression to
7650 * be filtered does not evaluate to a node-set. The context node list
7651 * used for evaluating the expression in square brackets is the node-set
7652 * to be filtered listed in document order.
7653 */
7654
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007655static void
7656xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7657 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007658 CHECK_ERROR;
7659 SKIP_BLANKS;
7660
7661 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007662 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007663 SKIP_BLANKS;
7664 }
7665
7666
7667}
7668
7669/**
7670 * xmlXPathScanName:
7671 * @ctxt: the XPath Parser context
7672 *
7673 * Trickery: parse an XML name but without consuming the input flow
7674 * Needed to avoid insanity in the parser state.
7675 *
7676 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7677 * CombiningChar | Extender
7678 *
7679 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7680 *
7681 * [6] Names ::= Name (S Name)*
7682 *
7683 * Returns the Name parsed or NULL
7684 */
7685
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007686static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007687xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7688 xmlChar buf[XML_MAX_NAMELEN];
7689 int len = 0;
7690
7691 SKIP_BLANKS;
7692 if (!IS_LETTER(CUR) && (CUR != '_') &&
7693 (CUR != ':')) {
7694 return(NULL);
7695 }
7696
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 buf[len] = NXT(len);
7703 len++;
7704 if (len >= XML_MAX_NAMELEN) {
7705 xmlGenericError(xmlGenericErrorContext,
7706 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7707 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7708 (NXT(len) == '.') || (NXT(len) == '-') ||
7709 (NXT(len) == '_') || (NXT(len) == ':') ||
7710 (IS_COMBINING(NXT(len))) ||
7711 (IS_EXTENDER(NXT(len))))
7712 len++;
7713 break;
7714 }
7715 }
7716 return(xmlStrndup(buf, len));
7717}
7718
7719/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007720 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007721 * @ctxt: the XPath Parser context
7722 *
7723 * [19] PathExpr ::= LocationPath
7724 * | FilterExpr
7725 * | FilterExpr '/' RelativeLocationPath
7726 * | FilterExpr '//' RelativeLocationPath
7727 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007728 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007729 * The / operator and // operators combine an arbitrary expression
7730 * and a relative location path. It is an error if the expression
7731 * does not evaluate to a node-set.
7732 * The / operator does composition in the same way as when / is
7733 * used in a location path. As in location paths, // is short for
7734 * /descendant-or-self::node()/.
7735 */
7736
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007737static void
7738xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007739 int lc = 1; /* Should we branch to LocationPath ? */
7740 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7741
7742 SKIP_BLANKS;
7743 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007744 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007745 lc = 0;
7746 } else if (CUR == '*') {
7747 /* relative or absolute location path */
7748 lc = 1;
7749 } else if (CUR == '/') {
7750 /* relative or absolute location path */
7751 lc = 1;
7752 } else if (CUR == '@') {
7753 /* relative abbreviated attribute location path */
7754 lc = 1;
7755 } else if (CUR == '.') {
7756 /* relative abbreviated attribute location path */
7757 lc = 1;
7758 } else {
7759 /*
7760 * Problem is finding if we have a name here whether it's:
7761 * - a nodetype
7762 * - a function call in which case it's followed by '('
7763 * - an axis in which case it's followed by ':'
7764 * - a element name
7765 * We do an a priori analysis here rather than having to
7766 * maintain parsed token content through the recursive function
7767 * calls. This looks uglier but makes the code quite easier to
7768 * read/write/debug.
7769 */
7770 SKIP_BLANKS;
7771 name = xmlXPathScanName(ctxt);
7772 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7773#ifdef DEBUG_STEP
7774 xmlGenericError(xmlGenericErrorContext,
7775 "PathExpr: Axis\n");
7776#endif
7777 lc = 1;
7778 xmlFree(name);
7779 } else if (name != NULL) {
7780 int len =xmlStrlen(name);
7781 int blank = 0;
7782
7783
7784 while (NXT(len) != 0) {
7785 if (NXT(len) == '/') {
7786 /* element name */
7787#ifdef DEBUG_STEP
7788 xmlGenericError(xmlGenericErrorContext,
7789 "PathExpr: AbbrRelLocation\n");
7790#endif
7791 lc = 1;
7792 break;
7793 } else if (IS_BLANK(NXT(len))) {
7794 /* skip to next */
7795 blank = 1;
7796 } else if (NXT(len) == ':') {
7797#ifdef DEBUG_STEP
7798 xmlGenericError(xmlGenericErrorContext,
7799 "PathExpr: AbbrRelLocation\n");
7800#endif
7801 lc = 1;
7802 break;
7803 } else if ((NXT(len) == '(')) {
7804 /* Note Type or Function */
7805 if (xmlXPathIsNodeType(name)) {
7806#ifdef DEBUG_STEP
7807 xmlGenericError(xmlGenericErrorContext,
7808 "PathExpr: Type search\n");
7809#endif
7810 lc = 1;
7811 } else {
7812#ifdef DEBUG_STEP
7813 xmlGenericError(xmlGenericErrorContext,
7814 "PathExpr: function call\n");
7815#endif
7816 lc = 0;
7817 }
7818 break;
7819 } else if ((NXT(len) == '[')) {
7820 /* element name */
7821#ifdef DEBUG_STEP
7822 xmlGenericError(xmlGenericErrorContext,
7823 "PathExpr: AbbrRelLocation\n");
7824#endif
7825 lc = 1;
7826 break;
7827 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7828 (NXT(len) == '=')) {
7829 lc = 1;
7830 break;
7831 } else {
7832 lc = 1;
7833 break;
7834 }
7835 len++;
7836 }
7837 if (NXT(len) == 0) {
7838#ifdef DEBUG_STEP
7839 xmlGenericError(xmlGenericErrorContext,
7840 "PathExpr: AbbrRelLocation\n");
7841#endif
7842 /* element name */
7843 lc = 1;
7844 }
7845 xmlFree(name);
7846 } else {
7847 /* make sure all cases are covered explicitely */
7848 XP_ERROR(XPATH_EXPR_ERROR);
7849 }
7850 }
7851
7852 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007853 if (CUR == '/') {
7854 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7855 } else {
7856 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007857 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007858 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007859 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007860 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007861 CHECK_ERROR;
7862 if ((CUR == '/') && (NXT(1) == '/')) {
7863 SKIP(2);
7864 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007865
7866 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7867 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7868 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7869
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007870 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007871 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007872 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007873 }
7874 }
7875 SKIP_BLANKS;
7876}
7877
7878/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007879 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007880 * @ctxt: the XPath Parser context
7881 *
7882 * [18] UnionExpr ::= PathExpr
7883 * | UnionExpr '|' PathExpr
7884 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007885 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007886 */
7887
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007888static void
7889xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7890 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007891 CHECK_ERROR;
7892 SKIP_BLANKS;
7893 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007894 int op1 = ctxt->comp->last;
7895 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007896
7897 NEXT;
7898 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007899 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007900
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007901 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7902
Owen Taylor3473f882001-02-23 17:55:21 +00007903 SKIP_BLANKS;
7904 }
Owen Taylor3473f882001-02-23 17:55:21 +00007905}
7906
7907/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007908 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007909 * @ctxt: the XPath Parser context
7910 *
7911 * [27] UnaryExpr ::= UnionExpr
7912 * | '-' UnaryExpr
7913 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007914 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007915 */
7916
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007917static void
7918xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007919 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007920 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007921
7922 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007923 while (CUR == '-') {
7924 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007925 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007926 NEXT;
7927 SKIP_BLANKS;
7928 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007929
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007930 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007931 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007932 if (found) {
7933 if (minus)
7934 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7935 else
7936 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007937 }
7938}
7939
7940/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007941 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007942 * @ctxt: the XPath Parser context
7943 *
7944 * [26] MultiplicativeExpr ::= UnaryExpr
7945 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7946 * | MultiplicativeExpr 'div' UnaryExpr
7947 * | MultiplicativeExpr 'mod' UnaryExpr
7948 * [34] MultiplyOperator ::= '*'
7949 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007950 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007951 */
7952
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007953static void
7954xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7955 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007956 CHECK_ERROR;
7957 SKIP_BLANKS;
7958 while ((CUR == '*') ||
7959 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7960 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7961 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007962 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007963
7964 if (CUR == '*') {
7965 op = 0;
7966 NEXT;
7967 } else if (CUR == 'd') {
7968 op = 1;
7969 SKIP(3);
7970 } else if (CUR == 'm') {
7971 op = 2;
7972 SKIP(3);
7973 }
7974 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007975 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007976 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007977 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007978 SKIP_BLANKS;
7979 }
7980}
7981
7982/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007983 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007984 * @ctxt: the XPath Parser context
7985 *
7986 * [25] AdditiveExpr ::= MultiplicativeExpr
7987 * | AdditiveExpr '+' MultiplicativeExpr
7988 * | AdditiveExpr '-' MultiplicativeExpr
7989 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007990 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007991 */
7992
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007993static void
7994xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007995
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007996 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007997 CHECK_ERROR;
7998 SKIP_BLANKS;
7999 while ((CUR == '+') || (CUR == '-')) {
8000 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008001 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008002
8003 if (CUR == '+') plus = 1;
8004 else plus = 0;
8005 NEXT;
8006 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008007 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008008 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008009 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008010 SKIP_BLANKS;
8011 }
8012}
8013
8014/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008015 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008016 * @ctxt: the XPath Parser context
8017 *
8018 * [24] RelationalExpr ::= AdditiveExpr
8019 * | RelationalExpr '<' AdditiveExpr
8020 * | RelationalExpr '>' AdditiveExpr
8021 * | RelationalExpr '<=' AdditiveExpr
8022 * | RelationalExpr '>=' AdditiveExpr
8023 *
8024 * A <= B > C is allowed ? Answer from James, yes with
8025 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8026 * which is basically what got implemented.
8027 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008028 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008029 * on the stack
8030 */
8031
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008032static void
8033xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8034 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008035 CHECK_ERROR;
8036 SKIP_BLANKS;
8037 while ((CUR == '<') ||
8038 (CUR == '>') ||
8039 ((CUR == '<') && (NXT(1) == '=')) ||
8040 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008041 int inf, strict;
8042 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008043
8044 if (CUR == '<') inf = 1;
8045 else inf = 0;
8046 if (NXT(1) == '=') strict = 0;
8047 else strict = 1;
8048 NEXT;
8049 if (!strict) NEXT;
8050 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008051 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008052 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008053 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008054 SKIP_BLANKS;
8055 }
8056}
8057
8058/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008059 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008060 * @ctxt: the XPath Parser context
8061 *
8062 * [23] EqualityExpr ::= RelationalExpr
8063 * | EqualityExpr '=' RelationalExpr
8064 * | EqualityExpr '!=' RelationalExpr
8065 *
8066 * A != B != C is allowed ? Answer from James, yes with
8067 * (RelationalExpr = RelationalExpr) = RelationalExpr
8068 * (RelationalExpr != RelationalExpr) != RelationalExpr
8069 * which is basically what got implemented.
8070 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008071 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008072 *
8073 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008074static void
8075xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8076 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008077 CHECK_ERROR;
8078 SKIP_BLANKS;
8079 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008080 int eq;
8081 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008082
8083 if (CUR == '=') eq = 1;
8084 else eq = 0;
8085 NEXT;
8086 if (!eq) NEXT;
8087 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008088 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008089 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008090 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008091 SKIP_BLANKS;
8092 }
8093}
8094
8095/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008096 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008097 * @ctxt: the XPath Parser context
8098 *
8099 * [22] AndExpr ::= EqualityExpr
8100 * | AndExpr 'and' EqualityExpr
8101 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008102 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008103 *
8104 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008105static void
8106xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8107 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008108 CHECK_ERROR;
8109 SKIP_BLANKS;
8110 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008111 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008112 SKIP(3);
8113 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008114 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008115 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008116 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008117 SKIP_BLANKS;
8118 }
8119}
8120
8121/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008122 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008123 * @ctxt: the XPath Parser context
8124 *
8125 * [14] Expr ::= OrExpr
8126 * [21] OrExpr ::= AndExpr
8127 * | OrExpr 'or' AndExpr
8128 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008129 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008130 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008131static void
8132xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8133 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008134 CHECK_ERROR;
8135 SKIP_BLANKS;
8136 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008137 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008138 SKIP(2);
8139 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008140 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008141 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008142 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8143 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008144 SKIP_BLANKS;
8145 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008146 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8147 /* more ops could be optimized too */
8148 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8149 }
Owen Taylor3473f882001-02-23 17:55:21 +00008150}
8151
8152/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008153 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008154 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008155 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008156 *
8157 * [8] Predicate ::= '[' PredicateExpr ']'
8158 * [9] PredicateExpr ::= Expr
8159 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008160 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008161 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008162static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008163xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008164 int op1 = ctxt->comp->last;
8165
8166 SKIP_BLANKS;
8167 if (CUR != '[') {
8168 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8169 }
8170 NEXT;
8171 SKIP_BLANKS;
8172
8173 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008174 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008175 CHECK_ERROR;
8176
8177 if (CUR != ']') {
8178 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8179 }
8180
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008181 if (filter)
8182 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8183 else
8184 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008185
8186 NEXT;
8187 SKIP_BLANKS;
8188}
8189
8190/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008191 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008192 * @ctxt: the XPath Parser context
8193 * @test: pointer to a xmlXPathTestVal
8194 * @type: pointer to a xmlXPathTypeVal
8195 * @prefix: placeholder for a possible name prefix
8196 *
8197 * [7] NodeTest ::= NameTest
8198 * | NodeType '(' ')'
8199 * | 'processing-instruction' '(' Literal ')'
8200 *
8201 * [37] NameTest ::= '*'
8202 * | NCName ':' '*'
8203 * | QName
8204 * [38] NodeType ::= 'comment'
8205 * | 'text'
8206 * | 'processing-instruction'
8207 * | 'node'
8208 *
8209 * Returns the name found and update @test, @type and @prefix appropriately
8210 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008211static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008212xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8213 xmlXPathTypeVal *type, const xmlChar **prefix,
8214 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008215 int blanks;
8216
8217 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8218 STRANGE;
8219 return(NULL);
8220 }
8221 *type = 0;
8222 *test = 0;
8223 *prefix = NULL;
8224 SKIP_BLANKS;
8225
8226 if ((name == NULL) && (CUR == '*')) {
8227 /*
8228 * All elements
8229 */
8230 NEXT;
8231 *test = NODE_TEST_ALL;
8232 return(NULL);
8233 }
8234
8235 if (name == NULL)
8236 name = xmlXPathParseNCName(ctxt);
8237 if (name == NULL) {
8238 XP_ERROR0(XPATH_EXPR_ERROR);
8239 }
8240
8241 blanks = IS_BLANK(CUR);
8242 SKIP_BLANKS;
8243 if (CUR == '(') {
8244 NEXT;
8245 /*
8246 * NodeType or PI search
8247 */
8248 if (xmlStrEqual(name, BAD_CAST "comment"))
8249 *type = NODE_TYPE_COMMENT;
8250 else if (xmlStrEqual(name, BAD_CAST "node"))
8251 *type = NODE_TYPE_NODE;
8252 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8253 *type = NODE_TYPE_PI;
8254 else if (xmlStrEqual(name, BAD_CAST "text"))
8255 *type = NODE_TYPE_TEXT;
8256 else {
8257 if (name != NULL)
8258 xmlFree(name);
8259 XP_ERROR0(XPATH_EXPR_ERROR);
8260 }
8261
8262 *test = NODE_TEST_TYPE;
8263
8264 SKIP_BLANKS;
8265 if (*type == NODE_TYPE_PI) {
8266 /*
8267 * Specific case: search a PI by name.
8268 */
Owen Taylor3473f882001-02-23 17:55:21 +00008269 if (name != NULL)
8270 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008271 name = NULL;
8272 if (CUR != ')') {
8273 name = xmlXPathParseLiteral(ctxt);
8274 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008275 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008276 SKIP_BLANKS;
8277 }
Owen Taylor3473f882001-02-23 17:55:21 +00008278 }
8279 if (CUR != ')') {
8280 if (name != NULL)
8281 xmlFree(name);
8282 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8283 }
8284 NEXT;
8285 return(name);
8286 }
8287 *test = NODE_TEST_NAME;
8288 if ((!blanks) && (CUR == ':')) {
8289 NEXT;
8290
8291 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008292 * Since currently the parser context don't have a
8293 * namespace list associated:
8294 * The namespace name for this prefix can be computed
8295 * only at evaluation time. The compilation is done
8296 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008297 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008298#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008299 *prefix = xmlXPathNsLookup(ctxt->context, name);
8300 if (name != NULL)
8301 xmlFree(name);
8302 if (*prefix == NULL) {
8303 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8304 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008305#else
8306 *prefix = name;
8307#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008308
8309 if (CUR == '*') {
8310 /*
8311 * All elements
8312 */
8313 NEXT;
8314 *test = NODE_TEST_ALL;
8315 return(NULL);
8316 }
8317
8318 name = xmlXPathParseNCName(ctxt);
8319 if (name == NULL) {
8320 XP_ERROR0(XPATH_EXPR_ERROR);
8321 }
8322 }
8323 return(name);
8324}
8325
8326/**
8327 * xmlXPathIsAxisName:
8328 * @name: a preparsed name token
8329 *
8330 * [6] AxisName ::= 'ancestor'
8331 * | 'ancestor-or-self'
8332 * | 'attribute'
8333 * | 'child'
8334 * | 'descendant'
8335 * | 'descendant-or-self'
8336 * | 'following'
8337 * | 'following-sibling'
8338 * | 'namespace'
8339 * | 'parent'
8340 * | 'preceding'
8341 * | 'preceding-sibling'
8342 * | 'self'
8343 *
8344 * Returns the axis or 0
8345 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008346static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008347xmlXPathIsAxisName(const xmlChar *name) {
8348 xmlXPathAxisVal ret = 0;
8349 switch (name[0]) {
8350 case 'a':
8351 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8352 ret = AXIS_ANCESTOR;
8353 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8354 ret = AXIS_ANCESTOR_OR_SELF;
8355 if (xmlStrEqual(name, BAD_CAST "attribute"))
8356 ret = AXIS_ATTRIBUTE;
8357 break;
8358 case 'c':
8359 if (xmlStrEqual(name, BAD_CAST "child"))
8360 ret = AXIS_CHILD;
8361 break;
8362 case 'd':
8363 if (xmlStrEqual(name, BAD_CAST "descendant"))
8364 ret = AXIS_DESCENDANT;
8365 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8366 ret = AXIS_DESCENDANT_OR_SELF;
8367 break;
8368 case 'f':
8369 if (xmlStrEqual(name, BAD_CAST "following"))
8370 ret = AXIS_FOLLOWING;
8371 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8372 ret = AXIS_FOLLOWING_SIBLING;
8373 break;
8374 case 'n':
8375 if (xmlStrEqual(name, BAD_CAST "namespace"))
8376 ret = AXIS_NAMESPACE;
8377 break;
8378 case 'p':
8379 if (xmlStrEqual(name, BAD_CAST "parent"))
8380 ret = AXIS_PARENT;
8381 if (xmlStrEqual(name, BAD_CAST "preceding"))
8382 ret = AXIS_PRECEDING;
8383 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8384 ret = AXIS_PRECEDING_SIBLING;
8385 break;
8386 case 's':
8387 if (xmlStrEqual(name, BAD_CAST "self"))
8388 ret = AXIS_SELF;
8389 break;
8390 }
8391 return(ret);
8392}
8393
8394/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008395 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008396 * @ctxt: the XPath Parser context
8397 *
8398 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8399 * | AbbreviatedStep
8400 *
8401 * [12] AbbreviatedStep ::= '.' | '..'
8402 *
8403 * [5] AxisSpecifier ::= AxisName '::'
8404 * | AbbreviatedAxisSpecifier
8405 *
8406 * [13] AbbreviatedAxisSpecifier ::= '@'?
8407 *
8408 * Modified for XPtr range support as:
8409 *
8410 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8411 * | AbbreviatedStep
8412 * | 'range-to' '(' Expr ')' Predicate*
8413 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008414 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008415 * A location step of . is short for self::node(). This is
8416 * particularly useful in conjunction with //. For example, the
8417 * location path .//para is short for
8418 * self::node()/descendant-or-self::node()/child::para
8419 * and so will select all para descendant elements of the context
8420 * node.
8421 * Similarly, a location step of .. is short for parent::node().
8422 * For example, ../title is short for parent::node()/child::title
8423 * and so will select the title children of the parent of the context
8424 * node.
8425 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008426static void
8427xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008428#ifdef LIBXML_XPTR_ENABLED
8429 int rangeto = 0;
8430 int op2 = -1;
8431#endif
8432
Owen Taylor3473f882001-02-23 17:55:21 +00008433 SKIP_BLANKS;
8434 if ((CUR == '.') && (NXT(1) == '.')) {
8435 SKIP(2);
8436 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008437 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8438 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008439 } else if (CUR == '.') {
8440 NEXT;
8441 SKIP_BLANKS;
8442 } else {
8443 xmlChar *name = NULL;
8444 const xmlChar *prefix = NULL;
8445 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008446 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008447 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008448 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008449
8450 /*
8451 * The modification needed for XPointer change to the production
8452 */
8453#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008454 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008455 name = xmlXPathParseNCName(ctxt);
8456 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008457 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008458 xmlFree(name);
8459 SKIP_BLANKS;
8460 if (CUR != '(') {
8461 XP_ERROR(XPATH_EXPR_ERROR);
8462 }
8463 NEXT;
8464 SKIP_BLANKS;
8465
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008466 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008467 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008468 CHECK_ERROR;
8469
8470 SKIP_BLANKS;
8471 if (CUR != ')') {
8472 XP_ERROR(XPATH_EXPR_ERROR);
8473 }
8474 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008475 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008476 goto eval_predicates;
8477 }
8478 }
8479#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008480 if (CUR == '*') {
8481 axis = AXIS_CHILD;
8482 } else {
8483 if (name == NULL)
8484 name = xmlXPathParseNCName(ctxt);
8485 if (name != NULL) {
8486 axis = xmlXPathIsAxisName(name);
8487 if (axis != 0) {
8488 SKIP_BLANKS;
8489 if ((CUR == ':') && (NXT(1) == ':')) {
8490 SKIP(2);
8491 xmlFree(name);
8492 name = NULL;
8493 } else {
8494 /* an element name can conflict with an axis one :-\ */
8495 axis = AXIS_CHILD;
8496 }
Owen Taylor3473f882001-02-23 17:55:21 +00008497 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008498 axis = AXIS_CHILD;
8499 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008500 } else if (CUR == '@') {
8501 NEXT;
8502 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008503 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008504 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008505 }
Owen Taylor3473f882001-02-23 17:55:21 +00008506 }
8507
8508 CHECK_ERROR;
8509
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008510 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008511 if (test == 0)
8512 return;
8513
8514#ifdef DEBUG_STEP
8515 xmlGenericError(xmlGenericErrorContext,
8516 "Basis : computing new set\n");
8517#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008518
Owen Taylor3473f882001-02-23 17:55:21 +00008519#ifdef DEBUG_STEP
8520 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008521 if (ctxt->value == NULL)
8522 xmlGenericError(xmlGenericErrorContext, "no value\n");
8523 else if (ctxt->value->nodesetval == NULL)
8524 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8525 else
8526 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008527#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008528
8529eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008530 op1 = ctxt->comp->last;
8531 ctxt->comp->last = -1;
8532
Owen Taylor3473f882001-02-23 17:55:21 +00008533 SKIP_BLANKS;
8534 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008535 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008536 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008537
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008538#ifdef LIBXML_XPTR_ENABLED
8539 if (rangeto) {
8540 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8541 } else
8542#endif
8543 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8544 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008545
Owen Taylor3473f882001-02-23 17:55:21 +00008546 }
8547#ifdef DEBUG_STEP
8548 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008549 if (ctxt->value == NULL)
8550 xmlGenericError(xmlGenericErrorContext, "no value\n");
8551 else if (ctxt->value->nodesetval == NULL)
8552 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8553 else
8554 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8555 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008556#endif
8557}
8558
8559/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008560 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008561 * @ctxt: the XPath Parser context
8562 *
8563 * [3] RelativeLocationPath ::= Step
8564 * | RelativeLocationPath '/' Step
8565 * | AbbreviatedRelativeLocationPath
8566 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8567 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008568 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008569 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008570static void
Owen Taylor3473f882001-02-23 17:55:21 +00008571#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008572xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008573#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008574xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008575#endif
8576(xmlXPathParserContextPtr ctxt) {
8577 SKIP_BLANKS;
8578 if ((CUR == '/') && (NXT(1) == '/')) {
8579 SKIP(2);
8580 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008581 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8582 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008583 } else if (CUR == '/') {
8584 NEXT;
8585 SKIP_BLANKS;
8586 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008587 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008588 SKIP_BLANKS;
8589 while (CUR == '/') {
8590 if ((CUR == '/') && (NXT(1) == '/')) {
8591 SKIP(2);
8592 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008593 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008594 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008595 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008596 } else if (CUR == '/') {
8597 NEXT;
8598 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008599 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008600 }
8601 SKIP_BLANKS;
8602 }
8603}
8604
8605/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008606 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008607 * @ctxt: the XPath Parser context
8608 *
8609 * [1] LocationPath ::= RelativeLocationPath
8610 * | AbsoluteLocationPath
8611 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8612 * | AbbreviatedAbsoluteLocationPath
8613 * [10] AbbreviatedAbsoluteLocationPath ::=
8614 * '//' RelativeLocationPath
8615 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008616 * Compile a location path
8617 *
Owen Taylor3473f882001-02-23 17:55:21 +00008618 * // is short for /descendant-or-self::node()/. For example,
8619 * //para is short for /descendant-or-self::node()/child::para and
8620 * so will select any para element in the document (even a para element
8621 * that is a document element will be selected by //para since the
8622 * document element node is a child of the root node); div//para is
8623 * short for div/descendant-or-self::node()/child::para and so will
8624 * select all para descendants of div children.
8625 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008626static void
8627xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008628 SKIP_BLANKS;
8629 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008630 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008631 } else {
8632 while (CUR == '/') {
8633 if ((CUR == '/') && (NXT(1) == '/')) {
8634 SKIP(2);
8635 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008636 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8637 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008638 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008639 } else if (CUR == '/') {
8640 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008641 SKIP_BLANKS;
8642 if ((CUR != 0 ) &&
8643 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8644 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008645 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008646 }
8647 }
8648 }
8649}
8650
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008651/************************************************************************
8652 * *
8653 * XPath precompiled expression evaluation *
8654 * *
8655 ************************************************************************/
8656
Daniel Veillardf06307e2001-07-03 10:35:50 +00008657static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008658xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8659
8660/**
8661 * xmlXPathNodeCollectAndTest:
8662 * @ctxt: the XPath Parser context
8663 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008664 * @first: pointer to the first element in document order
8665 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008666 *
8667 * This is the function implementing a step: based on the current list
8668 * of nodes, it builds up a new list, looking at all nodes under that
8669 * axis and selecting them it also do the predicate filtering
8670 *
8671 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008672 *
8673 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008674 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008675static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008676xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008677 xmlXPathStepOpPtr op,
8678 xmlNodePtr * first, xmlNodePtr * last)
8679{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008680 xmlXPathAxisVal axis = op->value;
8681 xmlXPathTestVal test = op->value2;
8682 xmlXPathTypeVal type = op->value3;
8683 const xmlChar *prefix = op->value4;
8684 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008685 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008686
8687#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008688 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008689#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008690 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008691 xmlNodeSetPtr ret, list;
8692 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008693 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008694 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008695 xmlNodePtr cur = NULL;
8696 xmlXPathObjectPtr obj;
8697 xmlNodeSetPtr nodelist;
8698 xmlNodePtr tmp;
8699
Daniel Veillardf06307e2001-07-03 10:35:50 +00008700 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008701 obj = valuePop(ctxt);
8702 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008703 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008704 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008705 URI = xmlXPathNsLookup(ctxt->context, prefix);
8706 if (URI == NULL)
8707 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008708 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008709#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008710 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008711#endif
8712 switch (axis) {
8713 case AXIS_ANCESTOR:
8714#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008715 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008716#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008717 first = NULL;
8718 next = xmlXPathNextAncestor;
8719 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008720 case AXIS_ANCESTOR_OR_SELF:
8721#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008722 xmlGenericError(xmlGenericErrorContext,
8723 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008724#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008725 first = NULL;
8726 next = xmlXPathNextAncestorOrSelf;
8727 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008728 case AXIS_ATTRIBUTE:
8729#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008730 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008731#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008732 first = NULL;
8733 last = NULL;
8734 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008735 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008736 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008737 case AXIS_CHILD:
8738#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008739 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008740#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008741 last = NULL;
8742 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008743 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008744 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008745 case AXIS_DESCENDANT:
8746#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008747 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008748#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008749 last = NULL;
8750 next = xmlXPathNextDescendant;
8751 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008752 case AXIS_DESCENDANT_OR_SELF:
8753#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008754 xmlGenericError(xmlGenericErrorContext,
8755 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008756#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008757 last = NULL;
8758 next = xmlXPathNextDescendantOrSelf;
8759 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008760 case AXIS_FOLLOWING:
8761#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008762 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008763#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008764 last = NULL;
8765 next = xmlXPathNextFollowing;
8766 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008767 case AXIS_FOLLOWING_SIBLING:
8768#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008769 xmlGenericError(xmlGenericErrorContext,
8770 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008771#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008772 last = NULL;
8773 next = xmlXPathNextFollowingSibling;
8774 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008775 case AXIS_NAMESPACE:
8776#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008777 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008778#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008779 first = NULL;
8780 last = NULL;
8781 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008782 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008783 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008784 case AXIS_PARENT:
8785#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008786 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008787#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008788 first = NULL;
8789 next = xmlXPathNextParent;
8790 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008791 case AXIS_PRECEDING:
8792#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008793 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008794#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008795 first = NULL;
8796 next = xmlXPathNextPrecedingInternal;
8797 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008798 case AXIS_PRECEDING_SIBLING:
8799#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008800 xmlGenericError(xmlGenericErrorContext,
8801 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008802#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008803 first = NULL;
8804 next = xmlXPathNextPrecedingSibling;
8805 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008806 case AXIS_SELF:
8807#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008808 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008809#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008810 first = NULL;
8811 last = NULL;
8812 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008813 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008814 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008815 }
8816 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008817 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008818
8819 nodelist = obj->nodesetval;
8820 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008821 xmlXPathFreeObject(obj);
8822 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8823 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008824 }
8825 addNode = xmlXPathNodeSetAddUnique;
8826 ret = NULL;
8827#ifdef DEBUG_STEP
8828 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008829 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008830 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008831 case NODE_TEST_NONE:
8832 xmlGenericError(xmlGenericErrorContext,
8833 " searching for none !!!\n");
8834 break;
8835 case NODE_TEST_TYPE:
8836 xmlGenericError(xmlGenericErrorContext,
8837 " searching for type %d\n", type);
8838 break;
8839 case NODE_TEST_PI:
8840 xmlGenericError(xmlGenericErrorContext,
8841 " searching for PI !!!\n");
8842 break;
8843 case NODE_TEST_ALL:
8844 xmlGenericError(xmlGenericErrorContext,
8845 " searching for *\n");
8846 break;
8847 case NODE_TEST_NS:
8848 xmlGenericError(xmlGenericErrorContext,
8849 " searching for namespace %s\n",
8850 prefix);
8851 break;
8852 case NODE_TEST_NAME:
8853 xmlGenericError(xmlGenericErrorContext,
8854 " searching for name %s\n", name);
8855 if (prefix != NULL)
8856 xmlGenericError(xmlGenericErrorContext,
8857 " with namespace %s\n", prefix);
8858 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008859 }
8860 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8861#endif
8862 /*
8863 * 2.3 Node Tests
8864 * - For the attribute axis, the principal node type is attribute.
8865 * - For the namespace axis, the principal node type is namespace.
8866 * - For other axes, the principal node type is element.
8867 *
8868 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008869 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008870 * select all element children of the context node
8871 */
8872 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008873 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008874 ctxt->context->node = nodelist->nodeTab[i];
8875
Daniel Veillardf06307e2001-07-03 10:35:50 +00008876 cur = NULL;
8877 list = xmlXPathNodeSetCreate(NULL);
8878 do {
8879 cur = next(ctxt, cur);
8880 if (cur == NULL)
8881 break;
8882 if ((first != NULL) && (*first == cur))
8883 break;
8884 if (((t % 256) == 0) &&
8885 (first != NULL) && (*first != NULL) &&
8886 (xmlXPathCmpNodes(*first, cur) >= 0))
8887 break;
8888 if ((last != NULL) && (*last == cur))
8889 break;
8890 if (((t % 256) == 0) &&
8891 (last != NULL) && (*last != NULL) &&
8892 (xmlXPathCmpNodes(cur, *last) >= 0))
8893 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008894 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008895#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008896 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8897#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008898 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008899 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008900 ctxt->context->node = tmp;
8901 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008902 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008903 if ((cur->type == type) ||
8904 ((type == NODE_TYPE_NODE) &&
8905 ((cur->type == XML_DOCUMENT_NODE) ||
8906 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8907 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008908 (cur->type == XML_NAMESPACE_DECL) ||
8909 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008910 (cur->type == XML_PI_NODE) ||
8911 (cur->type == XML_COMMENT_NODE) ||
8912 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008913 (cur->type == XML_TEXT_NODE))) ||
8914 ((type == NODE_TYPE_TEXT) &&
8915 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008916#ifdef DEBUG_STEP
8917 n++;
8918#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008919 addNode(list, cur);
8920 }
8921 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008922 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008923 if (cur->type == XML_PI_NODE) {
8924 if ((name != NULL) &&
8925 (!xmlStrEqual(name, cur->name)))
8926 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008927#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008928 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008929#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008930 addNode(list, cur);
8931 }
8932 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008933 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008934 if (axis == AXIS_ATTRIBUTE) {
8935 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008936#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008937 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008938#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008939 addNode(list, cur);
8940 }
8941 } else if (axis == AXIS_NAMESPACE) {
8942 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008943#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008944 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008945#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008946 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8947 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008948 }
8949 } else {
8950 if (cur->type == XML_ELEMENT_NODE) {
8951 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008952#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008953 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008954#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 addNode(list, cur);
8956 } else if ((cur->ns != NULL) &&
8957 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008958#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008959 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008960#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008961 addNode(list, cur);
8962 }
8963 }
8964 }
8965 break;
8966 case NODE_TEST_NS:{
8967 TODO;
8968 break;
8969 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008971 switch (cur->type) {
8972 case XML_ELEMENT_NODE:
8973 if (xmlStrEqual(name, cur->name)) {
8974 if (prefix == NULL) {
8975 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008976#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008977 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008978#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008979 addNode(list, cur);
8980 }
8981 } else {
8982 if ((cur->ns != NULL) &&
8983 (xmlStrEqual(URI,
8984 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008986 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008987#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008988 addNode(list, cur);
8989 }
8990 }
8991 }
8992 break;
8993 case XML_ATTRIBUTE_NODE:{
8994 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008995
Daniel Veillardf06307e2001-07-03 10:35:50 +00008996 if (xmlStrEqual(name, attr->name)) {
8997 if (prefix == NULL) {
8998 if ((attr->ns == NULL) ||
8999 (attr->ns->prefix == NULL)) {
9000#ifdef DEBUG_STEP
9001 n++;
9002#endif
9003 addNode(list,
9004 (xmlNodePtr) attr);
9005 }
9006 } else {
9007 if ((attr->ns != NULL) &&
9008 (xmlStrEqual(URI,
9009 attr->ns->
9010 href))) {
9011#ifdef DEBUG_STEP
9012 n++;
9013#endif
9014 addNode(list,
9015 (xmlNodePtr) attr);
9016 }
9017 }
9018 }
9019 break;
9020 }
9021 case XML_NAMESPACE_DECL:
9022 if (cur->type == XML_NAMESPACE_DECL) {
9023 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009024
Daniel Veillardf06307e2001-07-03 10:35:50 +00009025 if ((ns->prefix != NULL) && (name != NULL)
9026 && (xmlStrEqual(ns->prefix, name))) {
9027#ifdef DEBUG_STEP
9028 n++;
9029#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009030 xmlXPathNodeSetAddNs(list,
9031 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009032 }
9033 }
9034 break;
9035 default:
9036 break;
9037 }
9038 break;
9039 break;
9040 }
9041 } while (cur != NULL);
9042
9043 /*
9044 * If there is some predicate filtering do it now
9045 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009046 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009047 xmlXPathObjectPtr obj2;
9048
9049 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9050 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9051 CHECK_TYPE0(XPATH_NODESET);
9052 obj2 = valuePop(ctxt);
9053 list = obj2->nodesetval;
9054 obj2->nodesetval = NULL;
9055 xmlXPathFreeObject(obj2);
9056 }
9057 if (ret == NULL) {
9058 ret = list;
9059 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009060 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009061 xmlXPathFreeNodeSet(list);
9062 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009063 }
9064 ctxt->context->node = tmp;
9065#ifdef DEBUG_STEP
9066 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009067 "\nExamined %d nodes, found %d nodes at that step\n",
9068 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009069#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009070 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009071 if ((obj->boolval) && (obj->user != NULL)) {
9072 ctxt->value->boolval = 1;
9073 ctxt->value->user = obj->user;
9074 obj->user = NULL;
9075 obj->boolval = 0;
9076 }
9077 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009078 return(t);
9079}
9080
9081/**
9082 * xmlXPathNodeCollectAndTestNth:
9083 * @ctxt: the XPath Parser context
9084 * @op: the XPath precompiled step operation
9085 * @indx: the index to collect
9086 * @first: pointer to the first element in document order
9087 * @last: pointer to the last element in document order
9088 *
9089 * This is the function implementing a step: based on the current list
9090 * of nodes, it builds up a new list, looking at all nodes under that
9091 * axis and selecting them it also do the predicate filtering
9092 *
9093 * Pushes the new NodeSet resulting from the search.
9094 * Returns the number of node traversed
9095 */
9096static int
9097xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9098 xmlXPathStepOpPtr op, int indx,
9099 xmlNodePtr * first, xmlNodePtr * last)
9100{
9101 xmlXPathAxisVal axis = op->value;
9102 xmlXPathTestVal test = op->value2;
9103 xmlXPathTypeVal type = op->value3;
9104 const xmlChar *prefix = op->value4;
9105 const xmlChar *name = op->value5;
9106 const xmlChar *URI = NULL;
9107 int n = 0, t = 0;
9108
9109 int i;
9110 xmlNodeSetPtr list;
9111 xmlXPathTraversalFunction next = NULL;
9112 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9113 xmlNodePtr cur = NULL;
9114 xmlXPathObjectPtr obj;
9115 xmlNodeSetPtr nodelist;
9116 xmlNodePtr tmp;
9117
9118 CHECK_TYPE0(XPATH_NODESET);
9119 obj = valuePop(ctxt);
9120 addNode = xmlXPathNodeSetAdd;
9121 if (prefix != NULL) {
9122 URI = xmlXPathNsLookup(ctxt->context, prefix);
9123 if (URI == NULL)
9124 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9125 }
9126#ifdef DEBUG_STEP_NTH
9127 xmlGenericError(xmlGenericErrorContext, "new step : ");
9128 if (first != NULL) {
9129 if (*first != NULL)
9130 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9131 (*first)->name);
9132 else
9133 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9134 }
9135 if (last != NULL) {
9136 if (*last != NULL)
9137 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9138 (*last)->name);
9139 else
9140 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9141 }
9142#endif
9143 switch (axis) {
9144 case AXIS_ANCESTOR:
9145#ifdef DEBUG_STEP_NTH
9146 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9147#endif
9148 first = NULL;
9149 next = xmlXPathNextAncestor;
9150 break;
9151 case AXIS_ANCESTOR_OR_SELF:
9152#ifdef DEBUG_STEP_NTH
9153 xmlGenericError(xmlGenericErrorContext,
9154 "axis 'ancestors-or-self' ");
9155#endif
9156 first = NULL;
9157 next = xmlXPathNextAncestorOrSelf;
9158 break;
9159 case AXIS_ATTRIBUTE:
9160#ifdef DEBUG_STEP_NTH
9161 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9162#endif
9163 first = NULL;
9164 last = NULL;
9165 next = xmlXPathNextAttribute;
9166 break;
9167 case AXIS_CHILD:
9168#ifdef DEBUG_STEP_NTH
9169 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9170#endif
9171 last = NULL;
9172 next = xmlXPathNextChild;
9173 break;
9174 case AXIS_DESCENDANT:
9175#ifdef DEBUG_STEP_NTH
9176 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9177#endif
9178 last = NULL;
9179 next = xmlXPathNextDescendant;
9180 break;
9181 case AXIS_DESCENDANT_OR_SELF:
9182#ifdef DEBUG_STEP_NTH
9183 xmlGenericError(xmlGenericErrorContext,
9184 "axis 'descendant-or-self' ");
9185#endif
9186 last = NULL;
9187 next = xmlXPathNextDescendantOrSelf;
9188 break;
9189 case AXIS_FOLLOWING:
9190#ifdef DEBUG_STEP_NTH
9191 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9192#endif
9193 last = NULL;
9194 next = xmlXPathNextFollowing;
9195 break;
9196 case AXIS_FOLLOWING_SIBLING:
9197#ifdef DEBUG_STEP_NTH
9198 xmlGenericError(xmlGenericErrorContext,
9199 "axis 'following-siblings' ");
9200#endif
9201 last = NULL;
9202 next = xmlXPathNextFollowingSibling;
9203 break;
9204 case AXIS_NAMESPACE:
9205#ifdef DEBUG_STEP_NTH
9206 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9207#endif
9208 last = NULL;
9209 first = NULL;
9210 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9211 break;
9212 case AXIS_PARENT:
9213#ifdef DEBUG_STEP_NTH
9214 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9215#endif
9216 first = NULL;
9217 next = xmlXPathNextParent;
9218 break;
9219 case AXIS_PRECEDING:
9220#ifdef DEBUG_STEP_NTH
9221 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9222#endif
9223 first = NULL;
9224 next = xmlXPathNextPrecedingInternal;
9225 break;
9226 case AXIS_PRECEDING_SIBLING:
9227#ifdef DEBUG_STEP_NTH
9228 xmlGenericError(xmlGenericErrorContext,
9229 "axis 'preceding-sibling' ");
9230#endif
9231 first = NULL;
9232 next = xmlXPathNextPrecedingSibling;
9233 break;
9234 case AXIS_SELF:
9235#ifdef DEBUG_STEP_NTH
9236 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9237#endif
9238 first = NULL;
9239 last = NULL;
9240 next = xmlXPathNextSelf;
9241 break;
9242 }
9243 if (next == NULL)
9244 return(0);
9245
9246 nodelist = obj->nodesetval;
9247 if (nodelist == NULL) {
9248 xmlXPathFreeObject(obj);
9249 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9250 return(0);
9251 }
9252 addNode = xmlXPathNodeSetAddUnique;
9253#ifdef DEBUG_STEP_NTH
9254 xmlGenericError(xmlGenericErrorContext,
9255 " context contains %d nodes\n", nodelist->nodeNr);
9256 switch (test) {
9257 case NODE_TEST_NONE:
9258 xmlGenericError(xmlGenericErrorContext,
9259 " searching for none !!!\n");
9260 break;
9261 case NODE_TEST_TYPE:
9262 xmlGenericError(xmlGenericErrorContext,
9263 " searching for type %d\n", type);
9264 break;
9265 case NODE_TEST_PI:
9266 xmlGenericError(xmlGenericErrorContext,
9267 " searching for PI !!!\n");
9268 break;
9269 case NODE_TEST_ALL:
9270 xmlGenericError(xmlGenericErrorContext,
9271 " searching for *\n");
9272 break;
9273 case NODE_TEST_NS:
9274 xmlGenericError(xmlGenericErrorContext,
9275 " searching for namespace %s\n",
9276 prefix);
9277 break;
9278 case NODE_TEST_NAME:
9279 xmlGenericError(xmlGenericErrorContext,
9280 " searching for name %s\n", name);
9281 if (prefix != NULL)
9282 xmlGenericError(xmlGenericErrorContext,
9283 " with namespace %s\n", prefix);
9284 break;
9285 }
9286 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9287#endif
9288 /*
9289 * 2.3 Node Tests
9290 * - For the attribute axis, the principal node type is attribute.
9291 * - For the namespace axis, the principal node type is namespace.
9292 * - For other axes, the principal node type is element.
9293 *
9294 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009295 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009296 * select all element children of the context node
9297 */
9298 tmp = ctxt->context->node;
9299 list = xmlXPathNodeSetCreate(NULL);
9300 for (i = 0; i < nodelist->nodeNr; i++) {
9301 ctxt->context->node = nodelist->nodeTab[i];
9302
9303 cur = NULL;
9304 n = 0;
9305 do {
9306 cur = next(ctxt, cur);
9307 if (cur == NULL)
9308 break;
9309 if ((first != NULL) && (*first == cur))
9310 break;
9311 if (((t % 256) == 0) &&
9312 (first != NULL) && (*first != NULL) &&
9313 (xmlXPathCmpNodes(*first, cur) >= 0))
9314 break;
9315 if ((last != NULL) && (*last == cur))
9316 break;
9317 if (((t % 256) == 0) &&
9318 (last != NULL) && (*last != NULL) &&
9319 (xmlXPathCmpNodes(cur, *last) >= 0))
9320 break;
9321 t++;
9322 switch (test) {
9323 case NODE_TEST_NONE:
9324 ctxt->context->node = tmp;
9325 STRANGE return(0);
9326 case NODE_TEST_TYPE:
9327 if ((cur->type == type) ||
9328 ((type == NODE_TYPE_NODE) &&
9329 ((cur->type == XML_DOCUMENT_NODE) ||
9330 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9331 (cur->type == XML_ELEMENT_NODE) ||
9332 (cur->type == XML_PI_NODE) ||
9333 (cur->type == XML_COMMENT_NODE) ||
9334 (cur->type == XML_CDATA_SECTION_NODE) ||
9335 (cur->type == XML_TEXT_NODE)))) {
9336 n++;
9337 if (n == indx)
9338 addNode(list, cur);
9339 }
9340 break;
9341 case NODE_TEST_PI:
9342 if (cur->type == XML_PI_NODE) {
9343 if ((name != NULL) &&
9344 (!xmlStrEqual(name, cur->name)))
9345 break;
9346 n++;
9347 if (n == indx)
9348 addNode(list, cur);
9349 }
9350 break;
9351 case NODE_TEST_ALL:
9352 if (axis == AXIS_ATTRIBUTE) {
9353 if (cur->type == XML_ATTRIBUTE_NODE) {
9354 n++;
9355 if (n == indx)
9356 addNode(list, cur);
9357 }
9358 } else if (axis == AXIS_NAMESPACE) {
9359 if (cur->type == XML_NAMESPACE_DECL) {
9360 n++;
9361 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009362 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9363 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009364 }
9365 } else {
9366 if (cur->type == XML_ELEMENT_NODE) {
9367 if (prefix == NULL) {
9368 n++;
9369 if (n == indx)
9370 addNode(list, cur);
9371 } else if ((cur->ns != NULL) &&
9372 (xmlStrEqual(URI, cur->ns->href))) {
9373 n++;
9374 if (n == indx)
9375 addNode(list, cur);
9376 }
9377 }
9378 }
9379 break;
9380 case NODE_TEST_NS:{
9381 TODO;
9382 break;
9383 }
9384 case NODE_TEST_NAME:
9385 switch (cur->type) {
9386 case XML_ELEMENT_NODE:
9387 if (xmlStrEqual(name, cur->name)) {
9388 if (prefix == NULL) {
9389 if (cur->ns == NULL) {
9390 n++;
9391 if (n == indx)
9392 addNode(list, cur);
9393 }
9394 } else {
9395 if ((cur->ns != NULL) &&
9396 (xmlStrEqual(URI,
9397 cur->ns->href))) {
9398 n++;
9399 if (n == indx)
9400 addNode(list, cur);
9401 }
9402 }
9403 }
9404 break;
9405 case XML_ATTRIBUTE_NODE:{
9406 xmlAttrPtr attr = (xmlAttrPtr) cur;
9407
9408 if (xmlStrEqual(name, attr->name)) {
9409 if (prefix == NULL) {
9410 if ((attr->ns == NULL) ||
9411 (attr->ns->prefix == NULL)) {
9412 n++;
9413 if (n == indx)
9414 addNode(list, cur);
9415 }
9416 } else {
9417 if ((attr->ns != NULL) &&
9418 (xmlStrEqual(URI,
9419 attr->ns->
9420 href))) {
9421 n++;
9422 if (n == indx)
9423 addNode(list, cur);
9424 }
9425 }
9426 }
9427 break;
9428 }
9429 case XML_NAMESPACE_DECL:
9430 if (cur->type == XML_NAMESPACE_DECL) {
9431 xmlNsPtr ns = (xmlNsPtr) cur;
9432
9433 if ((ns->prefix != NULL) && (name != NULL)
9434 && (xmlStrEqual(ns->prefix, name))) {
9435 n++;
9436 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009437 xmlXPathNodeSetAddNs(list,
9438 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009439 }
9440 }
9441 break;
9442 default:
9443 break;
9444 }
9445 break;
9446 break;
9447 }
9448 } while (n < indx);
9449 }
9450 ctxt->context->node = tmp;
9451#ifdef DEBUG_STEP_NTH
9452 xmlGenericError(xmlGenericErrorContext,
9453 "\nExamined %d nodes, found %d nodes at that step\n",
9454 t, list->nodeNr);
9455#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009456 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009457 if ((obj->boolval) && (obj->user != NULL)) {
9458 ctxt->value->boolval = 1;
9459 ctxt->value->user = obj->user;
9460 obj->user = NULL;
9461 obj->boolval = 0;
9462 }
9463 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009464 return(t);
9465}
9466
9467/**
9468 * xmlXPathCompOpEvalFirst:
9469 * @ctxt: the XPath parser context with the compiled expression
9470 * @op: an XPath compiled operation
9471 * @first: the first elem found so far
9472 *
9473 * Evaluate the Precompiled XPath operation searching only the first
9474 * element in document order
9475 *
9476 * Returns the number of examined objects.
9477 */
9478static int
9479xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9480 xmlXPathStepOpPtr op, xmlNodePtr * first)
9481{
9482 int total = 0, cur;
9483 xmlXPathCompExprPtr comp;
9484 xmlXPathObjectPtr arg1, arg2;
9485
Daniel Veillard556c6682001-10-06 09:59:51 +00009486 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009487 comp = ctxt->comp;
9488 switch (op->op) {
9489 case XPATH_OP_END:
9490 return (0);
9491 case XPATH_OP_UNION:
9492 total =
9493 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9494 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009495 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009496 if ((ctxt->value != NULL)
9497 && (ctxt->value->type == XPATH_NODESET)
9498 && (ctxt->value->nodesetval != NULL)
9499 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9500 /*
9501 * limit tree traversing to first node in the result
9502 */
9503 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9504 *first = ctxt->value->nodesetval->nodeTab[0];
9505 }
9506 cur =
9507 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9508 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009509 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009510 CHECK_TYPE0(XPATH_NODESET);
9511 arg2 = valuePop(ctxt);
9512
9513 CHECK_TYPE0(XPATH_NODESET);
9514 arg1 = valuePop(ctxt);
9515
9516 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9517 arg2->nodesetval);
9518 valuePush(ctxt, arg1);
9519 xmlXPathFreeObject(arg2);
9520 /* optimizer */
9521 if (total > cur)
9522 xmlXPathCompSwap(op);
9523 return (total + cur);
9524 case XPATH_OP_ROOT:
9525 xmlXPathRoot(ctxt);
9526 return (0);
9527 case XPATH_OP_NODE:
9528 if (op->ch1 != -1)
9529 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009530 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009531 if (op->ch2 != -1)
9532 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009533 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009534 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9535 return (total);
9536 case XPATH_OP_RESET:
9537 if (op->ch1 != -1)
9538 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009539 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009540 if (op->ch2 != -1)
9541 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009542 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009543 ctxt->context->node = NULL;
9544 return (total);
9545 case XPATH_OP_COLLECT:{
9546 if (op->ch1 == -1)
9547 return (total);
9548
9549 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009550 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009551
9552 /*
9553 * Optimization for [n] selection where n is a number
9554 */
9555 if ((op->ch2 != -1) &&
9556 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9557 (comp->steps[op->ch2].ch1 == -1) &&
9558 (comp->steps[op->ch2].ch2 != -1) &&
9559 (comp->steps[comp->steps[op->ch2].ch2].op ==
9560 XPATH_OP_VALUE)) {
9561 xmlXPathObjectPtr val;
9562
9563 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9564 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9565 int indx = (int) val->floatval;
9566
9567 if (val->floatval == (float) indx) {
9568 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9569 first, NULL);
9570 return (total);
9571 }
9572 }
9573 }
9574 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9575 return (total);
9576 }
9577 case XPATH_OP_VALUE:
9578 valuePush(ctxt,
9579 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9580 return (0);
9581 case XPATH_OP_SORT:
9582 if (op->ch1 != -1)
9583 total +=
9584 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9585 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009586 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009587 if ((ctxt->value != NULL)
9588 && (ctxt->value->type == XPATH_NODESET)
9589 && (ctxt->value->nodesetval != NULL))
9590 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9591 return (total);
9592 default:
9593 return (xmlXPathCompOpEval(ctxt, op));
9594 }
9595}
9596
9597/**
9598 * xmlXPathCompOpEvalLast:
9599 * @ctxt: the XPath parser context with the compiled expression
9600 * @op: an XPath compiled operation
9601 * @last: the last elem found so far
9602 *
9603 * Evaluate the Precompiled XPath operation searching only the last
9604 * element in document order
9605 *
9606 * Returns the number of node traversed
9607 */
9608static int
9609xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9610 xmlNodePtr * last)
9611{
9612 int total = 0, cur;
9613 xmlXPathCompExprPtr comp;
9614 xmlXPathObjectPtr arg1, arg2;
9615
Daniel Veillard556c6682001-10-06 09:59:51 +00009616 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009617 comp = ctxt->comp;
9618 switch (op->op) {
9619 case XPATH_OP_END:
9620 return (0);
9621 case XPATH_OP_UNION:
9622 total =
9623 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009624 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009625 if ((ctxt->value != NULL)
9626 && (ctxt->value->type == XPATH_NODESET)
9627 && (ctxt->value->nodesetval != NULL)
9628 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9629 /*
9630 * limit tree traversing to first node in the result
9631 */
9632 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9633 *last =
9634 ctxt->value->nodesetval->nodeTab[ctxt->value->
9635 nodesetval->nodeNr -
9636 1];
9637 }
9638 cur =
9639 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009640 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009641 if ((ctxt->value != NULL)
9642 && (ctxt->value->type == XPATH_NODESET)
9643 && (ctxt->value->nodesetval != NULL)
9644 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9645 }
9646 CHECK_TYPE0(XPATH_NODESET);
9647 arg2 = valuePop(ctxt);
9648
9649 CHECK_TYPE0(XPATH_NODESET);
9650 arg1 = valuePop(ctxt);
9651
9652 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9653 arg2->nodesetval);
9654 valuePush(ctxt, arg1);
9655 xmlXPathFreeObject(arg2);
9656 /* optimizer */
9657 if (total > cur)
9658 xmlXPathCompSwap(op);
9659 return (total + cur);
9660 case XPATH_OP_ROOT:
9661 xmlXPathRoot(ctxt);
9662 return (0);
9663 case XPATH_OP_NODE:
9664 if (op->ch1 != -1)
9665 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009666 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009667 if (op->ch2 != -1)
9668 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009669 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009670 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9671 return (total);
9672 case XPATH_OP_RESET:
9673 if (op->ch1 != -1)
9674 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009675 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009676 if (op->ch2 != -1)
9677 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009678 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009679 ctxt->context->node = NULL;
9680 return (total);
9681 case XPATH_OP_COLLECT:{
9682 if (op->ch1 == -1)
9683 return (0);
9684
9685 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009686 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009687
9688 /*
9689 * Optimization for [n] selection where n is a number
9690 */
9691 if ((op->ch2 != -1) &&
9692 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9693 (comp->steps[op->ch2].ch1 == -1) &&
9694 (comp->steps[op->ch2].ch2 != -1) &&
9695 (comp->steps[comp->steps[op->ch2].ch2].op ==
9696 XPATH_OP_VALUE)) {
9697 xmlXPathObjectPtr val;
9698
9699 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9700 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9701 int indx = (int) val->floatval;
9702
9703 if (val->floatval == (float) indx) {
9704 total +=
9705 xmlXPathNodeCollectAndTestNth(ctxt, op,
9706 indx, NULL,
9707 last);
9708 return (total);
9709 }
9710 }
9711 }
9712 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9713 return (total);
9714 }
9715 case XPATH_OP_VALUE:
9716 valuePush(ctxt,
9717 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9718 return (0);
9719 case XPATH_OP_SORT:
9720 if (op->ch1 != -1)
9721 total +=
9722 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9723 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009724 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009725 if ((ctxt->value != NULL)
9726 && (ctxt->value->type == XPATH_NODESET)
9727 && (ctxt->value->nodesetval != NULL))
9728 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9729 return (total);
9730 default:
9731 return (xmlXPathCompOpEval(ctxt, op));
9732 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009733}
9734
Owen Taylor3473f882001-02-23 17:55:21 +00009735/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009736 * xmlXPathCompOpEval:
9737 * @ctxt: the XPath parser context with the compiled expression
9738 * @op: an XPath compiled operation
9739 *
9740 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009741 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009742 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009743static int
9744xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9745{
9746 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009747 int equal, ret;
9748 xmlXPathCompExprPtr comp;
9749 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009750 xmlNodePtr bak;
9751 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009752 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009753 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009754
Daniel Veillard556c6682001-10-06 09:59:51 +00009755 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009756 comp = ctxt->comp;
9757 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009758 case XPATH_OP_END:
9759 return (0);
9760 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009761 bakd = ctxt->context->doc;
9762 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009763 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009764 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009765 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009766 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009767 xmlXPathBooleanFunction(ctxt, 1);
9768 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9769 return (total);
9770 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009771 ctxt->context->doc = bakd;
9772 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009773 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009774 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009775 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009776 if (ctxt->error) {
9777 xmlXPathFreeObject(arg2);
9778 return(0);
9779 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009780 xmlXPathBooleanFunction(ctxt, 1);
9781 arg1 = valuePop(ctxt);
9782 arg1->boolval &= arg2->boolval;
9783 valuePush(ctxt, arg1);
9784 xmlXPathFreeObject(arg2);
9785 return (total);
9786 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009787 bakd = ctxt->context->doc;
9788 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009789 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009790 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009791 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009792 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009793 xmlXPathBooleanFunction(ctxt, 1);
9794 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9795 return (total);
9796 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009797 ctxt->context->doc = bakd;
9798 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009799 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009800 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009801 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009802 if (ctxt->error) {
9803 xmlXPathFreeObject(arg2);
9804 return(0);
9805 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009806 xmlXPathBooleanFunction(ctxt, 1);
9807 arg1 = valuePop(ctxt);
9808 arg1->boolval |= arg2->boolval;
9809 valuePush(ctxt, arg1);
9810 xmlXPathFreeObject(arg2);
9811 return (total);
9812 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009813 bakd = ctxt->context->doc;
9814 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009815 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009816 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009817 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009818 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009819 ctxt->context->doc = bakd;
9820 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009821 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009822 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009824 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009825 if (op->value)
9826 equal = xmlXPathEqualValues(ctxt);
9827 else
9828 equal = xmlXPathNotEqualValues(ctxt);
9829 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009830 return (total);
9831 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009832 bakd = ctxt->context->doc;
9833 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009834 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009835 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009836 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009837 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009838 ctxt->context->doc = bakd;
9839 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009840 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009841 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009843 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009844 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9845 valuePush(ctxt, xmlXPathNewBoolean(ret));
9846 return (total);
9847 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009848 bakd = ctxt->context->doc;
9849 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009850 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009851 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009852 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009853 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009854 if (op->ch2 != -1) {
9855 ctxt->context->doc = bakd;
9856 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009857 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009858 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009859 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009860 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009861 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009862 if (op->value == 0)
9863 xmlXPathSubValues(ctxt);
9864 else if (op->value == 1)
9865 xmlXPathAddValues(ctxt);
9866 else if (op->value == 2)
9867 xmlXPathValueFlipSign(ctxt);
9868 else if (op->value == 3) {
9869 CAST_TO_NUMBER;
9870 CHECK_TYPE0(XPATH_NUMBER);
9871 }
9872 return (total);
9873 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009874 bakd = ctxt->context->doc;
9875 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009876 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009877 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009878 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009879 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009880 ctxt->context->doc = bakd;
9881 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009882 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009883 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009884 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009885 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009886 if (op->value == 0)
9887 xmlXPathMultValues(ctxt);
9888 else if (op->value == 1)
9889 xmlXPathDivValues(ctxt);
9890 else if (op->value == 2)
9891 xmlXPathModValues(ctxt);
9892 return (total);
9893 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009894 bakd = ctxt->context->doc;
9895 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009896 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009897 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009898 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009899 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009900 ctxt->context->doc = bakd;
9901 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009902 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009903 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009904 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009905 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009906 CHECK_TYPE0(XPATH_NODESET);
9907 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009908
Daniel Veillardf06307e2001-07-03 10:35:50 +00009909 CHECK_TYPE0(XPATH_NODESET);
9910 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009911
Daniel Veillardf06307e2001-07-03 10:35:50 +00009912 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9913 arg2->nodesetval);
9914 valuePush(ctxt, arg1);
9915 xmlXPathFreeObject(arg2);
9916 return (total);
9917 case XPATH_OP_ROOT:
9918 xmlXPathRoot(ctxt);
9919 return (total);
9920 case XPATH_OP_NODE:
9921 if (op->ch1 != -1)
9922 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009923 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009924 if (op->ch2 != -1)
9925 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009926 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009927 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9928 return (total);
9929 case XPATH_OP_RESET:
9930 if (op->ch1 != -1)
9931 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009932 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009933 if (op->ch2 != -1)
9934 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009935 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009936 ctxt->context->node = NULL;
9937 return (total);
9938 case XPATH_OP_COLLECT:{
9939 if (op->ch1 == -1)
9940 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009941
Daniel Veillardf06307e2001-07-03 10:35:50 +00009942 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009943 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009944
Daniel Veillardf06307e2001-07-03 10:35:50 +00009945 /*
9946 * Optimization for [n] selection where n is a number
9947 */
9948 if ((op->ch2 != -1) &&
9949 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9950 (comp->steps[op->ch2].ch1 == -1) &&
9951 (comp->steps[op->ch2].ch2 != -1) &&
9952 (comp->steps[comp->steps[op->ch2].ch2].op ==
9953 XPATH_OP_VALUE)) {
9954 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009955
Daniel Veillardf06307e2001-07-03 10:35:50 +00009956 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9957 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9958 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009959
Daniel Veillardf06307e2001-07-03 10:35:50 +00009960 if (val->floatval == (float) indx) {
9961 total +=
9962 xmlXPathNodeCollectAndTestNth(ctxt, op,
9963 indx, NULL,
9964 NULL);
9965 return (total);
9966 }
9967 }
9968 }
9969 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9970 return (total);
9971 }
9972 case XPATH_OP_VALUE:
9973 valuePush(ctxt,
9974 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9975 return (total);
9976 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009977 xmlXPathObjectPtr val;
9978
Daniel Veillardf06307e2001-07-03 10:35:50 +00009979 if (op->ch1 != -1)
9980 total +=
9981 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009982 if (op->value5 == NULL) {
9983 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9984 if (val == NULL) {
9985 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9986 return(0);
9987 }
9988 valuePush(ctxt, val);
9989 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009990 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009991
Daniel Veillardf06307e2001-07-03 10:35:50 +00009992 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9993 if (URI == NULL) {
9994 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009995 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 op->value4, op->value5);
9997 return (total);
9998 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009999 val = xmlXPathVariableLookupNS(ctxt->context,
10000 op->value4, URI);
10001 if (val == NULL) {
10002 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10003 return(0);
10004 }
10005 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010006 }
10007 return (total);
10008 }
10009 case XPATH_OP_FUNCTION:{
10010 xmlXPathFunction func;
10011 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010012 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010013
10014 if (op->ch1 != -1)
10015 total +=
10016 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010017 if (ctxt->valueNr < op->value) {
10018 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010019 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010020 ctxt->error = XPATH_INVALID_OPERAND;
10021 return (total);
10022 }
10023 for (i = 0; i < op->value; i++)
10024 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10025 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010026 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010027 ctxt->error = XPATH_INVALID_OPERAND;
10028 return (total);
10029 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010030 if (op->cache != NULL)
10031 func = (xmlXPathFunction) op->cache;
10032 else {
10033 const xmlChar *URI = NULL;
10034
10035 if (op->value5 == NULL)
10036 func =
10037 xmlXPathFunctionLookup(ctxt->context,
10038 op->value4);
10039 else {
10040 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10041 if (URI == NULL) {
10042 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010043 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010044 op->value4, op->value5);
10045 return (total);
10046 }
10047 func = xmlXPathFunctionLookupNS(ctxt->context,
10048 op->value4, URI);
10049 }
10050 if (func == NULL) {
10051 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010052 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010053 op->value4);
10054 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010055 }
10056 op->cache = (void *) func;
10057 op->cacheURI = (void *) URI;
10058 }
10059 oldFunc = ctxt->context->function;
10060 oldFuncURI = ctxt->context->functionURI;
10061 ctxt->context->function = op->value4;
10062 ctxt->context->functionURI = op->cacheURI;
10063 func(ctxt, op->value);
10064 ctxt->context->function = oldFunc;
10065 ctxt->context->functionURI = oldFuncURI;
10066 return (total);
10067 }
10068 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010069 bakd = ctxt->context->doc;
10070 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010071 if (op->ch1 != -1)
10072 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010073 ctxt->context->doc = bakd;
10074 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010075 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010076 if (op->ch2 != -1)
10077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010078 ctxt->context->doc = bakd;
10079 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010080 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010081 return (total);
10082 case XPATH_OP_PREDICATE:
10083 case XPATH_OP_FILTER:{
10084 xmlXPathObjectPtr res;
10085 xmlXPathObjectPtr obj, tmp;
10086 xmlNodeSetPtr newset = NULL;
10087 xmlNodeSetPtr oldset;
10088 xmlNodePtr oldnode;
10089 int i;
10090
10091 /*
10092 * Optimization for ()[1] selection i.e. the first elem
10093 */
10094 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10095 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10096 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10097 xmlXPathObjectPtr val;
10098
10099 val = comp->steps[op->ch2].value4;
10100 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10101 (val->floatval == 1.0)) {
10102 xmlNodePtr first = NULL;
10103
10104 total +=
10105 xmlXPathCompOpEvalFirst(ctxt,
10106 &comp->steps[op->ch1],
10107 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010108 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010109 /*
10110 * The nodeset should be in document order,
10111 * Keep only the first value
10112 */
10113 if ((ctxt->value != NULL) &&
10114 (ctxt->value->type == XPATH_NODESET) &&
10115 (ctxt->value->nodesetval != NULL) &&
10116 (ctxt->value->nodesetval->nodeNr > 1))
10117 ctxt->value->nodesetval->nodeNr = 1;
10118 return (total);
10119 }
10120 }
10121 /*
10122 * Optimization for ()[last()] selection i.e. the last elem
10123 */
10124 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10125 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10126 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10127 int f = comp->steps[op->ch2].ch1;
10128
10129 if ((f != -1) &&
10130 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10131 (comp->steps[f].value5 == NULL) &&
10132 (comp->steps[f].value == 0) &&
10133 (comp->steps[f].value4 != NULL) &&
10134 (xmlStrEqual
10135 (comp->steps[f].value4, BAD_CAST "last"))) {
10136 xmlNodePtr last = NULL;
10137
10138 total +=
10139 xmlXPathCompOpEvalLast(ctxt,
10140 &comp->steps[op->ch1],
10141 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010142 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010143 /*
10144 * The nodeset should be in document order,
10145 * Keep only the last value
10146 */
10147 if ((ctxt->value != NULL) &&
10148 (ctxt->value->type == XPATH_NODESET) &&
10149 (ctxt->value->nodesetval != NULL) &&
10150 (ctxt->value->nodesetval->nodeTab != NULL) &&
10151 (ctxt->value->nodesetval->nodeNr > 1)) {
10152 ctxt->value->nodesetval->nodeTab[0] =
10153 ctxt->value->nodesetval->nodeTab[ctxt->
10154 value->
10155 nodesetval->
10156 nodeNr -
10157 1];
10158 ctxt->value->nodesetval->nodeNr = 1;
10159 }
10160 return (total);
10161 }
10162 }
10163
10164 if (op->ch1 != -1)
10165 total +=
10166 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010167 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010168 if (op->ch2 == -1)
10169 return (total);
10170 if (ctxt->value == NULL)
10171 return (total);
10172
10173 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010174
10175#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010176 /*
10177 * Hum are we filtering the result of an XPointer expression
10178 */
10179 if (ctxt->value->type == XPATH_LOCATIONSET) {
10180 xmlLocationSetPtr newlocset = NULL;
10181 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010182
Daniel Veillardf06307e2001-07-03 10:35:50 +000010183 /*
10184 * Extract the old locset, and then evaluate the result of the
10185 * expression for all the element in the locset. use it to grow
10186 * up a new locset.
10187 */
10188 CHECK_TYPE0(XPATH_LOCATIONSET);
10189 obj = valuePop(ctxt);
10190 oldlocset = obj->user;
10191 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010192
Daniel Veillardf06307e2001-07-03 10:35:50 +000010193 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10194 ctxt->context->contextSize = 0;
10195 ctxt->context->proximityPosition = 0;
10196 if (op->ch2 != -1)
10197 total +=
10198 xmlXPathCompOpEval(ctxt,
10199 &comp->steps[op->ch2]);
10200 res = valuePop(ctxt);
10201 if (res != NULL)
10202 xmlXPathFreeObject(res);
10203 valuePush(ctxt, obj);
10204 CHECK_ERROR0;
10205 return (total);
10206 }
10207 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010208
Daniel Veillardf06307e2001-07-03 10:35:50 +000010209 for (i = 0; i < oldlocset->locNr; i++) {
10210 /*
10211 * Run the evaluation with a node list made of a
10212 * single item in the nodelocset.
10213 */
10214 ctxt->context->node = oldlocset->locTab[i]->user;
10215 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10216 valuePush(ctxt, tmp);
10217 ctxt->context->contextSize = oldlocset->locNr;
10218 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010219
Daniel Veillardf06307e2001-07-03 10:35:50 +000010220 if (op->ch2 != -1)
10221 total +=
10222 xmlXPathCompOpEval(ctxt,
10223 &comp->steps[op->ch2]);
10224 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010225
Daniel Veillardf06307e2001-07-03 10:35:50 +000010226 /*
10227 * The result of the evaluation need to be tested to
10228 * decided whether the filter succeeded or not
10229 */
10230 res = valuePop(ctxt);
10231 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10232 xmlXPtrLocationSetAdd(newlocset,
10233 xmlXPathObjectCopy
10234 (oldlocset->locTab[i]));
10235 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010236
Daniel Veillardf06307e2001-07-03 10:35:50 +000010237 /*
10238 * Cleanup
10239 */
10240 if (res != NULL)
10241 xmlXPathFreeObject(res);
10242 if (ctxt->value == tmp) {
10243 res = valuePop(ctxt);
10244 xmlXPathFreeObject(res);
10245 }
10246
10247 ctxt->context->node = NULL;
10248 }
10249
10250 /*
10251 * The result is used as the new evaluation locset.
10252 */
10253 xmlXPathFreeObject(obj);
10254 ctxt->context->node = NULL;
10255 ctxt->context->contextSize = -1;
10256 ctxt->context->proximityPosition = -1;
10257 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10258 ctxt->context->node = oldnode;
10259 return (total);
10260 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010261#endif /* LIBXML_XPTR_ENABLED */
10262
Daniel Veillardf06307e2001-07-03 10:35:50 +000010263 /*
10264 * Extract the old set, and then evaluate the result of the
10265 * expression for all the element in the set. use it to grow
10266 * up a new set.
10267 */
10268 CHECK_TYPE0(XPATH_NODESET);
10269 obj = valuePop(ctxt);
10270 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010271
Daniel Veillardf06307e2001-07-03 10:35:50 +000010272 oldnode = ctxt->context->node;
10273 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010274
Daniel Veillardf06307e2001-07-03 10:35:50 +000010275 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10276 ctxt->context->contextSize = 0;
10277 ctxt->context->proximityPosition = 0;
10278 if (op->ch2 != -1)
10279 total +=
10280 xmlXPathCompOpEval(ctxt,
10281 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010282 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010283 res = valuePop(ctxt);
10284 if (res != NULL)
10285 xmlXPathFreeObject(res);
10286 valuePush(ctxt, obj);
10287 ctxt->context->node = oldnode;
10288 CHECK_ERROR0;
10289 } else {
10290 /*
10291 * Initialize the new set.
10292 */
10293 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010294
Daniel Veillardf06307e2001-07-03 10:35:50 +000010295 for (i = 0; i < oldset->nodeNr; i++) {
10296 /*
10297 * Run the evaluation with a node list made of
10298 * a single item in the nodeset.
10299 */
10300 ctxt->context->node = oldset->nodeTab[i];
10301 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10302 valuePush(ctxt, tmp);
10303 ctxt->context->contextSize = oldset->nodeNr;
10304 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010305
Daniel Veillardf06307e2001-07-03 10:35:50 +000010306 if (op->ch2 != -1)
10307 total +=
10308 xmlXPathCompOpEval(ctxt,
10309 &comp->steps[op->ch2]);
10310 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010311
Daniel Veillardf06307e2001-07-03 10:35:50 +000010312 /*
10313 * The result of the evaluation need to be tested to
10314 * decided whether the filter succeeded or not
10315 */
10316 res = valuePop(ctxt);
10317 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10318 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10319 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010320
Daniel Veillardf06307e2001-07-03 10:35:50 +000010321 /*
10322 * Cleanup
10323 */
10324 if (res != NULL)
10325 xmlXPathFreeObject(res);
10326 if (ctxt->value == tmp) {
10327 res = valuePop(ctxt);
10328 xmlXPathFreeObject(res);
10329 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010330
Daniel Veillardf06307e2001-07-03 10:35:50 +000010331 ctxt->context->node = NULL;
10332 }
10333
10334 /*
10335 * The result is used as the new evaluation set.
10336 */
10337 xmlXPathFreeObject(obj);
10338 ctxt->context->node = NULL;
10339 ctxt->context->contextSize = -1;
10340 ctxt->context->proximityPosition = -1;
10341 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10342 }
10343 ctxt->context->node = oldnode;
10344 return (total);
10345 }
10346 case XPATH_OP_SORT:
10347 if (op->ch1 != -1)
10348 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010349 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010350 if ((ctxt->value != NULL) &&
10351 (ctxt->value->type == XPATH_NODESET) &&
10352 (ctxt->value->nodesetval != NULL))
10353 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10354 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010355#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010356 case XPATH_OP_RANGETO:{
10357 xmlXPathObjectPtr range;
10358 xmlXPathObjectPtr res, obj;
10359 xmlXPathObjectPtr tmp;
10360 xmlLocationSetPtr newset = NULL;
10361 xmlNodeSetPtr oldset;
10362 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010363
Daniel Veillardf06307e2001-07-03 10:35:50 +000010364 if (op->ch1 != -1)
10365 total +=
10366 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10367 if (op->ch2 == -1)
10368 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010369
Daniel Veillardf06307e2001-07-03 10:35:50 +000010370 CHECK_TYPE0(XPATH_NODESET);
10371 obj = valuePop(ctxt);
10372 oldset = obj->nodesetval;
10373 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010374
Daniel Veillardf06307e2001-07-03 10:35:50 +000010375 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010376
Daniel Veillardf06307e2001-07-03 10:35:50 +000010377 if (oldset != NULL) {
10378 for (i = 0; i < oldset->nodeNr; i++) {
10379 /*
10380 * Run the evaluation with a node list made of a single item
10381 * in the nodeset.
10382 */
10383 ctxt->context->node = oldset->nodeTab[i];
10384 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10385 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010386
Daniel Veillardf06307e2001-07-03 10:35:50 +000010387 if (op->ch2 != -1)
10388 total +=
10389 xmlXPathCompOpEval(ctxt,
10390 &comp->steps[op->ch2]);
10391 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010392
Daniel Veillardf06307e2001-07-03 10:35:50 +000010393 /*
10394 * The result of the evaluation need to be tested to
10395 * decided whether the filter succeeded or not
10396 */
10397 res = valuePop(ctxt);
10398 range =
10399 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10400 res);
10401 if (range != NULL) {
10402 xmlXPtrLocationSetAdd(newset, range);
10403 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010404
Daniel Veillardf06307e2001-07-03 10:35:50 +000010405 /*
10406 * Cleanup
10407 */
10408 if (res != NULL)
10409 xmlXPathFreeObject(res);
10410 if (ctxt->value == tmp) {
10411 res = valuePop(ctxt);
10412 xmlXPathFreeObject(res);
10413 }
10414
10415 ctxt->context->node = NULL;
10416 }
10417 }
10418
10419 /*
10420 * The result is used as the new evaluation set.
10421 */
10422 xmlXPathFreeObject(obj);
10423 ctxt->context->node = NULL;
10424 ctxt->context->contextSize = -1;
10425 ctxt->context->proximityPosition = -1;
10426 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10427 return (total);
10428 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010429#endif /* LIBXML_XPTR_ENABLED */
10430 }
10431 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010432 "XPath: unknown precompiled operation %d\n", op->op);
10433 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010434}
10435
10436/**
10437 * xmlXPathRunEval:
10438 * @ctxt: the XPath parser context with the compiled expression
10439 *
10440 * Evaluate the Precompiled XPath expression in the given context.
10441 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010442static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010443xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10444 xmlXPathCompExprPtr comp;
10445
10446 if ((ctxt == NULL) || (ctxt->comp == NULL))
10447 return;
10448
10449 if (ctxt->valueTab == NULL) {
10450 /* Allocate the value stack */
10451 ctxt->valueTab = (xmlXPathObjectPtr *)
10452 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10453 if (ctxt->valueTab == NULL) {
10454 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010455 }
10456 ctxt->valueNr = 0;
10457 ctxt->valueMax = 10;
10458 ctxt->value = NULL;
10459 }
10460 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010461 if(comp->last < 0) {
10462 xmlGenericError(xmlGenericErrorContext,
10463 "xmlXPathRunEval: last is less than zero\n");
10464 return;
10465 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010466 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10467}
10468
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010469/************************************************************************
10470 * *
10471 * Public interfaces *
10472 * *
10473 ************************************************************************/
10474
10475/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010476 * xmlXPathEvalPredicate:
10477 * @ctxt: the XPath context
10478 * @res: the Predicate Expression evaluation result
10479 *
10480 * Evaluate a predicate result for the current node.
10481 * A PredicateExpr is evaluated by evaluating the Expr and converting
10482 * the result to a boolean. If the result is a number, the result will
10483 * be converted to true if the number is equal to the position of the
10484 * context node in the context node list (as returned by the position
10485 * function) and will be converted to false otherwise; if the result
10486 * is not a number, then the result will be converted as if by a call
10487 * to the boolean function.
10488 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010489 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010490 */
10491int
10492xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10493 if (res == NULL) return(0);
10494 switch (res->type) {
10495 case XPATH_BOOLEAN:
10496 return(res->boolval);
10497 case XPATH_NUMBER:
10498 return(res->floatval == ctxt->proximityPosition);
10499 case XPATH_NODESET:
10500 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010501 if (res->nodesetval == NULL)
10502 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010503 return(res->nodesetval->nodeNr != 0);
10504 case XPATH_STRING:
10505 return((res->stringval != NULL) &&
10506 (xmlStrlen(res->stringval) != 0));
10507 default:
10508 STRANGE
10509 }
10510 return(0);
10511}
10512
10513/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010514 * xmlXPathEvaluatePredicateResult:
10515 * @ctxt: the XPath Parser context
10516 * @res: the Predicate Expression evaluation result
10517 *
10518 * Evaluate a predicate result for the current node.
10519 * A PredicateExpr is evaluated by evaluating the Expr and converting
10520 * the result to a boolean. If the result is a number, the result will
10521 * be converted to true if the number is equal to the position of the
10522 * context node in the context node list (as returned by the position
10523 * function) and will be converted to false otherwise; if the result
10524 * is not a number, then the result will be converted as if by a call
10525 * to the boolean function.
10526 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010527 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010528 */
10529int
10530xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10531 xmlXPathObjectPtr res) {
10532 if (res == NULL) return(0);
10533 switch (res->type) {
10534 case XPATH_BOOLEAN:
10535 return(res->boolval);
10536 case XPATH_NUMBER:
10537 return(res->floatval == ctxt->context->proximityPosition);
10538 case XPATH_NODESET:
10539 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010540 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010541 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010542 return(res->nodesetval->nodeNr != 0);
10543 case XPATH_STRING:
10544 return((res->stringval != NULL) &&
10545 (xmlStrlen(res->stringval) != 0));
10546 default:
10547 STRANGE
10548 }
10549 return(0);
10550}
10551
10552/**
10553 * xmlXPathCompile:
10554 * @str: the XPath expression
10555 *
10556 * Compile an XPath expression
10557 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010558 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010559 * the caller has to free the object.
10560 */
10561xmlXPathCompExprPtr
10562xmlXPathCompile(const xmlChar *str) {
10563 xmlXPathParserContextPtr ctxt;
10564 xmlXPathCompExprPtr comp;
10565
10566 xmlXPathInit();
10567
10568 ctxt = xmlXPathNewParserContext(str, NULL);
10569 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010570
Daniel Veillard40af6492001-04-22 08:50:55 +000010571 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010572 /*
10573 * aleksey: in some cases this line prints *second* error message
10574 * (see bug #78858) and probably this should be fixed.
10575 * However, we are not sure that all error messages are printed
10576 * out in other places. It's not critical so we leave it as-is for now
10577 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010578 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10579 comp = NULL;
10580 } else {
10581 comp = ctxt->comp;
10582 ctxt->comp = NULL;
10583 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010584 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010585 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010586 comp->expr = xmlStrdup(str);
10587#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010588 comp->string = xmlStrdup(str);
10589 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010590#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010591 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010592 return(comp);
10593}
10594
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010595/**
10596 * xmlXPathCompiledEval:
10597 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010598 * @ctx: the XPath context
10599 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010600 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010601 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010602 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010603 * the caller has to free the object.
10604 */
10605xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010606xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010607 xmlXPathParserContextPtr ctxt;
10608 xmlXPathObjectPtr res, tmp, init = NULL;
10609 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010610#ifndef LIBXML_THREAD_ENABLED
10611 static int reentance = 0;
10612#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010613
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010614 if ((comp == NULL) || (ctx == NULL))
10615 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010616 xmlXPathInit();
10617
10618 CHECK_CONTEXT(ctx)
10619
Daniel Veillard81463942001-10-16 12:34:39 +000010620#ifndef LIBXML_THREAD_ENABLED
10621 reentance++;
10622 if (reentance > 1)
10623 xmlXPathDisableOptimizer = 1;
10624#endif
10625
Daniel Veillardf06307e2001-07-03 10:35:50 +000010626#ifdef DEBUG_EVAL_COUNTS
10627 comp->nb++;
10628 if ((comp->string != NULL) && (comp->nb > 100)) {
10629 fprintf(stderr, "100 x %s\n", comp->string);
10630 comp->nb = 0;
10631 }
10632#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010633 ctxt = xmlXPathCompParserContext(comp, ctx);
10634 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010635
10636 if (ctxt->value == NULL) {
10637 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010638 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010639 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010640 } else {
10641 res = valuePop(ctxt);
10642 }
10643
Daniel Veillardf06307e2001-07-03 10:35:50 +000010644
Owen Taylor3473f882001-02-23 17:55:21 +000010645 do {
10646 tmp = valuePop(ctxt);
10647 if (tmp != NULL) {
10648 if (tmp != init)
10649 stack++;
10650 xmlXPathFreeObject(tmp);
10651 }
10652 } while (tmp != NULL);
10653 if ((stack != 0) && (res != NULL)) {
10654 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010655 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010656 stack);
10657 }
10658 if (ctxt->error != XPATH_EXPRESSION_OK) {
10659 xmlXPathFreeObject(res);
10660 res = NULL;
10661 }
10662
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010663
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010664 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010665 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010666#ifndef LIBXML_THREAD_ENABLED
10667 reentance--;
10668#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010669 return(res);
10670}
10671
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010672/**
10673 * xmlXPathEvalExpr:
10674 * @ctxt: the XPath Parser context
10675 *
10676 * Parse and evaluate an XPath expression in the given context,
10677 * then push the result on the context stack
10678 */
10679void
10680xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10681 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010682 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010683 xmlXPathRunEval(ctxt);
10684}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010685
10686/**
10687 * xmlXPathEval:
10688 * @str: the XPath expression
10689 * @ctx: the XPath context
10690 *
10691 * Evaluate the XPath Location Path in the given context.
10692 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010693 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010694 * the caller has to free the object.
10695 */
10696xmlXPathObjectPtr
10697xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10698 xmlXPathParserContextPtr ctxt;
10699 xmlXPathObjectPtr res, tmp, init = NULL;
10700 int stack = 0;
10701
10702 xmlXPathInit();
10703
10704 CHECK_CONTEXT(ctx)
10705
10706 ctxt = xmlXPathNewParserContext(str, ctx);
10707 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010708
10709 if (ctxt->value == NULL) {
10710 xmlGenericError(xmlGenericErrorContext,
10711 "xmlXPathEval: evaluation failed\n");
10712 res = NULL;
10713 } else if (*ctxt->cur != 0) {
10714 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10715 res = NULL;
10716 } else {
10717 res = valuePop(ctxt);
10718 }
10719
10720 do {
10721 tmp = valuePop(ctxt);
10722 if (tmp != NULL) {
10723 if (tmp != init)
10724 stack++;
10725 xmlXPathFreeObject(tmp);
10726 }
10727 } while (tmp != NULL);
10728 if ((stack != 0) && (res != NULL)) {
10729 xmlGenericError(xmlGenericErrorContext,
10730 "xmlXPathEval: %d object left on the stack\n",
10731 stack);
10732 }
10733 if (ctxt->error != XPATH_EXPRESSION_OK) {
10734 xmlXPathFreeObject(res);
10735 res = NULL;
10736 }
10737
Owen Taylor3473f882001-02-23 17:55:21 +000010738 xmlXPathFreeParserContext(ctxt);
10739 return(res);
10740}
10741
10742/**
10743 * xmlXPathEvalExpression:
10744 * @str: the XPath expression
10745 * @ctxt: the XPath context
10746 *
10747 * Evaluate the XPath expression in the given context.
10748 *
10749 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10750 * the caller has to free the object.
10751 */
10752xmlXPathObjectPtr
10753xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10754 xmlXPathParserContextPtr pctxt;
10755 xmlXPathObjectPtr res, tmp;
10756 int stack = 0;
10757
10758 xmlXPathInit();
10759
10760 CHECK_CONTEXT(ctxt)
10761
10762 pctxt = xmlXPathNewParserContext(str, ctxt);
10763 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010764
10765 if (*pctxt->cur != 0) {
10766 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10767 res = NULL;
10768 } else {
10769 res = valuePop(pctxt);
10770 }
10771 do {
10772 tmp = valuePop(pctxt);
10773 if (tmp != NULL) {
10774 xmlXPathFreeObject(tmp);
10775 stack++;
10776 }
10777 } while (tmp != NULL);
10778 if ((stack != 0) && (res != NULL)) {
10779 xmlGenericError(xmlGenericErrorContext,
10780 "xmlXPathEvalExpression: %d object left on the stack\n",
10781 stack);
10782 }
10783 xmlXPathFreeParserContext(pctxt);
10784 return(res);
10785}
10786
Daniel Veillard42766c02002-08-22 20:52:17 +000010787/************************************************************************
10788 * *
10789 * Extra functions not pertaining to the XPath spec *
10790 * *
10791 ************************************************************************/
10792/**
10793 * xmlXPathEscapeUriFunction:
10794 * @ctxt: the XPath Parser context
10795 * @nargs: the number of arguments
10796 *
10797 * Implement the escape-uri() XPath function
10798 * string escape-uri(string $str, bool $escape-reserved)
10799 *
10800 * This function applies the URI escaping rules defined in section 2 of [RFC
10801 * 2396] to the string supplied as $uri-part, which typically represents all
10802 * or part of a URI. The effect of the function is to replace any special
10803 * character in the string by an escape sequence of the form %xx%yy...,
10804 * where xxyy... is the hexadecimal representation of the octets used to
10805 * represent the character in UTF-8.
10806 *
10807 * The set of characters that are escaped depends on the setting of the
10808 * boolean argument $escape-reserved.
10809 *
10810 * If $escape-reserved is true, all characters are escaped other than lower
10811 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10812 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10813 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10814 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10815 * A-F).
10816 *
10817 * If $escape-reserved is false, the behavior differs in that characters
10818 * referred to in [RFC 2396] as reserved characters are not escaped. These
10819 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10820 *
10821 * [RFC 2396] does not define whether escaped URIs should use lower case or
10822 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10823 * compared using string comparison functions, this function must always use
10824 * the upper-case letters A-F.
10825 *
10826 * Generally, $escape-reserved should be set to true when escaping a string
10827 * that is to form a single part of a URI, and to false when escaping an
10828 * entire URI or URI reference.
10829 *
10830 * In the case of non-ascii characters, the string is encoded according to
10831 * utf-8 and then converted according to RFC 2396.
10832 *
10833 * Examples
10834 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10835 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10836 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10837 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10838 *
10839 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010840static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010841xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10842 xmlXPathObjectPtr str;
10843 int escape_reserved;
10844 xmlBufferPtr target;
10845 xmlChar *cptr;
10846 xmlChar escape[4];
10847
10848 CHECK_ARITY(2);
10849
10850 escape_reserved = xmlXPathPopBoolean(ctxt);
10851
10852 CAST_TO_STRING;
10853 str = valuePop(ctxt);
10854
10855 target = xmlBufferCreate();
10856
10857 escape[0] = '%';
10858 escape[3] = 0;
10859
10860 if (target) {
10861 for (cptr = str->stringval; *cptr; cptr++) {
10862 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10863 (*cptr >= 'a' && *cptr <= 'z') ||
10864 (*cptr >= '0' && *cptr <= '9') ||
10865 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10866 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10867 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10868 (*cptr == '%' &&
10869 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10870 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10871 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10872 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10873 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10874 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10875 (!escape_reserved &&
10876 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10877 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10878 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10879 *cptr == ','))) {
10880 xmlBufferAdd(target, cptr, 1);
10881 } else {
10882 if ((*cptr >> 4) < 10)
10883 escape[1] = '0' + (*cptr >> 4);
10884 else
10885 escape[1] = 'A' - 10 + (*cptr >> 4);
10886 if ((*cptr & 0xF) < 10)
10887 escape[2] = '0' + (*cptr & 0xF);
10888 else
10889 escape[2] = 'A' - 10 + (*cptr & 0xF);
10890
10891 xmlBufferAdd(target, &escape[0], 3);
10892 }
10893 }
10894 }
10895 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10896 xmlBufferFree(target);
10897 xmlXPathFreeObject(str);
10898}
10899
Owen Taylor3473f882001-02-23 17:55:21 +000010900/**
10901 * xmlXPathRegisterAllFunctions:
10902 * @ctxt: the XPath context
10903 *
10904 * Registers all default XPath functions in this context
10905 */
10906void
10907xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10908{
10909 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10910 xmlXPathBooleanFunction);
10911 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10912 xmlXPathCeilingFunction);
10913 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10914 xmlXPathCountFunction);
10915 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10916 xmlXPathConcatFunction);
10917 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10918 xmlXPathContainsFunction);
10919 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10920 xmlXPathIdFunction);
10921 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10922 xmlXPathFalseFunction);
10923 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10924 xmlXPathFloorFunction);
10925 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10926 xmlXPathLastFunction);
10927 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10928 xmlXPathLangFunction);
10929 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10930 xmlXPathLocalNameFunction);
10931 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10932 xmlXPathNotFunction);
10933 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10934 xmlXPathNameFunction);
10935 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10936 xmlXPathNamespaceURIFunction);
10937 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10938 xmlXPathNormalizeFunction);
10939 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10940 xmlXPathNumberFunction);
10941 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10942 xmlXPathPositionFunction);
10943 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10944 xmlXPathRoundFunction);
10945 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10946 xmlXPathStringFunction);
10947 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10948 xmlXPathStringLengthFunction);
10949 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10950 xmlXPathStartsWithFunction);
10951 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10952 xmlXPathSubstringFunction);
10953 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10954 xmlXPathSubstringBeforeFunction);
10955 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10956 xmlXPathSubstringAfterFunction);
10957 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10958 xmlXPathSumFunction);
10959 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10960 xmlXPathTrueFunction);
10961 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10962 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000010963
10964 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
10965 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
10966 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000010967}
10968
10969#endif /* LIBXML_XPATH_ENABLED */