blob: 7a39f74b0af041e55d42cad22b972b8b89bd49d5 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019#ifdef LIBXML_XPATH_ENABLED
20
Owen Taylor3473f882001-02-23 17:55:21 +000021#include <string.h>
22
23#ifdef HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26#ifdef HAVE_MATH_H
27#include <math.h>
28#endif
29#ifdef HAVE_FLOAT_H
30#include <float.h>
31#endif
Owen Taylor3473f882001-02-23 17:55:21 +000032#ifdef HAVE_CTYPE_H
33#include <ctype.h>
34#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000035#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000037#endif
Owen Taylor3473f882001-02-23 17:55:21 +000038
39#include <libxml/xmlmemory.h>
40#include <libxml/tree.h>
41#include <libxml/valid.h>
42#include <libxml/xpath.h>
43#include <libxml/xpathInternals.h>
44#include <libxml/parserInternals.h>
45#include <libxml/hash.h>
46#ifdef LIBXML_XPTR_ENABLED
47#include <libxml/xpointer.h>
48#endif
49#ifdef LIBXML_DEBUG_ENABLED
50#include <libxml/debugXML.h>
51#endif
52#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000053#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000054#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000055
56/* #define DEBUG */
57/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000058/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000059/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000060/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000061
Daniel Veillard5792e162001-04-30 17:44:45 +000062double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000063
Daniel Veillard20ee8c02001-10-05 09:18:14 +000064static xmlNs xmlXPathXMLNamespaceStruct = {
65 NULL,
66 XML_NAMESPACE_DECL,
67 XML_XML_NAMESPACE,
Daniel Veillard118aed72002-09-24 14:13:13 +000068 BAD_CAST "xml",
69 NULL
Daniel Veillard20ee8c02001-10-05 09:18:14 +000070};
71static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillardda423da2002-04-10 19:25:38 +000072#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +000073/*
74 * Optimizer is disabled only when threaded apps are detected while
75 * the library ain't compiled for thread safety.
76 */
77static int xmlXPathDisableOptimizer = 0;
78#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000079
Daniel Veillard9e7160d2001-03-18 23:17:47 +000080/************************************************************************
81 * *
82 * Floating point stuff *
83 * *
84 ************************************************************************/
85
Daniel Veillardc0631a62001-09-20 13:56:06 +000086#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000087#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000088#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000089#include "trionan.c"
90
Owen Taylor3473f882001-02-23 17:55:21 +000091/*
Owen Taylor3473f882001-02-23 17:55:21 +000092 * The lack of portability of this section of the libc is annoying !
93 */
94double xmlXPathNAN = 0;
95double xmlXPathPINF = 1;
96double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000097double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000098static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000099
Owen Taylor3473f882001-02-23 17:55:21 +0000100/**
101 * xmlXPathInit:
102 *
103 * Initialize the XPath environment
104 */
105void
106xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000107 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000108
Bjorn Reese45029602001-08-21 09:23:53 +0000109 xmlXPathPINF = trio_pinf();
110 xmlXPathNINF = trio_ninf();
111 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000112 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000113
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000114 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000115}
116
Daniel Veillardcda96922001-08-21 10:56:31 +0000117/**
118 * xmlXPathIsNaN:
119 * @val: a double value
120 *
121 * Provides a portable isnan() function to detect whether a double
122 * is a NotaNumber. Based on trio code
123 * http://sourceforge.net/projects/ctrio/
124 *
125 * Returns 1 if the value is a NaN, 0 otherwise
126 */
127int
128xmlXPathIsNaN(double val) {
129 return(trio_isnan(val));
130}
131
132/**
133 * xmlXPathIsInf:
134 * @val: a double value
135 *
136 * Provides a portable isinf() function to detect whether a double
137 * is a +Infinite or -Infinite. Based on trio code
138 * http://sourceforge.net/projects/ctrio/
139 *
140 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
141 */
142int
143xmlXPathIsInf(double val) {
144 return(trio_isinf(val));
145}
146
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000147/**
148 * xmlXPathGetSign:
149 * @val: a double value
150 *
151 * Provides a portable function to detect the sign of a double
152 * Modified from trio code
153 * http://sourceforge.net/projects/ctrio/
154 *
155 * Returns 1 if the value is Negative, 0 if positive
156 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000157static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000158xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000159 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000160}
161
162
Owen Taylor3473f882001-02-23 17:55:21 +0000163/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000164 * *
165 * Parser Types *
166 * *
167 ************************************************************************/
168
169/*
170 * Types are private:
171 */
172
173typedef enum {
174 XPATH_OP_END=0,
175 XPATH_OP_AND,
176 XPATH_OP_OR,
177 XPATH_OP_EQUAL,
178 XPATH_OP_CMP,
179 XPATH_OP_PLUS,
180 XPATH_OP_MULT,
181 XPATH_OP_UNION,
182 XPATH_OP_ROOT,
183 XPATH_OP_NODE,
184 XPATH_OP_RESET,
185 XPATH_OP_COLLECT,
186 XPATH_OP_VALUE,
187 XPATH_OP_VARIABLE,
188 XPATH_OP_FUNCTION,
189 XPATH_OP_ARG,
190 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000191 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000192 XPATH_OP_SORT
193#ifdef LIBXML_XPTR_ENABLED
194 ,XPATH_OP_RANGETO
195#endif
196} xmlXPathOp;
197
198typedef enum {
199 AXIS_ANCESTOR = 1,
200 AXIS_ANCESTOR_OR_SELF,
201 AXIS_ATTRIBUTE,
202 AXIS_CHILD,
203 AXIS_DESCENDANT,
204 AXIS_DESCENDANT_OR_SELF,
205 AXIS_FOLLOWING,
206 AXIS_FOLLOWING_SIBLING,
207 AXIS_NAMESPACE,
208 AXIS_PARENT,
209 AXIS_PRECEDING,
210 AXIS_PRECEDING_SIBLING,
211 AXIS_SELF
212} xmlXPathAxisVal;
213
214typedef enum {
215 NODE_TEST_NONE = 0,
216 NODE_TEST_TYPE = 1,
217 NODE_TEST_PI = 2,
218 NODE_TEST_ALL = 3,
219 NODE_TEST_NS = 4,
220 NODE_TEST_NAME = 5
221} xmlXPathTestVal;
222
223typedef enum {
224 NODE_TYPE_NODE = 0,
225 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
226 NODE_TYPE_TEXT = XML_TEXT_NODE,
227 NODE_TYPE_PI = XML_PI_NODE
228} xmlXPathTypeVal;
229
230
231typedef struct _xmlXPathStepOp xmlXPathStepOp;
232typedef xmlXPathStepOp *xmlXPathStepOpPtr;
233struct _xmlXPathStepOp {
234 xmlXPathOp op;
235 int ch1;
236 int ch2;
237 int value;
238 int value2;
239 int value3;
240 void *value4;
241 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000242 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000243 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000244};
245
246struct _xmlXPathCompExpr {
247 int nbStep;
248 int maxStep;
249 xmlXPathStepOp *steps; /* ops for computation */
250 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000251 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000252#ifdef DEBUG_EVAL_COUNTS
253 int nb;
254 xmlChar *string;
255#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000256};
257
258/************************************************************************
259 * *
260 * Parser Type functions *
261 * *
262 ************************************************************************/
263
264/**
265 * xmlXPathNewCompExpr:
266 *
267 * Create a new Xpath component
268 *
269 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
270 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000271static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000272xmlXPathNewCompExpr(void) {
273 xmlXPathCompExprPtr cur;
274
275 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
276 if (cur == NULL) {
277 xmlGenericError(xmlGenericErrorContext,
278 "xmlXPathNewCompExpr : malloc failed\n");
279 return(NULL);
280 }
281 memset(cur, 0, sizeof(xmlXPathCompExpr));
282 cur->maxStep = 10;
283 cur->nbStep = 0;
284 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
285 sizeof(xmlXPathStepOp));
286 if (cur->steps == NULL) {
287 xmlGenericError(xmlGenericErrorContext,
288 "xmlXPathNewCompExpr : malloc failed\n");
289 xmlFree(cur);
290 return(NULL);
291 }
292 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
293 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000294#ifdef DEBUG_EVAL_COUNTS
295 cur->nb = 0;
296#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000297 return(cur);
298}
299
300/**
301 * xmlXPathFreeCompExpr:
302 * @comp: an XPATH comp
303 *
304 * Free up the memory allocated by @comp
305 */
306void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000307xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
308{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000309 xmlXPathStepOpPtr op;
310 int i;
311
312 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000313 return;
314 for (i = 0; i < comp->nbStep; i++) {
315 op = &comp->steps[i];
316 if (op->value4 != NULL) {
317 if (op->op == XPATH_OP_VALUE)
318 xmlXPathFreeObject(op->value4);
319 else
320 xmlFree(op->value4);
321 }
322 if (op->value5 != NULL)
323 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000324 }
325 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000326 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000327 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328#ifdef DEBUG_EVAL_COUNTS
329 if (comp->string != NULL) {
330 xmlFree(comp->string);
331 }
332#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000333 if (comp->expr != NULL) {
334 xmlFree(comp->expr);
335 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000336
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000337 xmlFree(comp);
338}
339
340/**
341 * xmlXPathCompExprAdd:
342 * @comp: the compiled expression
343 * @ch1: first child index
344 * @ch2: second child index
345 * @op: an op
346 * @value: the first int value
347 * @value2: the second int value
348 * @value3: the third int value
349 * @value4: the first string value
350 * @value5: the second string value
351 *
352 * Add an step to an XPath Compiled Expression
353 *
354 * Returns -1 in case of failure, the index otherwise
355 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000356static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000357xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
358 xmlXPathOp op, int value,
359 int value2, int value3, void *value4, void *value5) {
360 if (comp->nbStep >= comp->maxStep) {
361 xmlXPathStepOp *real;
362
363 comp->maxStep *= 2;
364 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
365 comp->maxStep * sizeof(xmlXPathStepOp));
366 if (real == NULL) {
367 comp->maxStep /= 2;
368 xmlGenericError(xmlGenericErrorContext,
369 "xmlXPathCompExprAdd : realloc failed\n");
370 return(-1);
371 }
372 comp->steps = real;
373 }
374 comp->last = comp->nbStep;
375 comp->steps[comp->nbStep].ch1 = ch1;
376 comp->steps[comp->nbStep].ch2 = ch2;
377 comp->steps[comp->nbStep].op = op;
378 comp->steps[comp->nbStep].value = value;
379 comp->steps[comp->nbStep].value2 = value2;
380 comp->steps[comp->nbStep].value3 = value3;
381 comp->steps[comp->nbStep].value4 = value4;
382 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000383 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000384 return(comp->nbStep++);
385}
386
Daniel Veillardf06307e2001-07-03 10:35:50 +0000387/**
388 * xmlXPathCompSwap:
389 * @comp: the compiled expression
390 * @op: operation index
391 *
392 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000393 */
394static void
395xmlXPathCompSwap(xmlXPathStepOpPtr op) {
396 int tmp;
397
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000398#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000399 /*
400 * Since this manipulates possibly shared variables, this is
401 * disable if one detects that the library is used in a multithreaded
402 * application
403 */
404 if (xmlXPathDisableOptimizer)
405 return;
406#endif
407
Daniel Veillardf06307e2001-07-03 10:35:50 +0000408 tmp = op->ch1;
409 op->ch1 = op->ch2;
410 op->ch2 = tmp;
411}
412
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000413#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
414 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
415 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000416#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
417 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
418 (op), (val), (val2), (val3), (val4), (val5))
419
420#define PUSH_LEAVE_EXPR(op, val, val2) \
421xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
422
423#define PUSH_UNARY_EXPR(op, ch, val, val2) \
424xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
425
426#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
427xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
428
429/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000430 * *
431 * Debugging related functions *
432 * *
433 ************************************************************************/
434
435#define TODO \
436 xmlGenericError(xmlGenericErrorContext, \
437 "Unimplemented block at %s:%d\n", \
438 __FILE__, __LINE__);
439
440#define STRANGE \
441 xmlGenericError(xmlGenericErrorContext, \
442 "Internal error at %s:%d\n", \
443 __FILE__, __LINE__);
444
445#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000446static void
447xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000448 int i;
449 char shift[100];
450
451 for (i = 0;((i < depth) && (i < 25));i++)
452 shift[2 * i] = shift[2 * i + 1] = ' ';
453 shift[2 * i] = shift[2 * i + 1] = 0;
454 if (cur == NULL) {
455 fprintf(output, shift);
456 fprintf(output, "Node is NULL !\n");
457 return;
458
459 }
460
461 if ((cur->type == XML_DOCUMENT_NODE) ||
462 (cur->type == XML_HTML_DOCUMENT_NODE)) {
463 fprintf(output, shift);
464 fprintf(output, " /\n");
465 } else if (cur->type == XML_ATTRIBUTE_NODE)
466 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
467 else
468 xmlDebugDumpOneNode(output, cur, depth);
469}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000470static void
471xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000472 xmlNodePtr tmp;
473 int i;
474 char shift[100];
475
476 for (i = 0;((i < depth) && (i < 25));i++)
477 shift[2 * i] = shift[2 * i + 1] = ' ';
478 shift[2 * i] = shift[2 * i + 1] = 0;
479 if (cur == NULL) {
480 fprintf(output, shift);
481 fprintf(output, "Node is NULL !\n");
482 return;
483
484 }
485
486 while (cur != NULL) {
487 tmp = cur;
488 cur = cur->next;
489 xmlDebugDumpOneNode(output, tmp, depth);
490 }
491}
Owen Taylor3473f882001-02-23 17:55:21 +0000492
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000493static void
494xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000495 int i;
496 char shift[100];
497
498 for (i = 0;((i < depth) && (i < 25));i++)
499 shift[2 * i] = shift[2 * i + 1] = ' ';
500 shift[2 * i] = shift[2 * i + 1] = 0;
501
502 if (cur == NULL) {
503 fprintf(output, shift);
504 fprintf(output, "NodeSet is NULL !\n");
505 return;
506
507 }
508
Daniel Veillard911f49a2001-04-07 15:39:35 +0000509 if (cur != NULL) {
510 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
511 for (i = 0;i < cur->nodeNr;i++) {
512 fprintf(output, shift);
513 fprintf(output, "%d", i + 1);
514 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
515 }
Owen Taylor3473f882001-02-23 17:55:21 +0000516 }
517}
518
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000519static void
520xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000521 int i;
522 char shift[100];
523
524 for (i = 0;((i < depth) && (i < 25));i++)
525 shift[2 * i] = shift[2 * i + 1] = ' ';
526 shift[2 * i] = shift[2 * i + 1] = 0;
527
528 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
529 fprintf(output, shift);
530 fprintf(output, "Value Tree is NULL !\n");
531 return;
532
533 }
534
535 fprintf(output, shift);
536 fprintf(output, "%d", i + 1);
537 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
538}
Owen Taylor3473f882001-02-23 17:55:21 +0000539#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000540static void
541xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000542 int i;
543 char shift[100];
544
545 for (i = 0;((i < depth) && (i < 25));i++)
546 shift[2 * i] = shift[2 * i + 1] = ' ';
547 shift[2 * i] = shift[2 * i + 1] = 0;
548
549 if (cur == NULL) {
550 fprintf(output, shift);
551 fprintf(output, "LocationSet is NULL !\n");
552 return;
553
554 }
555
556 for (i = 0;i < cur->locNr;i++) {
557 fprintf(output, shift);
558 fprintf(output, "%d : ", i + 1);
559 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
560 }
561}
Daniel Veillard017b1082001-06-21 11:20:21 +0000562#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000563
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000564/**
565 * xmlXPathDebugDumpObject:
566 * @output: the FILE * to dump the output
567 * @cur: the object to inspect
568 * @depth: indentation level
569 *
570 * Dump the content of the object for debugging purposes
571 */
572void
573xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000574 int i;
575 char shift[100];
576
577 for (i = 0;((i < depth) && (i < 25));i++)
578 shift[2 * i] = shift[2 * i + 1] = ' ';
579 shift[2 * i] = shift[2 * i + 1] = 0;
580
581 fprintf(output, shift);
582
583 if (cur == NULL) {
584 fprintf(output, "Object is empty (NULL)\n");
585 return;
586 }
587 switch(cur->type) {
588 case XPATH_UNDEFINED:
589 fprintf(output, "Object is uninitialized\n");
590 break;
591 case XPATH_NODESET:
592 fprintf(output, "Object is a Node Set :\n");
593 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
594 break;
595 case XPATH_XSLT_TREE:
596 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000597 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000598 break;
599 case XPATH_BOOLEAN:
600 fprintf(output, "Object is a Boolean : ");
601 if (cur->boolval) fprintf(output, "true\n");
602 else fprintf(output, "false\n");
603 break;
604 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000605 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000606 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000607 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000608 break;
609 case -1:
610 fprintf(output, "Object is a number : -Infinity\n");
611 break;
612 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000613 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000614 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000615 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
616 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000617 } else {
618 fprintf(output, "Object is a number : %0g\n", cur->floatval);
619 }
620 }
Owen Taylor3473f882001-02-23 17:55:21 +0000621 break;
622 case XPATH_STRING:
623 fprintf(output, "Object is a string : ");
624 xmlDebugDumpString(output, cur->stringval);
625 fprintf(output, "\n");
626 break;
627 case XPATH_POINT:
628 fprintf(output, "Object is a point : index %d in node", cur->index);
629 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
630 fprintf(output, "\n");
631 break;
632 case XPATH_RANGE:
633 if ((cur->user2 == NULL) ||
634 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
635 fprintf(output, "Object is a collapsed range :\n");
636 fprintf(output, shift);
637 if (cur->index >= 0)
638 fprintf(output, "index %d in ", cur->index);
639 fprintf(output, "node\n");
640 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
641 depth + 1);
642 } else {
643 fprintf(output, "Object is a range :\n");
644 fprintf(output, shift);
645 fprintf(output, "From ");
646 if (cur->index >= 0)
647 fprintf(output, "index %d in ", cur->index);
648 fprintf(output, "node\n");
649 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
650 depth + 1);
651 fprintf(output, shift);
652 fprintf(output, "To ");
653 if (cur->index2 >= 0)
654 fprintf(output, "index %d in ", cur->index2);
655 fprintf(output, "node\n");
656 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
657 depth + 1);
658 fprintf(output, "\n");
659 }
660 break;
661 case XPATH_LOCATIONSET:
662#if defined(LIBXML_XPTR_ENABLED)
663 fprintf(output, "Object is a Location Set:\n");
664 xmlXPathDebugDumpLocationSet(output,
665 (xmlLocationSetPtr) cur->user, depth);
666#endif
667 break;
668 case XPATH_USERS:
669 fprintf(output, "Object is user defined\n");
670 break;
671 }
672}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000673
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000674static void
675xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000676 xmlXPathStepOpPtr op, int depth) {
677 int i;
678 char shift[100];
679
680 for (i = 0;((i < depth) && (i < 25));i++)
681 shift[2 * i] = shift[2 * i + 1] = ' ';
682 shift[2 * i] = shift[2 * i + 1] = 0;
683
684 fprintf(output, shift);
685 if (op == NULL) {
686 fprintf(output, "Step is NULL\n");
687 return;
688 }
689 switch (op->op) {
690 case XPATH_OP_END:
691 fprintf(output, "END"); break;
692 case XPATH_OP_AND:
693 fprintf(output, "AND"); break;
694 case XPATH_OP_OR:
695 fprintf(output, "OR"); break;
696 case XPATH_OP_EQUAL:
697 if (op->value)
698 fprintf(output, "EQUAL =");
699 else
700 fprintf(output, "EQUAL !=");
701 break;
702 case XPATH_OP_CMP:
703 if (op->value)
704 fprintf(output, "CMP <");
705 else
706 fprintf(output, "CMP >");
707 if (!op->value2)
708 fprintf(output, "=");
709 break;
710 case XPATH_OP_PLUS:
711 if (op->value == 0)
712 fprintf(output, "PLUS -");
713 else if (op->value == 1)
714 fprintf(output, "PLUS +");
715 else if (op->value == 2)
716 fprintf(output, "PLUS unary -");
717 else if (op->value == 3)
718 fprintf(output, "PLUS unary - -");
719 break;
720 case XPATH_OP_MULT:
721 if (op->value == 0)
722 fprintf(output, "MULT *");
723 else if (op->value == 1)
724 fprintf(output, "MULT div");
725 else
726 fprintf(output, "MULT mod");
727 break;
728 case XPATH_OP_UNION:
729 fprintf(output, "UNION"); break;
730 case XPATH_OP_ROOT:
731 fprintf(output, "ROOT"); break;
732 case XPATH_OP_NODE:
733 fprintf(output, "NODE"); break;
734 case XPATH_OP_RESET:
735 fprintf(output, "RESET"); break;
736 case XPATH_OP_SORT:
737 fprintf(output, "SORT"); break;
738 case XPATH_OP_COLLECT: {
739 xmlXPathAxisVal axis = op->value;
740 xmlXPathTestVal test = op->value2;
741 xmlXPathTypeVal type = op->value3;
742 const xmlChar *prefix = op->value4;
743 const xmlChar *name = op->value5;
744
745 fprintf(output, "COLLECT ");
746 switch (axis) {
747 case AXIS_ANCESTOR:
748 fprintf(output, " 'ancestors' "); break;
749 case AXIS_ANCESTOR_OR_SELF:
750 fprintf(output, " 'ancestors-or-self' "); break;
751 case AXIS_ATTRIBUTE:
752 fprintf(output, " 'attributes' "); break;
753 case AXIS_CHILD:
754 fprintf(output, " 'child' "); break;
755 case AXIS_DESCENDANT:
756 fprintf(output, " 'descendant' "); break;
757 case AXIS_DESCENDANT_OR_SELF:
758 fprintf(output, " 'descendant-or-self' "); break;
759 case AXIS_FOLLOWING:
760 fprintf(output, " 'following' "); break;
761 case AXIS_FOLLOWING_SIBLING:
762 fprintf(output, " 'following-siblings' "); break;
763 case AXIS_NAMESPACE:
764 fprintf(output, " 'namespace' "); break;
765 case AXIS_PARENT:
766 fprintf(output, " 'parent' "); break;
767 case AXIS_PRECEDING:
768 fprintf(output, " 'preceding' "); break;
769 case AXIS_PRECEDING_SIBLING:
770 fprintf(output, " 'preceding-sibling' "); break;
771 case AXIS_SELF:
772 fprintf(output, " 'self' "); break;
773 }
774 switch (test) {
775 case NODE_TEST_NONE:
776 fprintf(output, "'none' "); break;
777 case NODE_TEST_TYPE:
778 fprintf(output, "'type' "); break;
779 case NODE_TEST_PI:
780 fprintf(output, "'PI' "); break;
781 case NODE_TEST_ALL:
782 fprintf(output, "'all' "); break;
783 case NODE_TEST_NS:
784 fprintf(output, "'namespace' "); break;
785 case NODE_TEST_NAME:
786 fprintf(output, "'name' "); break;
787 }
788 switch (type) {
789 case NODE_TYPE_NODE:
790 fprintf(output, "'node' "); break;
791 case NODE_TYPE_COMMENT:
792 fprintf(output, "'comment' "); break;
793 case NODE_TYPE_TEXT:
794 fprintf(output, "'text' "); break;
795 case NODE_TYPE_PI:
796 fprintf(output, "'PI' "); break;
797 }
798 if (prefix != NULL)
799 fprintf(output, "%s:", prefix);
800 if (name != NULL)
801 fprintf(output, "%s", name);
802 break;
803
804 }
805 case XPATH_OP_VALUE: {
806 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
807
808 fprintf(output, "ELEM ");
809 xmlXPathDebugDumpObject(output, object, 0);
810 goto finish;
811 }
812 case XPATH_OP_VARIABLE: {
813 const xmlChar *prefix = op->value5;
814 const xmlChar *name = op->value4;
815
816 if (prefix != NULL)
817 fprintf(output, "VARIABLE %s:%s", prefix, name);
818 else
819 fprintf(output, "VARIABLE %s", name);
820 break;
821 }
822 case XPATH_OP_FUNCTION: {
823 int nbargs = op->value;
824 const xmlChar *prefix = op->value5;
825 const xmlChar *name = op->value4;
826
827 if (prefix != NULL)
828 fprintf(output, "FUNCTION %s:%s(%d args)",
829 prefix, name, nbargs);
830 else
831 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
832 break;
833 }
834 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
835 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000836 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000837#ifdef LIBXML_XPTR_ENABLED
838 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
839#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000840 default:
841 fprintf(output, "UNKNOWN %d\n", op->op); return;
842 }
843 fprintf(output, "\n");
844finish:
845 if (op->ch1 >= 0)
846 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
847 if (op->ch2 >= 0)
848 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
849}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000850
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000851/**
852 * xmlXPathDebugDumpCompExpr:
853 * @output: the FILE * for the output
854 * @comp: the precompiled XPath expression
855 * @depth: the indentation level.
856 *
857 * Dumps the tree of the compiled XPath expression.
858 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000859void
860xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
861 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000862 int i;
863 char shift[100];
864
865 for (i = 0;((i < depth) && (i < 25));i++)
866 shift[2 * i] = shift[2 * i + 1] = ' ';
867 shift[2 * i] = shift[2 * i + 1] = 0;
868
869 fprintf(output, shift);
870
871 if (comp == NULL) {
872 fprintf(output, "Compiled Expression is NULL\n");
873 return;
874 }
875 fprintf(output, "Compiled Expression : %d elements\n",
876 comp->nbStep);
877 i = comp->last;
878 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
879}
Daniel Veillard017b1082001-06-21 11:20:21 +0000880#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000881
882/************************************************************************
883 * *
884 * Parser stacks related functions and macros *
885 * *
886 ************************************************************************/
887
888/*
889 * Generic function for accessing stacks in the Parser Context
890 */
891
892#define PUSH_AND_POP(type, name) \
893extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
894 if (ctxt->name##Nr >= ctxt->name##Max) { \
895 ctxt->name##Max *= 2; \
896 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
897 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
898 if (ctxt->name##Tab == NULL) { \
899 xmlGenericError(xmlGenericErrorContext, \
900 "realloc failed !\n"); \
901 return(0); \
902 } \
903 } \
904 ctxt->name##Tab[ctxt->name##Nr] = value; \
905 ctxt->name = value; \
906 return(ctxt->name##Nr++); \
907} \
908extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
909 type ret; \
910 if (ctxt->name##Nr <= 0) return(0); \
911 ctxt->name##Nr--; \
912 if (ctxt->name##Nr > 0) \
913 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
914 else \
915 ctxt->name = NULL; \
916 ret = ctxt->name##Tab[ctxt->name##Nr]; \
917 ctxt->name##Tab[ctxt->name##Nr] = 0; \
918 return(ret); \
919} \
920
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000921/**
922 * valuePop:
923 * @ctxt: an XPath evaluation context
924 *
925 * Pops the top XPath object from the value stack
926 *
927 * Returns the XPath object just removed
928 */
929/**
930 * valuePush:
931 * @ctxt: an XPath evaluation context
932 * @value: the XPath object
933 *
934 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000935 *
936 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000937 */
Owen Taylor3473f882001-02-23 17:55:21 +0000938PUSH_AND_POP(xmlXPathObjectPtr, value)
939
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000940/**
941 * xmlXPathPopBoolean:
942 * @ctxt: an XPath parser context
943 *
944 * Pops a boolean from the stack, handling conversion if needed.
945 * Check error with #xmlXPathCheckError.
946 *
947 * Returns the boolean
948 */
949int
950xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
951 xmlXPathObjectPtr obj;
952 int ret;
953
954 obj = valuePop(ctxt);
955 if (obj == NULL) {
956 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
957 return(0);
958 }
959 ret = xmlXPathCastToBoolean(obj);
960 xmlXPathFreeObject(obj);
961 return(ret);
962}
963
964/**
965 * xmlXPathPopNumber:
966 * @ctxt: an XPath parser context
967 *
968 * Pops a number from the stack, handling conversion if needed.
969 * Check error with #xmlXPathCheckError.
970 *
971 * Returns the number
972 */
973double
974xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
975 xmlXPathObjectPtr obj;
976 double ret;
977
978 obj = valuePop(ctxt);
979 if (obj == NULL) {
980 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
981 return(0);
982 }
983 ret = xmlXPathCastToNumber(obj);
984 xmlXPathFreeObject(obj);
985 return(ret);
986}
987
988/**
989 * xmlXPathPopString:
990 * @ctxt: an XPath parser context
991 *
992 * Pops a string from the stack, handling conversion if needed.
993 * Check error with #xmlXPathCheckError.
994 *
995 * Returns the string
996 */
997xmlChar *
998xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
999 xmlXPathObjectPtr obj;
1000 xmlChar * ret;
1001
1002 obj = valuePop(ctxt);
1003 if (obj == NULL) {
1004 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1005 return(NULL);
1006 }
1007 ret = xmlXPathCastToString(obj);
1008 /* TODO: needs refactoring somewhere else */
1009 if (obj->stringval == ret)
1010 obj->stringval = NULL;
1011 xmlXPathFreeObject(obj);
1012 return(ret);
1013}
1014
1015/**
1016 * xmlXPathPopNodeSet:
1017 * @ctxt: an XPath parser context
1018 *
1019 * Pops a node-set from the stack, handling conversion if needed.
1020 * Check error with #xmlXPathCheckError.
1021 *
1022 * Returns the node-set
1023 */
1024xmlNodeSetPtr
1025xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1026 xmlXPathObjectPtr obj;
1027 xmlNodeSetPtr ret;
1028
1029 if (ctxt->value == NULL) {
1030 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1031 return(NULL);
1032 }
1033 if (!xmlXPathStackIsNodeSet(ctxt)) {
1034 xmlXPathSetTypeError(ctxt);
1035 return(NULL);
1036 }
1037 obj = valuePop(ctxt);
1038 ret = obj->nodesetval;
1039 xmlXPathFreeNodeSetList(obj);
1040 return(ret);
1041}
1042
1043/**
1044 * xmlXPathPopExternal:
1045 * @ctxt: an XPath parser context
1046 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001047 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001048 * Check error with #xmlXPathCheckError.
1049 *
1050 * Returns the object
1051 */
1052void *
1053xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1054 xmlXPathObjectPtr obj;
1055 void * ret;
1056
1057 if (ctxt->value == NULL) {
1058 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1059 return(NULL);
1060 }
1061 if (ctxt->value->type != XPATH_USERS) {
1062 xmlXPathSetTypeError(ctxt);
1063 return(NULL);
1064 }
1065 obj = valuePop(ctxt);
1066 ret = obj->user;
1067 xmlXPathFreeObject(obj);
1068 return(ret);
1069}
1070
Owen Taylor3473f882001-02-23 17:55:21 +00001071/*
1072 * Macros for accessing the content. Those should be used only by the parser,
1073 * and not exported.
1074 *
1075 * Dirty macros, i.e. one need to make assumption on the context to use them
1076 *
1077 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1078 * CUR returns the current xmlChar value, i.e. a 8 bit value
1079 * in ISO-Latin or UTF-8.
1080 * This should be used internally by the parser
1081 * only to compare to ASCII values otherwise it would break when
1082 * running with UTF-8 encoding.
1083 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1084 * to compare on ASCII based substring.
1085 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1086 * strings within the parser.
1087 * CURRENT Returns the current char value, with the full decoding of
1088 * UTF-8 if we are using this mode. It returns an int.
1089 * NEXT Skip to the next character, this does the proper decoding
1090 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1091 * It returns the pointer to the current xmlChar.
1092 */
1093
1094#define CUR (*ctxt->cur)
1095#define SKIP(val) ctxt->cur += (val)
1096#define NXT(val) ctxt->cur[(val)]
1097#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001098#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1099
1100#define COPY_BUF(l,b,i,v) \
1101 if (l == 1) b[i++] = (xmlChar) v; \
1102 else i += xmlCopyChar(l,&b[i],v)
1103
1104#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001105
1106#define SKIP_BLANKS \
1107 while (IS_BLANK(*(ctxt->cur))) NEXT
1108
1109#define CURRENT (*ctxt->cur)
1110#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1111
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001112
1113#ifndef DBL_DIG
1114#define DBL_DIG 16
1115#endif
1116#ifndef DBL_EPSILON
1117#define DBL_EPSILON 1E-9
1118#endif
1119
1120#define UPPER_DOUBLE 1E9
1121#define LOWER_DOUBLE 1E-5
1122
1123#define INTEGER_DIGITS DBL_DIG
1124#define FRACTION_DIGITS (DBL_DIG + 1)
1125#define EXPONENT_DIGITS (3 + 2)
1126
1127/**
1128 * xmlXPathFormatNumber:
1129 * @number: number to format
1130 * @buffer: output buffer
1131 * @buffersize: size of output buffer
1132 *
1133 * Convert the number into a string representation.
1134 */
1135static void
1136xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1137{
Daniel Veillardcda96922001-08-21 10:56:31 +00001138 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001139 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001140 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001141 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001142 break;
1143 case -1:
1144 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001145 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001146 break;
1147 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001148 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001149 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001150 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001151 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001152 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001153 } else if (number == ((int) number)) {
1154 char work[30];
1155 char *ptr, *cur;
1156 int res, value = (int) number;
1157
1158 ptr = &buffer[0];
1159 if (value < 0) {
1160 *ptr++ = '-';
1161 value = -value;
1162 }
1163 if (value == 0) {
1164 *ptr++ = '0';
1165 } else {
1166 cur = &work[0];
1167 while (value != 0) {
1168 res = value % 10;
1169 value = value / 10;
1170 *cur++ = '0' + res;
1171 }
1172 cur--;
1173 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1174 *ptr++ = *cur--;
1175 }
1176 }
1177 if (ptr - buffer < buffersize) {
1178 *ptr = 0;
1179 } else if (buffersize > 0) {
1180 ptr--;
1181 *ptr = 0;
1182 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001183 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001184 /* 3 is sign, decimal point, and terminating zero */
1185 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1186 int integer_place, fraction_place;
1187 char *ptr;
1188 char *after_fraction;
1189 double absolute_value;
1190 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001191
Bjorn Reese70a9da52001-04-21 16:57:29 +00001192 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001193
Bjorn Reese70a9da52001-04-21 16:57:29 +00001194 /*
1195 * First choose format - scientific or regular floating point.
1196 * In either case, result is in work, and after_fraction points
1197 * just past the fractional part.
1198 */
1199 if ( ((absolute_value > UPPER_DOUBLE) ||
1200 (absolute_value < LOWER_DOUBLE)) &&
1201 (absolute_value != 0.0) ) {
1202 /* Use scientific notation */
1203 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1204 fraction_place = DBL_DIG - 1;
1205 snprintf(work, sizeof(work),"%*.*e",
1206 integer_place, fraction_place, number);
1207 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001208 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001209 else {
1210 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001211 if (absolute_value > 0.0)
1212 integer_place = 1 + (int)log10(absolute_value);
1213 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001214 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001215 fraction_place = (integer_place > 0)
1216 ? DBL_DIG - integer_place
1217 : DBL_DIG;
1218 size = snprintf(work, sizeof(work), "%0.*f",
1219 fraction_place, number);
1220 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001221 }
1222
Bjorn Reese70a9da52001-04-21 16:57:29 +00001223 /* Remove fractional trailing zeroes */
1224 ptr = after_fraction;
1225 while (*(--ptr) == '0')
1226 ;
1227 if (*ptr != '.')
1228 ptr++;
1229 strcpy(ptr, after_fraction);
1230
1231 /* Finally copy result back to caller */
1232 size = strlen(work) + 1;
1233 if (size > buffersize) {
1234 work[buffersize - 1] = 0;
1235 size = buffersize;
1236 }
1237 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001238 }
1239 break;
1240 }
1241}
1242
Owen Taylor3473f882001-02-23 17:55:21 +00001243/************************************************************************
1244 * *
1245 * Error handling routines *
1246 * *
1247 ************************************************************************/
1248
1249
Daniel Veillardb44025c2001-10-11 22:55:55 +00001250static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001251 "Ok",
1252 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001253 "Unfinished literal",
1254 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001255 "Expected $ for variable reference",
1256 "Undefined variable",
1257 "Invalid predicate",
1258 "Invalid expression",
1259 "Missing closing curly brace",
1260 "Unregistered function",
1261 "Invalid operand",
1262 "Invalid type",
1263 "Invalid number of arguments",
1264 "Invalid context size",
1265 "Invalid context position",
1266 "Memory allocation error",
1267 "Syntax error",
1268 "Resource error",
1269 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001270 "Undefined namespace prefix",
1271 "Encoding error",
1272 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001273};
1274
1275/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001276 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001277 * @ctxt: the XPath Parser context
1278 * @file: the file name
1279 * @line: the line number
1280 * @no: the error number
1281 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001282 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001283 */
1284void
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001285xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1286 int line ATTRIBUTE_UNUSED, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001287 int n;
1288 const xmlChar *cur;
1289 const xmlChar *base;
1290
Owen Taylor3473f882001-02-23 17:55:21 +00001291 cur = ctxt->cur;
1292 base = ctxt->base;
Daniel Veillard118aed72002-09-24 14:13:13 +00001293 if ((cur == NULL) || (base == NULL)) {
1294 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1295 xmlGenericError(xmlGenericErrorContext,
1296 "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1297 ctxt->comp->expr);
1298 } else {
1299 xmlGenericError(xmlGenericErrorContext,
1300 "XPath error %s\n", xmlXPathErrorMessages[no]);
1301 }
1302
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001303 return;
Daniel Veillard118aed72002-09-24 14:13:13 +00001304 }
1305 xmlGenericError(xmlGenericErrorContext,
1306 "XPath error %s\n", xmlXPathErrorMessages[no]);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001307
Owen Taylor3473f882001-02-23 17:55:21 +00001308 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1309 cur--;
1310 }
1311 n = 0;
1312 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1313 cur--;
1314 if ((*cur == '\n') || (*cur == '\r')) cur++;
1315 base = cur;
1316 n = 0;
1317 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1318 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1319 n++;
1320 }
1321 xmlGenericError(xmlGenericErrorContext, "\n");
1322 cur = ctxt->cur;
1323 while ((*cur == '\n') || (*cur == '\r'))
1324 cur--;
1325 n = 0;
1326 while ((cur != base) && (n++ < 80)) {
1327 xmlGenericError(xmlGenericErrorContext, " ");
1328 base++;
1329 }
1330 xmlGenericError(xmlGenericErrorContext,"^\n");
1331}
1332
1333
1334/************************************************************************
1335 * *
1336 * Routines to handle NodeSets *
1337 * *
1338 ************************************************************************/
1339
1340/**
1341 * xmlXPathCmpNodes:
1342 * @node1: the first node
1343 * @node2: the second node
1344 *
1345 * Compare two nodes w.r.t document order
1346 *
1347 * Returns -2 in case of error 1 if first point < second point, 0 if
1348 * that's the same node, -1 otherwise
1349 */
1350int
1351xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1352 int depth1, depth2;
1353 xmlNodePtr cur, root;
1354
1355 if ((node1 == NULL) || (node2 == NULL))
1356 return(-2);
1357 /*
1358 * a couple of optimizations which will avoid computations in most cases
1359 */
1360 if (node1 == node2)
1361 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001362 if ((node1->type == XML_NAMESPACE_DECL) ||
1363 (node2->type == XML_NAMESPACE_DECL))
1364 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001365 if (node1 == node2->prev)
1366 return(1);
1367 if (node1 == node2->next)
1368 return(-1);
1369
1370 /*
1371 * compute depth to root
1372 */
1373 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1374 if (cur == node1)
1375 return(1);
1376 depth2++;
1377 }
1378 root = cur;
1379 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1380 if (cur == node2)
1381 return(-1);
1382 depth1++;
1383 }
1384 /*
1385 * Distinct document (or distinct entities :-( ) case.
1386 */
1387 if (root != cur) {
1388 return(-2);
1389 }
1390 /*
1391 * get the nearest common ancestor.
1392 */
1393 while (depth1 > depth2) {
1394 depth1--;
1395 node1 = node1->parent;
1396 }
1397 while (depth2 > depth1) {
1398 depth2--;
1399 node2 = node2->parent;
1400 }
1401 while (node1->parent != node2->parent) {
1402 node1 = node1->parent;
1403 node2 = node2->parent;
1404 /* should not happen but just in case ... */
1405 if ((node1 == NULL) || (node2 == NULL))
1406 return(-2);
1407 }
1408 /*
1409 * Find who's first.
1410 */
1411 if (node1 == node2->next)
1412 return(-1);
1413 for (cur = node1->next;cur != NULL;cur = cur->next)
1414 if (cur == node2)
1415 return(1);
1416 return(-1); /* assume there is no sibling list corruption */
1417}
1418
1419/**
1420 * xmlXPathNodeSetSort:
1421 * @set: the node set
1422 *
1423 * Sort the node set in document order
1424 */
1425void
1426xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001427 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001428 xmlNodePtr tmp;
1429
1430 if (set == NULL)
1431 return;
1432
1433 /* Use Shell's sort to sort the node-set */
1434 len = set->nodeNr;
1435 for (incr = len / 2; incr > 0; incr /= 2) {
1436 for (i = incr; i < len; i++) {
1437 j = i - incr;
1438 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001439 if (xmlXPathCmpNodes(set->nodeTab[j],
1440 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001441 tmp = set->nodeTab[j];
1442 set->nodeTab[j] = set->nodeTab[j + incr];
1443 set->nodeTab[j + incr] = tmp;
1444 j -= incr;
1445 } else
1446 break;
1447 }
1448 }
1449 }
1450}
1451
1452#define XML_NODESET_DEFAULT 10
1453/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001454 * xmlXPathNodeSetDupNs:
1455 * @node: the parent node of the namespace XPath node
1456 * @ns: the libxml namespace declaration node.
1457 *
1458 * Namespace node in libxml don't match the XPath semantic. In a node set
1459 * the namespace nodes are duplicated and the next pointer is set to the
1460 * parent node in the XPath semantic.
1461 *
1462 * Returns the newly created object.
1463 */
1464static xmlNodePtr
1465xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1466 xmlNsPtr cur;
1467
1468 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1469 return(NULL);
1470 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1471 return((xmlNodePtr) ns);
1472
1473 /*
1474 * Allocate a new Namespace and fill the fields.
1475 */
1476 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1477 if (cur == NULL) {
1478 xmlGenericError(xmlGenericErrorContext,
1479 "xmlXPathNodeSetDupNs : malloc failed\n");
1480 return(NULL);
1481 }
1482 memset(cur, 0, sizeof(xmlNs));
1483 cur->type = XML_NAMESPACE_DECL;
1484 if (ns->href != NULL)
1485 cur->href = xmlStrdup(ns->href);
1486 if (ns->prefix != NULL)
1487 cur->prefix = xmlStrdup(ns->prefix);
1488 cur->next = (xmlNsPtr) node;
1489 return((xmlNodePtr) cur);
1490}
1491
1492/**
1493 * xmlXPathNodeSetFreeNs:
1494 * @ns: the XPath namespace node found in a nodeset.
1495 *
1496 * Namespace node in libxml don't match the XPath semantic. In a node set
1497 * the namespace nodes are duplicated and the next pointer is set to the
1498 * parent node in the XPath semantic. Check if such a node need to be freed
1499 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001500void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001501xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1502 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1503 return;
1504
1505 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1506 if (ns->href != NULL)
1507 xmlFree((xmlChar *)ns->href);
1508 if (ns->prefix != NULL)
1509 xmlFree((xmlChar *)ns->prefix);
1510 xmlFree(ns);
1511 }
1512}
1513
1514/**
Owen Taylor3473f882001-02-23 17:55:21 +00001515 * xmlXPathNodeSetCreate:
1516 * @val: an initial xmlNodePtr, or NULL
1517 *
1518 * Create a new xmlNodeSetPtr of type double and of value @val
1519 *
1520 * Returns the newly created object.
1521 */
1522xmlNodeSetPtr
1523xmlXPathNodeSetCreate(xmlNodePtr val) {
1524 xmlNodeSetPtr ret;
1525
1526 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1527 if (ret == NULL) {
1528 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001529 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001530 return(NULL);
1531 }
1532 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1533 if (val != NULL) {
1534 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1535 sizeof(xmlNodePtr));
1536 if (ret->nodeTab == NULL) {
1537 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001538 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001539 return(NULL);
1540 }
1541 memset(ret->nodeTab, 0 ,
1542 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1543 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001544 if (val->type == XML_NAMESPACE_DECL) {
1545 xmlNsPtr ns = (xmlNsPtr) val;
1546
1547 ret->nodeTab[ret->nodeNr++] =
1548 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1549 } else
1550 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001551 }
1552 return(ret);
1553}
1554
1555/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001556 * xmlXPathNodeSetContains:
1557 * @cur: the node-set
1558 * @val: the node
1559 *
1560 * checks whether @cur contains @val
1561 *
1562 * Returns true (1) if @cur contains @val, false (0) otherwise
1563 */
1564int
1565xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1566 int i;
1567
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001568 if (val->type == XML_NAMESPACE_DECL) {
1569 for (i = 0; i < cur->nodeNr; i++) {
1570 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1571 xmlNsPtr ns1, ns2;
1572
1573 ns1 = (xmlNsPtr) val;
1574 ns2 = (xmlNsPtr) cur->nodeTab[i];
1575 if (ns1 == ns2)
1576 return(1);
1577 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1578 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1579 return(1);
1580 }
1581 }
1582 } else {
1583 for (i = 0; i < cur->nodeNr; i++) {
1584 if (cur->nodeTab[i] == val)
1585 return(1);
1586 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001587 }
1588 return(0);
1589}
1590
1591/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001592 * xmlXPathNodeSetAddNs:
1593 * @cur: the initial node set
1594 * @node: the hosting node
1595 * @ns: a the namespace node
1596 *
1597 * add a new namespace node to an existing NodeSet
1598 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001599void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001600xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1601 int i;
1602
1603 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1604 (node->type != XML_ELEMENT_NODE))
1605 return;
1606
1607 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1608 /*
1609 * check against doublons
1610 */
1611 for (i = 0;i < cur->nodeNr;i++) {
1612 if ((cur->nodeTab[i] != NULL) &&
1613 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001614 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001615 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1616 return;
1617 }
1618
1619 /*
1620 * grow the nodeTab if needed
1621 */
1622 if (cur->nodeMax == 0) {
1623 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1624 sizeof(xmlNodePtr));
1625 if (cur->nodeTab == NULL) {
1626 xmlGenericError(xmlGenericErrorContext,
1627 "xmlXPathNodeSetAdd: out of memory\n");
1628 return;
1629 }
1630 memset(cur->nodeTab, 0 ,
1631 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1632 cur->nodeMax = XML_NODESET_DEFAULT;
1633 } else if (cur->nodeNr == cur->nodeMax) {
1634 xmlNodePtr *temp;
1635
1636 cur->nodeMax *= 2;
1637 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1638 sizeof(xmlNodePtr));
1639 if (temp == NULL) {
1640 xmlGenericError(xmlGenericErrorContext,
1641 "xmlXPathNodeSetAdd: out of memory\n");
1642 return;
1643 }
1644 cur->nodeTab = temp;
1645 }
1646 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1647}
1648
1649/**
Owen Taylor3473f882001-02-23 17:55:21 +00001650 * xmlXPathNodeSetAdd:
1651 * @cur: the initial node set
1652 * @val: a new xmlNodePtr
1653 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001654 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001655 */
1656void
1657xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1658 int i;
1659
1660 if (val == NULL) return;
1661
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001662 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001663 /*
1664 * check against doublons
1665 */
1666 for (i = 0;i < cur->nodeNr;i++)
1667 if (cur->nodeTab[i] == val) return;
1668
1669 /*
1670 * grow the nodeTab if needed
1671 */
1672 if (cur->nodeMax == 0) {
1673 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1674 sizeof(xmlNodePtr));
1675 if (cur->nodeTab == NULL) {
1676 xmlGenericError(xmlGenericErrorContext,
1677 "xmlXPathNodeSetAdd: out of memory\n");
1678 return;
1679 }
1680 memset(cur->nodeTab, 0 ,
1681 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1682 cur->nodeMax = XML_NODESET_DEFAULT;
1683 } else if (cur->nodeNr == cur->nodeMax) {
1684 xmlNodePtr *temp;
1685
1686 cur->nodeMax *= 2;
1687 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1688 sizeof(xmlNodePtr));
1689 if (temp == NULL) {
1690 xmlGenericError(xmlGenericErrorContext,
1691 "xmlXPathNodeSetAdd: out of memory\n");
1692 return;
1693 }
1694 cur->nodeTab = temp;
1695 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001696 if (val->type == XML_NAMESPACE_DECL) {
1697 xmlNsPtr ns = (xmlNsPtr) val;
1698
1699 cur->nodeTab[cur->nodeNr++] =
1700 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1701 } else
1702 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001703}
1704
1705/**
1706 * xmlXPathNodeSetAddUnique:
1707 * @cur: the initial node set
1708 * @val: a new xmlNodePtr
1709 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001710 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001711 * when we are sure the node is not already in the set.
1712 */
1713void
1714xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1715 if (val == NULL) return;
1716
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001717 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001718 /*
1719 * grow the nodeTab if needed
1720 */
1721 if (cur->nodeMax == 0) {
1722 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1723 sizeof(xmlNodePtr));
1724 if (cur->nodeTab == NULL) {
1725 xmlGenericError(xmlGenericErrorContext,
1726 "xmlXPathNodeSetAddUnique: out of memory\n");
1727 return;
1728 }
1729 memset(cur->nodeTab, 0 ,
1730 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1731 cur->nodeMax = XML_NODESET_DEFAULT;
1732 } else if (cur->nodeNr == cur->nodeMax) {
1733 xmlNodePtr *temp;
1734
1735 cur->nodeMax *= 2;
1736 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1737 sizeof(xmlNodePtr));
1738 if (temp == NULL) {
1739 xmlGenericError(xmlGenericErrorContext,
1740 "xmlXPathNodeSetAddUnique: out of memory\n");
1741 return;
1742 }
1743 cur->nodeTab = temp;
1744 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001745 if (val->type == XML_NAMESPACE_DECL) {
1746 xmlNsPtr ns = (xmlNsPtr) val;
1747
1748 cur->nodeTab[cur->nodeNr++] =
1749 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1750 } else
1751 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001752}
1753
1754/**
1755 * xmlXPathNodeSetMerge:
1756 * @val1: the first NodeSet or NULL
1757 * @val2: the second NodeSet
1758 *
1759 * Merges two nodesets, all nodes from @val2 are added to @val1
1760 * if @val1 is NULL, a new set is created and copied from @val2
1761 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001762 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001763 */
1764xmlNodeSetPtr
1765xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001766 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001767
1768 if (val2 == NULL) return(val1);
1769 if (val1 == NULL) {
1770 val1 = xmlXPathNodeSetCreate(NULL);
1771 }
1772
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001773 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001774 initNr = val1->nodeNr;
1775
1776 for (i = 0;i < val2->nodeNr;i++) {
1777 /*
1778 * check against doublons
1779 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001780 skip = 0;
1781 for (j = 0; j < initNr; j++) {
1782 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1783 skip = 1;
1784 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001785 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1786 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1787 xmlNsPtr ns1, ns2;
1788 ns1 = (xmlNsPtr) val1->nodeTab[j];
1789 ns2 = (xmlNsPtr) val2->nodeTab[i];
1790 if ((ns1->next == ns2->next) &&
1791 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1792 skip = 1;
1793 break;
1794 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001795 }
1796 }
1797 if (skip)
1798 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001799
1800 /*
1801 * grow the nodeTab if needed
1802 */
1803 if (val1->nodeMax == 0) {
1804 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1805 sizeof(xmlNodePtr));
1806 if (val1->nodeTab == NULL) {
1807 xmlGenericError(xmlGenericErrorContext,
1808 "xmlXPathNodeSetMerge: out of memory\n");
1809 return(NULL);
1810 }
1811 memset(val1->nodeTab, 0 ,
1812 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1813 val1->nodeMax = XML_NODESET_DEFAULT;
1814 } else if (val1->nodeNr == val1->nodeMax) {
1815 xmlNodePtr *temp;
1816
1817 val1->nodeMax *= 2;
1818 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1819 sizeof(xmlNodePtr));
1820 if (temp == NULL) {
1821 xmlGenericError(xmlGenericErrorContext,
1822 "xmlXPathNodeSetMerge: out of memory\n");
1823 return(NULL);
1824 }
1825 val1->nodeTab = temp;
1826 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001827 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1828 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1829
1830 val1->nodeTab[val1->nodeNr++] =
1831 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1832 } else
1833 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001834 }
1835
1836 return(val1);
1837}
1838
1839/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001840 * xmlXPathNodeSetMergeUnique:
1841 * @val1: the first NodeSet or NULL
1842 * @val2: the second NodeSet
1843 *
1844 * Merges two nodesets, all nodes from @val2 are added to @val1
1845 * if @val1 is NULL, a new set is created and copied from @val2
1846 *
1847 * Returns @val1 once extended or NULL in case of error.
1848 */
1849static xmlNodeSetPtr
1850xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1851 int i, initNr;
1852
1853 if (val2 == NULL) return(val1);
1854 if (val1 == NULL) {
1855 val1 = xmlXPathNodeSetCreate(NULL);
1856 }
1857
1858 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1859 initNr = val1->nodeNr;
1860
1861 for (i = 0;i < val2->nodeNr;i++) {
1862 /*
1863 * grow the nodeTab if needed
1864 */
1865 if (val1->nodeMax == 0) {
1866 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1867 sizeof(xmlNodePtr));
1868 if (val1->nodeTab == NULL) {
1869 xmlGenericError(xmlGenericErrorContext,
1870 "xmlXPathNodeSetMerge: out of memory\n");
1871 return(NULL);
1872 }
1873 memset(val1->nodeTab, 0 ,
1874 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1875 val1->nodeMax = XML_NODESET_DEFAULT;
1876 } else if (val1->nodeNr == val1->nodeMax) {
1877 xmlNodePtr *temp;
1878
1879 val1->nodeMax *= 2;
1880 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1881 sizeof(xmlNodePtr));
1882 if (temp == NULL) {
1883 xmlGenericError(xmlGenericErrorContext,
1884 "xmlXPathNodeSetMerge: out of memory\n");
1885 return(NULL);
1886 }
1887 val1->nodeTab = temp;
1888 }
1889 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1890 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1891
1892 val1->nodeTab[val1->nodeNr++] =
1893 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1894 } else
1895 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1896 }
1897
1898 return(val1);
1899}
1900
1901/**
Owen Taylor3473f882001-02-23 17:55:21 +00001902 * xmlXPathNodeSetDel:
1903 * @cur: the initial node set
1904 * @val: an xmlNodePtr
1905 *
1906 * Removes an xmlNodePtr from an existing NodeSet
1907 */
1908void
1909xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1910 int i;
1911
1912 if (cur == NULL) return;
1913 if (val == NULL) return;
1914
1915 /*
1916 * check against doublons
1917 */
1918 for (i = 0;i < cur->nodeNr;i++)
1919 if (cur->nodeTab[i] == val) break;
1920
1921 if (i >= cur->nodeNr) {
1922#ifdef DEBUG
1923 xmlGenericError(xmlGenericErrorContext,
1924 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1925 val->name);
1926#endif
1927 return;
1928 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001929 if ((cur->nodeTab[i] != NULL) &&
1930 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1931 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001932 cur->nodeNr--;
1933 for (;i < cur->nodeNr;i++)
1934 cur->nodeTab[i] = cur->nodeTab[i + 1];
1935 cur->nodeTab[cur->nodeNr] = NULL;
1936}
1937
1938/**
1939 * xmlXPathNodeSetRemove:
1940 * @cur: the initial node set
1941 * @val: the index to remove
1942 *
1943 * Removes an entry from an existing NodeSet list.
1944 */
1945void
1946xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1947 if (cur == NULL) return;
1948 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001949 if ((cur->nodeTab[val] != NULL) &&
1950 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1951 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001952 cur->nodeNr--;
1953 for (;val < cur->nodeNr;val++)
1954 cur->nodeTab[val] = cur->nodeTab[val + 1];
1955 cur->nodeTab[cur->nodeNr] = NULL;
1956}
1957
1958/**
1959 * xmlXPathFreeNodeSet:
1960 * @obj: the xmlNodeSetPtr to free
1961 *
1962 * Free the NodeSet compound (not the actual nodes !).
1963 */
1964void
1965xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1966 if (obj == NULL) return;
1967 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001968 int i;
1969
1970 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1971 for (i = 0;i < obj->nodeNr;i++)
1972 if ((obj->nodeTab[i] != NULL) &&
1973 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1974 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001975 xmlFree(obj->nodeTab);
1976 }
Owen Taylor3473f882001-02-23 17:55:21 +00001977 xmlFree(obj);
1978}
1979
1980/**
1981 * xmlXPathFreeValueTree:
1982 * @obj: the xmlNodeSetPtr to free
1983 *
1984 * Free the NodeSet compound and the actual tree, this is different
1985 * from xmlXPathFreeNodeSet()
1986 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001987static void
Owen Taylor3473f882001-02-23 17:55:21 +00001988xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1989 int i;
1990
1991 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001992
1993 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001994 for (i = 0;i < obj->nodeNr;i++) {
1995 if (obj->nodeTab[i] != NULL) {
1996 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1997 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
1998 } else {
1999 xmlFreeNodeList(obj->nodeTab[i]);
2000 }
2001 }
2002 }
Owen Taylor3473f882001-02-23 17:55:21 +00002003 xmlFree(obj->nodeTab);
2004 }
Owen Taylor3473f882001-02-23 17:55:21 +00002005 xmlFree(obj);
2006}
2007
2008#if defined(DEBUG) || defined(DEBUG_STEP)
2009/**
2010 * xmlGenericErrorContextNodeSet:
2011 * @output: a FILE * for the output
2012 * @obj: the xmlNodeSetPtr to free
2013 *
2014 * Quick display of a NodeSet
2015 */
2016void
2017xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2018 int i;
2019
2020 if (output == NULL) output = xmlGenericErrorContext;
2021 if (obj == NULL) {
2022 fprintf(output, "NodeSet == NULL !\n");
2023 return;
2024 }
2025 if (obj->nodeNr == 0) {
2026 fprintf(output, "NodeSet is empty\n");
2027 return;
2028 }
2029 if (obj->nodeTab == NULL) {
2030 fprintf(output, " nodeTab == NULL !\n");
2031 return;
2032 }
2033 for (i = 0; i < obj->nodeNr; i++) {
2034 if (obj->nodeTab[i] == NULL) {
2035 fprintf(output, " NULL !\n");
2036 return;
2037 }
2038 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2039 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2040 fprintf(output, " /");
2041 else if (obj->nodeTab[i]->name == NULL)
2042 fprintf(output, " noname!");
2043 else fprintf(output, " %s", obj->nodeTab[i]->name);
2044 }
2045 fprintf(output, "\n");
2046}
2047#endif
2048
2049/**
2050 * xmlXPathNewNodeSet:
2051 * @val: the NodePtr value
2052 *
2053 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2054 * it with the single Node @val
2055 *
2056 * Returns the newly created object.
2057 */
2058xmlXPathObjectPtr
2059xmlXPathNewNodeSet(xmlNodePtr val) {
2060 xmlXPathObjectPtr ret;
2061
2062 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2063 if (ret == NULL) {
2064 xmlGenericError(xmlGenericErrorContext,
2065 "xmlXPathNewNodeSet: out of memory\n");
2066 return(NULL);
2067 }
2068 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2069 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002070 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002071 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002072 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002073 return(ret);
2074}
2075
2076/**
2077 * xmlXPathNewValueTree:
2078 * @val: the NodePtr value
2079 *
2080 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2081 * it with the tree root @val
2082 *
2083 * Returns the newly created object.
2084 */
2085xmlXPathObjectPtr
2086xmlXPathNewValueTree(xmlNodePtr val) {
2087 xmlXPathObjectPtr ret;
2088
2089 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2090 if (ret == NULL) {
2091 xmlGenericError(xmlGenericErrorContext,
2092 "xmlXPathNewNodeSet: out of memory\n");
2093 return(NULL);
2094 }
2095 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2096 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002097 ret->boolval = 1;
2098 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002099 ret->nodesetval = xmlXPathNodeSetCreate(val);
2100 return(ret);
2101}
2102
2103/**
2104 * xmlXPathNewNodeSetList:
2105 * @val: an existing NodeSet
2106 *
2107 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2108 * it with the Nodeset @val
2109 *
2110 * Returns the newly created object.
2111 */
2112xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002113xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2114{
Owen Taylor3473f882001-02-23 17:55:21 +00002115 xmlXPathObjectPtr ret;
2116 int i;
2117
2118 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002119 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002120 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002121 ret = xmlXPathNewNodeSet(NULL);
2122 else {
2123 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2124 for (i = 1; i < val->nodeNr; ++i)
2125 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2126 }
Owen Taylor3473f882001-02-23 17:55:21 +00002127
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002128 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002129}
2130
2131/**
2132 * xmlXPathWrapNodeSet:
2133 * @val: the NodePtr value
2134 *
2135 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2136 *
2137 * Returns the newly created object.
2138 */
2139xmlXPathObjectPtr
2140xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2141 xmlXPathObjectPtr ret;
2142
2143 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2144 if (ret == NULL) {
2145 xmlGenericError(xmlGenericErrorContext,
2146 "xmlXPathWrapNodeSet: out of memory\n");
2147 return(NULL);
2148 }
2149 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2150 ret->type = XPATH_NODESET;
2151 ret->nodesetval = val;
2152 return(ret);
2153}
2154
2155/**
2156 * xmlXPathFreeNodeSetList:
2157 * @obj: an existing NodeSetList object
2158 *
2159 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2160 * the list contrary to xmlXPathFreeObject().
2161 */
2162void
2163xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2164 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002165 xmlFree(obj);
2166}
2167
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002168/**
2169 * xmlXPathDifference:
2170 * @nodes1: a node-set
2171 * @nodes2: a node-set
2172 *
2173 * Implements the EXSLT - Sets difference() function:
2174 * node-set set:difference (node-set, node-set)
2175 *
2176 * Returns the difference between the two node sets, or nodes1 if
2177 * nodes2 is empty
2178 */
2179xmlNodeSetPtr
2180xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2181 xmlNodeSetPtr ret;
2182 int i, l1;
2183 xmlNodePtr cur;
2184
2185 if (xmlXPathNodeSetIsEmpty(nodes2))
2186 return(nodes1);
2187
2188 ret = xmlXPathNodeSetCreate(NULL);
2189 if (xmlXPathNodeSetIsEmpty(nodes1))
2190 return(ret);
2191
2192 l1 = xmlXPathNodeSetGetLength(nodes1);
2193
2194 for (i = 0; i < l1; i++) {
2195 cur = xmlXPathNodeSetItem(nodes1, i);
2196 if (!xmlXPathNodeSetContains(nodes2, cur))
2197 xmlXPathNodeSetAddUnique(ret, cur);
2198 }
2199 return(ret);
2200}
2201
2202/**
2203 * xmlXPathIntersection:
2204 * @nodes1: a node-set
2205 * @nodes2: a node-set
2206 *
2207 * Implements the EXSLT - Sets intersection() function:
2208 * node-set set:intersection (node-set, node-set)
2209 *
2210 * Returns a node set comprising the nodes that are within both the
2211 * node sets passed as arguments
2212 */
2213xmlNodeSetPtr
2214xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2215 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2216 int i, l1;
2217 xmlNodePtr cur;
2218
2219 if (xmlXPathNodeSetIsEmpty(nodes1))
2220 return(ret);
2221 if (xmlXPathNodeSetIsEmpty(nodes2))
2222 return(ret);
2223
2224 l1 = xmlXPathNodeSetGetLength(nodes1);
2225
2226 for (i = 0; i < l1; i++) {
2227 cur = xmlXPathNodeSetItem(nodes1, i);
2228 if (xmlXPathNodeSetContains(nodes2, cur))
2229 xmlXPathNodeSetAddUnique(ret, cur);
2230 }
2231 return(ret);
2232}
2233
2234/**
2235 * xmlXPathDistinctSorted:
2236 * @nodes: a node-set, sorted by document order
2237 *
2238 * Implements the EXSLT - Sets distinct() function:
2239 * node-set set:distinct (node-set)
2240 *
2241 * Returns a subset of the nodes contained in @nodes, or @nodes if
2242 * it is empty
2243 */
2244xmlNodeSetPtr
2245xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2246 xmlNodeSetPtr ret;
2247 xmlHashTablePtr hash;
2248 int i, l;
2249 xmlChar * strval;
2250 xmlNodePtr cur;
2251
2252 if (xmlXPathNodeSetIsEmpty(nodes))
2253 return(nodes);
2254
2255 ret = xmlXPathNodeSetCreate(NULL);
2256 l = xmlXPathNodeSetGetLength(nodes);
2257 hash = xmlHashCreate (l);
2258 for (i = 0; i < l; i++) {
2259 cur = xmlXPathNodeSetItem(nodes, i);
2260 strval = xmlXPathCastNodeToString(cur);
2261 if (xmlHashLookup(hash, strval) == NULL) {
2262 xmlHashAddEntry(hash, strval, strval);
2263 xmlXPathNodeSetAddUnique(ret, cur);
2264 } else {
2265 xmlFree(strval);
2266 }
2267 }
2268 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2269 return(ret);
2270}
2271
2272/**
2273 * xmlXPathDistinct:
2274 * @nodes: a node-set
2275 *
2276 * Implements the EXSLT - Sets distinct() function:
2277 * node-set set:distinct (node-set)
2278 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2279 * is called with the sorted node-set
2280 *
2281 * Returns a subset of the nodes contained in @nodes, or @nodes if
2282 * it is empty
2283 */
2284xmlNodeSetPtr
2285xmlXPathDistinct (xmlNodeSetPtr nodes) {
2286 if (xmlXPathNodeSetIsEmpty(nodes))
2287 return(nodes);
2288
2289 xmlXPathNodeSetSort(nodes);
2290 return(xmlXPathDistinctSorted(nodes));
2291}
2292
2293/**
2294 * xmlXPathHasSameNodes:
2295 * @nodes1: a node-set
2296 * @nodes2: a node-set
2297 *
2298 * Implements the EXSLT - Sets has-same-nodes function:
2299 * boolean set:has-same-node(node-set, node-set)
2300 *
2301 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2302 * otherwise
2303 */
2304int
2305xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2306 int i, l;
2307 xmlNodePtr cur;
2308
2309 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2310 xmlXPathNodeSetIsEmpty(nodes2))
2311 return(0);
2312
2313 l = xmlXPathNodeSetGetLength(nodes1);
2314 for (i = 0; i < l; i++) {
2315 cur = xmlXPathNodeSetItem(nodes1, i);
2316 if (xmlXPathNodeSetContains(nodes2, cur))
2317 return(1);
2318 }
2319 return(0);
2320}
2321
2322/**
2323 * xmlXPathNodeLeadingSorted:
2324 * @nodes: a node-set, sorted by document order
2325 * @node: a node
2326 *
2327 * Implements the EXSLT - Sets leading() function:
2328 * node-set set:leading (node-set, node-set)
2329 *
2330 * Returns the nodes in @nodes that precede @node in document order,
2331 * @nodes if @node is NULL or an empty node-set if @nodes
2332 * doesn't contain @node
2333 */
2334xmlNodeSetPtr
2335xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2336 int i, l;
2337 xmlNodePtr cur;
2338 xmlNodeSetPtr ret;
2339
2340 if (node == NULL)
2341 return(nodes);
2342
2343 ret = xmlXPathNodeSetCreate(NULL);
2344 if (xmlXPathNodeSetIsEmpty(nodes) ||
2345 (!xmlXPathNodeSetContains(nodes, node)))
2346 return(ret);
2347
2348 l = xmlXPathNodeSetGetLength(nodes);
2349 for (i = 0; i < l; i++) {
2350 cur = xmlXPathNodeSetItem(nodes, i);
2351 if (cur == node)
2352 break;
2353 xmlXPathNodeSetAddUnique(ret, cur);
2354 }
2355 return(ret);
2356}
2357
2358/**
2359 * xmlXPathNodeLeading:
2360 * @nodes: a node-set
2361 * @node: a node
2362 *
2363 * Implements the EXSLT - Sets leading() function:
2364 * node-set set:leading (node-set, node-set)
2365 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2366 * is called.
2367 *
2368 * Returns the nodes in @nodes that precede @node in document order,
2369 * @nodes if @node is NULL or an empty node-set if @nodes
2370 * doesn't contain @node
2371 */
2372xmlNodeSetPtr
2373xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2374 xmlXPathNodeSetSort(nodes);
2375 return(xmlXPathNodeLeadingSorted(nodes, node));
2376}
2377
2378/**
2379 * xmlXPathLeadingSorted:
2380 * @nodes1: a node-set, sorted by document order
2381 * @nodes2: a node-set, sorted by document order
2382 *
2383 * Implements the EXSLT - Sets leading() function:
2384 * node-set set:leading (node-set, node-set)
2385 *
2386 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2387 * in document order, @nodes1 if @nodes2 is NULL or empty or
2388 * an empty node-set if @nodes1 doesn't contain @nodes2
2389 */
2390xmlNodeSetPtr
2391xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2392 if (xmlXPathNodeSetIsEmpty(nodes2))
2393 return(nodes1);
2394 return(xmlXPathNodeLeadingSorted(nodes1,
2395 xmlXPathNodeSetItem(nodes2, 1)));
2396}
2397
2398/**
2399 * xmlXPathLeading:
2400 * @nodes1: a node-set
2401 * @nodes2: a node-set
2402 *
2403 * Implements the EXSLT - Sets leading() function:
2404 * node-set set:leading (node-set, node-set)
2405 * @nodes1 and @nodes2 are sorted by document order, then
2406 * #exslSetsLeadingSorted is called.
2407 *
2408 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2409 * in document order, @nodes1 if @nodes2 is NULL or empty or
2410 * an empty node-set if @nodes1 doesn't contain @nodes2
2411 */
2412xmlNodeSetPtr
2413xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2414 if (xmlXPathNodeSetIsEmpty(nodes2))
2415 return(nodes1);
2416 if (xmlXPathNodeSetIsEmpty(nodes1))
2417 return(xmlXPathNodeSetCreate(NULL));
2418 xmlXPathNodeSetSort(nodes1);
2419 xmlXPathNodeSetSort(nodes2);
2420 return(xmlXPathNodeLeadingSorted(nodes1,
2421 xmlXPathNodeSetItem(nodes2, 1)));
2422}
2423
2424/**
2425 * xmlXPathNodeTrailingSorted:
2426 * @nodes: a node-set, sorted by document order
2427 * @node: a node
2428 *
2429 * Implements the EXSLT - Sets trailing() function:
2430 * node-set set:trailing (node-set, node-set)
2431 *
2432 * Returns the nodes in @nodes that follow @node in document order,
2433 * @nodes if @node is NULL or an empty node-set if @nodes
2434 * doesn't contain @node
2435 */
2436xmlNodeSetPtr
2437xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2438 int i, l;
2439 xmlNodePtr cur;
2440 xmlNodeSetPtr ret;
2441
2442 if (node == NULL)
2443 return(nodes);
2444
2445 ret = xmlXPathNodeSetCreate(NULL);
2446 if (xmlXPathNodeSetIsEmpty(nodes) ||
2447 (!xmlXPathNodeSetContains(nodes, node)))
2448 return(ret);
2449
2450 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002451 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002452 cur = xmlXPathNodeSetItem(nodes, i);
2453 if (cur == node)
2454 break;
2455 xmlXPathNodeSetAddUnique(ret, cur);
2456 }
2457 return(ret);
2458}
2459
2460/**
2461 * xmlXPathNodeTrailing:
2462 * @nodes: a node-set
2463 * @node: a node
2464 *
2465 * Implements the EXSLT - Sets trailing() function:
2466 * node-set set:trailing (node-set, node-set)
2467 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2468 * is called.
2469 *
2470 * Returns the nodes in @nodes that follow @node in document order,
2471 * @nodes if @node is NULL or an empty node-set if @nodes
2472 * doesn't contain @node
2473 */
2474xmlNodeSetPtr
2475xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2476 xmlXPathNodeSetSort(nodes);
2477 return(xmlXPathNodeTrailingSorted(nodes, node));
2478}
2479
2480/**
2481 * xmlXPathTrailingSorted:
2482 * @nodes1: a node-set, sorted by document order
2483 * @nodes2: a node-set, sorted by document order
2484 *
2485 * Implements the EXSLT - Sets trailing() function:
2486 * node-set set:trailing (node-set, node-set)
2487 *
2488 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2489 * in document order, @nodes1 if @nodes2 is NULL or empty or
2490 * an empty node-set if @nodes1 doesn't contain @nodes2
2491 */
2492xmlNodeSetPtr
2493xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2494 if (xmlXPathNodeSetIsEmpty(nodes2))
2495 return(nodes1);
2496 return(xmlXPathNodeTrailingSorted(nodes1,
2497 xmlXPathNodeSetItem(nodes2, 0)));
2498}
2499
2500/**
2501 * xmlXPathTrailing:
2502 * @nodes1: a node-set
2503 * @nodes2: a node-set
2504 *
2505 * Implements the EXSLT - Sets trailing() function:
2506 * node-set set:trailing (node-set, node-set)
2507 * @nodes1 and @nodes2 are sorted by document order, then
2508 * #xmlXPathTrailingSorted is called.
2509 *
2510 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2511 * in document order, @nodes1 if @nodes2 is NULL or empty or
2512 * an empty node-set if @nodes1 doesn't contain @nodes2
2513 */
2514xmlNodeSetPtr
2515xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2516 if (xmlXPathNodeSetIsEmpty(nodes2))
2517 return(nodes1);
2518 if (xmlXPathNodeSetIsEmpty(nodes1))
2519 return(xmlXPathNodeSetCreate(NULL));
2520 xmlXPathNodeSetSort(nodes1);
2521 xmlXPathNodeSetSort(nodes2);
2522 return(xmlXPathNodeTrailingSorted(nodes1,
2523 xmlXPathNodeSetItem(nodes2, 0)));
2524}
2525
Owen Taylor3473f882001-02-23 17:55:21 +00002526/************************************************************************
2527 * *
2528 * Routines to handle extra functions *
2529 * *
2530 ************************************************************************/
2531
2532/**
2533 * xmlXPathRegisterFunc:
2534 * @ctxt: the XPath context
2535 * @name: the function name
2536 * @f: the function implementation or NULL
2537 *
2538 * Register a new function. If @f is NULL it unregisters the function
2539 *
2540 * Returns 0 in case of success, -1 in case of error
2541 */
2542int
2543xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2544 xmlXPathFunction f) {
2545 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2546}
2547
2548/**
2549 * xmlXPathRegisterFuncNS:
2550 * @ctxt: the XPath context
2551 * @name: the function name
2552 * @ns_uri: the function namespace URI
2553 * @f: the function implementation or NULL
2554 *
2555 * Register a new function. If @f is NULL it unregisters the function
2556 *
2557 * Returns 0 in case of success, -1 in case of error
2558 */
2559int
2560xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2561 const xmlChar *ns_uri, xmlXPathFunction f) {
2562 if (ctxt == NULL)
2563 return(-1);
2564 if (name == NULL)
2565 return(-1);
2566
2567 if (ctxt->funcHash == NULL)
2568 ctxt->funcHash = xmlHashCreate(0);
2569 if (ctxt->funcHash == NULL)
2570 return(-1);
2571 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2572}
2573
2574/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002575 * xmlXPathRegisterFuncLookup:
2576 * @ctxt: the XPath context
2577 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002578 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002579 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002580 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002581 */
2582void
2583xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2584 xmlXPathFuncLookupFunc f,
2585 void *funcCtxt) {
2586 if (ctxt == NULL)
2587 return;
2588 ctxt->funcLookupFunc = (void *) f;
2589 ctxt->funcLookupData = funcCtxt;
2590}
2591
2592/**
Owen Taylor3473f882001-02-23 17:55:21 +00002593 * xmlXPathFunctionLookup:
2594 * @ctxt: the XPath context
2595 * @name: the function name
2596 *
2597 * Search in the Function array of the context for the given
2598 * function.
2599 *
2600 * Returns the xmlXPathFunction or NULL if not found
2601 */
2602xmlXPathFunction
2603xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002604 if (ctxt == NULL)
2605 return (NULL);
2606
2607 if (ctxt->funcLookupFunc != NULL) {
2608 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002609 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002610
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002611 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002612 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002613 if (ret != NULL)
2614 return(ret);
2615 }
Owen Taylor3473f882001-02-23 17:55:21 +00002616 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2617}
2618
2619/**
2620 * xmlXPathFunctionLookupNS:
2621 * @ctxt: the XPath context
2622 * @name: the function name
2623 * @ns_uri: the function namespace URI
2624 *
2625 * Search in the Function array of the context for the given
2626 * function.
2627 *
2628 * Returns the xmlXPathFunction or NULL if not found
2629 */
2630xmlXPathFunction
2631xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2632 const xmlChar *ns_uri) {
2633 if (ctxt == NULL)
2634 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002635 if (name == NULL)
2636 return(NULL);
2637
Thomas Broyerba4ad322001-07-26 16:55:21 +00002638 if (ctxt->funcLookupFunc != NULL) {
2639 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002640 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002641
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002642 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002643 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002644 if (ret != NULL)
2645 return(ret);
2646 }
2647
2648 if (ctxt->funcHash == NULL)
2649 return(NULL);
2650
Owen Taylor3473f882001-02-23 17:55:21 +00002651 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2652}
2653
2654/**
2655 * xmlXPathRegisteredFuncsCleanup:
2656 * @ctxt: the XPath context
2657 *
2658 * Cleanup the XPath context data associated to registered functions
2659 */
2660void
2661xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2662 if (ctxt == NULL)
2663 return;
2664
2665 xmlHashFree(ctxt->funcHash, NULL);
2666 ctxt->funcHash = NULL;
2667}
2668
2669/************************************************************************
2670 * *
2671 * Routines to handle Variable *
2672 * *
2673 ************************************************************************/
2674
2675/**
2676 * xmlXPathRegisterVariable:
2677 * @ctxt: the XPath context
2678 * @name: the variable name
2679 * @value: the variable value or NULL
2680 *
2681 * Register a new variable value. If @value is NULL it unregisters
2682 * the variable
2683 *
2684 * Returns 0 in case of success, -1 in case of error
2685 */
2686int
2687xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2688 xmlXPathObjectPtr value) {
2689 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2690}
2691
2692/**
2693 * xmlXPathRegisterVariableNS:
2694 * @ctxt: the XPath context
2695 * @name: the variable name
2696 * @ns_uri: the variable namespace URI
2697 * @value: the variable value or NULL
2698 *
2699 * Register a new variable value. If @value is NULL it unregisters
2700 * the variable
2701 *
2702 * Returns 0 in case of success, -1 in case of error
2703 */
2704int
2705xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2706 const xmlChar *ns_uri,
2707 xmlXPathObjectPtr value) {
2708 if (ctxt == NULL)
2709 return(-1);
2710 if (name == NULL)
2711 return(-1);
2712
2713 if (ctxt->varHash == NULL)
2714 ctxt->varHash = xmlHashCreate(0);
2715 if (ctxt->varHash == NULL)
2716 return(-1);
2717 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2718 (void *) value,
2719 (xmlHashDeallocator)xmlXPathFreeObject));
2720}
2721
2722/**
2723 * xmlXPathRegisterVariableLookup:
2724 * @ctxt: the XPath context
2725 * @f: the lookup function
2726 * @data: the lookup data
2727 *
2728 * register an external mechanism to do variable lookup
2729 */
2730void
2731xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2732 xmlXPathVariableLookupFunc f, void *data) {
2733 if (ctxt == NULL)
2734 return;
2735 ctxt->varLookupFunc = (void *) f;
2736 ctxt->varLookupData = data;
2737}
2738
2739/**
2740 * xmlXPathVariableLookup:
2741 * @ctxt: the XPath context
2742 * @name: the variable name
2743 *
2744 * Search in the Variable array of the context for the given
2745 * variable value.
2746 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002747 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002748 */
2749xmlXPathObjectPtr
2750xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2751 if (ctxt == NULL)
2752 return(NULL);
2753
2754 if (ctxt->varLookupFunc != NULL) {
2755 xmlXPathObjectPtr ret;
2756
2757 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2758 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002759 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002760 }
2761 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2762}
2763
2764/**
2765 * xmlXPathVariableLookupNS:
2766 * @ctxt: the XPath context
2767 * @name: the variable name
2768 * @ns_uri: the variable namespace URI
2769 *
2770 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002771 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002772 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002773 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002774 */
2775xmlXPathObjectPtr
2776xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2777 const xmlChar *ns_uri) {
2778 if (ctxt == NULL)
2779 return(NULL);
2780
2781 if (ctxt->varLookupFunc != NULL) {
2782 xmlXPathObjectPtr ret;
2783
2784 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2785 (ctxt->varLookupData, name, ns_uri);
2786 if (ret != NULL) return(ret);
2787 }
2788
2789 if (ctxt->varHash == NULL)
2790 return(NULL);
2791 if (name == NULL)
2792 return(NULL);
2793
Daniel Veillard8c357d52001-07-03 23:43:33 +00002794 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2795 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002796}
2797
2798/**
2799 * xmlXPathRegisteredVariablesCleanup:
2800 * @ctxt: the XPath context
2801 *
2802 * Cleanup the XPath context data associated to registered variables
2803 */
2804void
2805xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2806 if (ctxt == NULL)
2807 return;
2808
Daniel Veillard76d66f42001-05-16 21:05:17 +00002809 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002810 ctxt->varHash = NULL;
2811}
2812
2813/**
2814 * xmlXPathRegisterNs:
2815 * @ctxt: the XPath context
2816 * @prefix: the namespace prefix
2817 * @ns_uri: the namespace name
2818 *
2819 * Register a new namespace. If @ns_uri is NULL it unregisters
2820 * the namespace
2821 *
2822 * Returns 0 in case of success, -1 in case of error
2823 */
2824int
2825xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2826 const xmlChar *ns_uri) {
2827 if (ctxt == NULL)
2828 return(-1);
2829 if (prefix == NULL)
2830 return(-1);
2831
2832 if (ctxt->nsHash == NULL)
2833 ctxt->nsHash = xmlHashCreate(10);
2834 if (ctxt->nsHash == NULL)
2835 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002836 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002837 (xmlHashDeallocator)xmlFree));
2838}
2839
2840/**
2841 * xmlXPathNsLookup:
2842 * @ctxt: the XPath context
2843 * @prefix: the namespace prefix value
2844 *
2845 * Search in the namespace declaration array of the context for the given
2846 * namespace name associated to the given prefix
2847 *
2848 * Returns the value or NULL if not found
2849 */
2850const xmlChar *
2851xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2852 if (ctxt == NULL)
2853 return(NULL);
2854 if (prefix == NULL)
2855 return(NULL);
2856
2857#ifdef XML_XML_NAMESPACE
2858 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2859 return(XML_XML_NAMESPACE);
2860#endif
2861
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002862 if (ctxt->namespaces != NULL) {
2863 int i;
2864
2865 for (i = 0;i < ctxt->nsNr;i++) {
2866 if ((ctxt->namespaces[i] != NULL) &&
2867 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2868 return(ctxt->namespaces[i]->href);
2869 }
2870 }
Owen Taylor3473f882001-02-23 17:55:21 +00002871
2872 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2873}
2874
2875/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002876 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002877 * @ctxt: the XPath context
2878 *
2879 * Cleanup the XPath context data associated to registered variables
2880 */
2881void
2882xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2883 if (ctxt == NULL)
2884 return;
2885
Daniel Veillard42766c02002-08-22 20:52:17 +00002886 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002887 ctxt->nsHash = NULL;
2888}
2889
2890/************************************************************************
2891 * *
2892 * Routines to handle Values *
2893 * *
2894 ************************************************************************/
2895
2896/* Allocations are terrible, one need to optimize all this !!! */
2897
2898/**
2899 * xmlXPathNewFloat:
2900 * @val: the double value
2901 *
2902 * Create a new xmlXPathObjectPtr of type double and of value @val
2903 *
2904 * Returns the newly created object.
2905 */
2906xmlXPathObjectPtr
2907xmlXPathNewFloat(double val) {
2908 xmlXPathObjectPtr ret;
2909
2910 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2911 if (ret == NULL) {
2912 xmlGenericError(xmlGenericErrorContext,
2913 "xmlXPathNewFloat: out of memory\n");
2914 return(NULL);
2915 }
2916 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2917 ret->type = XPATH_NUMBER;
2918 ret->floatval = val;
2919 return(ret);
2920}
2921
2922/**
2923 * xmlXPathNewBoolean:
2924 * @val: the boolean value
2925 *
2926 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2927 *
2928 * Returns the newly created object.
2929 */
2930xmlXPathObjectPtr
2931xmlXPathNewBoolean(int val) {
2932 xmlXPathObjectPtr ret;
2933
2934 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2935 if (ret == NULL) {
2936 xmlGenericError(xmlGenericErrorContext,
2937 "xmlXPathNewBoolean: out of memory\n");
2938 return(NULL);
2939 }
2940 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2941 ret->type = XPATH_BOOLEAN;
2942 ret->boolval = (val != 0);
2943 return(ret);
2944}
2945
2946/**
2947 * xmlXPathNewString:
2948 * @val: the xmlChar * value
2949 *
2950 * Create a new xmlXPathObjectPtr of type string and of value @val
2951 *
2952 * Returns the newly created object.
2953 */
2954xmlXPathObjectPtr
2955xmlXPathNewString(const xmlChar *val) {
2956 xmlXPathObjectPtr ret;
2957
2958 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2959 if (ret == NULL) {
2960 xmlGenericError(xmlGenericErrorContext,
2961 "xmlXPathNewString: out of memory\n");
2962 return(NULL);
2963 }
2964 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2965 ret->type = XPATH_STRING;
2966 if (val != NULL)
2967 ret->stringval = xmlStrdup(val);
2968 else
2969 ret->stringval = xmlStrdup((const xmlChar *)"");
2970 return(ret);
2971}
2972
2973/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002974 * xmlXPathWrapString:
2975 * @val: the xmlChar * value
2976 *
2977 * Wraps the @val string into an XPath object.
2978 *
2979 * Returns the newly created object.
2980 */
2981xmlXPathObjectPtr
2982xmlXPathWrapString (xmlChar *val) {
2983 xmlXPathObjectPtr ret;
2984
2985 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2986 if (ret == NULL) {
2987 xmlGenericError(xmlGenericErrorContext,
2988 "xmlXPathWrapString: out of memory\n");
2989 return(NULL);
2990 }
2991 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2992 ret->type = XPATH_STRING;
2993 ret->stringval = val;
2994 return(ret);
2995}
2996
2997/**
Owen Taylor3473f882001-02-23 17:55:21 +00002998 * xmlXPathNewCString:
2999 * @val: the char * value
3000 *
3001 * Create a new xmlXPathObjectPtr of type string and of value @val
3002 *
3003 * Returns the newly created object.
3004 */
3005xmlXPathObjectPtr
3006xmlXPathNewCString(const char *val) {
3007 xmlXPathObjectPtr ret;
3008
3009 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3010 if (ret == NULL) {
3011 xmlGenericError(xmlGenericErrorContext,
3012 "xmlXPathNewCString: out of memory\n");
3013 return(NULL);
3014 }
3015 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3016 ret->type = XPATH_STRING;
3017 ret->stringval = xmlStrdup(BAD_CAST val);
3018 return(ret);
3019}
3020
3021/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003022 * xmlXPathWrapCString:
3023 * @val: the char * value
3024 *
3025 * Wraps a string into an XPath object.
3026 *
3027 * Returns the newly created object.
3028 */
3029xmlXPathObjectPtr
3030xmlXPathWrapCString (char * val) {
3031 return(xmlXPathWrapString((xmlChar *)(val)));
3032}
3033
3034/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003035 * xmlXPathWrapExternal:
3036 * @val: the user data
3037 *
3038 * Wraps the @val data into an XPath object.
3039 *
3040 * Returns the newly created object.
3041 */
3042xmlXPathObjectPtr
3043xmlXPathWrapExternal (void *val) {
3044 xmlXPathObjectPtr ret;
3045
3046 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3047 if (ret == NULL) {
3048 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003049 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003050 return(NULL);
3051 }
3052 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3053 ret->type = XPATH_USERS;
3054 ret->user = val;
3055 return(ret);
3056}
3057
3058/**
Owen Taylor3473f882001-02-23 17:55:21 +00003059 * xmlXPathObjectCopy:
3060 * @val: the original object
3061 *
3062 * allocate a new copy of a given object
3063 *
3064 * Returns the newly created object.
3065 */
3066xmlXPathObjectPtr
3067xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3068 xmlXPathObjectPtr ret;
3069
3070 if (val == NULL)
3071 return(NULL);
3072
3073 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3074 if (ret == NULL) {
3075 xmlGenericError(xmlGenericErrorContext,
3076 "xmlXPathObjectCopy: out of memory\n");
3077 return(NULL);
3078 }
3079 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3080 switch (val->type) {
3081 case XPATH_BOOLEAN:
3082 case XPATH_NUMBER:
3083 case XPATH_POINT:
3084 case XPATH_RANGE:
3085 break;
3086 case XPATH_STRING:
3087 ret->stringval = xmlStrdup(val->stringval);
3088 break;
3089 case XPATH_XSLT_TREE:
3090 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003091 (val->nodesetval->nodeTab != NULL)) {
3092 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003093 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3094 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003095 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003096 (xmlNodePtr) ret->user);
3097 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003098 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003099 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003100 break;
3101 case XPATH_NODESET:
3102 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003103 /* Do not deallocate the copied tree value */
3104 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003105 break;
3106 case XPATH_LOCATIONSET:
3107#ifdef LIBXML_XPTR_ENABLED
3108 {
3109 xmlLocationSetPtr loc = val->user;
3110 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3111 break;
3112 }
3113#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003114 case XPATH_USERS:
3115 ret->user = val->user;
3116 break;
3117 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003118 xmlGenericError(xmlGenericErrorContext,
3119 "xmlXPathObjectCopy: unsupported type %d\n",
3120 val->type);
3121 break;
3122 }
3123 return(ret);
3124}
3125
3126/**
3127 * xmlXPathFreeObject:
3128 * @obj: the object to free
3129 *
3130 * Free up an xmlXPathObjectPtr object.
3131 */
3132void
3133xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3134 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003135 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003136 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003137 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003138 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003139 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003140 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003141 xmlXPathFreeValueTree(obj->nodesetval);
3142 } else {
3143 if (obj->nodesetval != NULL)
3144 xmlXPathFreeNodeSet(obj->nodesetval);
3145 }
Owen Taylor3473f882001-02-23 17:55:21 +00003146#ifdef LIBXML_XPTR_ENABLED
3147 } else if (obj->type == XPATH_LOCATIONSET) {
3148 if (obj->user != NULL)
3149 xmlXPtrFreeLocationSet(obj->user);
3150#endif
3151 } else if (obj->type == XPATH_STRING) {
3152 if (obj->stringval != NULL)
3153 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003154 }
3155
Owen Taylor3473f882001-02-23 17:55:21 +00003156 xmlFree(obj);
3157}
3158
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003159
3160/************************************************************************
3161 * *
3162 * Type Casting Routines *
3163 * *
3164 ************************************************************************/
3165
3166/**
3167 * xmlXPathCastBooleanToString:
3168 * @val: a boolean
3169 *
3170 * Converts a boolean to its string value.
3171 *
3172 * Returns a newly allocated string.
3173 */
3174xmlChar *
3175xmlXPathCastBooleanToString (int val) {
3176 xmlChar *ret;
3177 if (val)
3178 ret = xmlStrdup((const xmlChar *) "true");
3179 else
3180 ret = xmlStrdup((const xmlChar *) "false");
3181 return(ret);
3182}
3183
3184/**
3185 * xmlXPathCastNumberToString:
3186 * @val: a number
3187 *
3188 * Converts a number to its string value.
3189 *
3190 * Returns a newly allocated string.
3191 */
3192xmlChar *
3193xmlXPathCastNumberToString (double val) {
3194 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003195 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003196 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003197 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003198 break;
3199 case -1:
3200 ret = xmlStrdup((const xmlChar *) "-Infinity");
3201 break;
3202 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003203 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003204 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003205 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3206 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003207 } else {
3208 /* could be improved */
3209 char buf[100];
3210 xmlXPathFormatNumber(val, buf, 100);
3211 ret = xmlStrdup((const xmlChar *) buf);
3212 }
3213 }
3214 return(ret);
3215}
3216
3217/**
3218 * xmlXPathCastNodeToString:
3219 * @node: a node
3220 *
3221 * Converts a node to its string value.
3222 *
3223 * Returns a newly allocated string.
3224 */
3225xmlChar *
3226xmlXPathCastNodeToString (xmlNodePtr node) {
Daniel Veillard23b1f372002-04-18 15:50:05 +00003227 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE))
3228 node = xmlDocGetRootElement((xmlDocPtr) node);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003229 return(xmlNodeGetContent(node));
3230}
3231
3232/**
3233 * xmlXPathCastNodeSetToString:
3234 * @ns: a node-set
3235 *
3236 * Converts a node-set to its string value.
3237 *
3238 * Returns a newly allocated string.
3239 */
3240xmlChar *
3241xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3242 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3243 return(xmlStrdup((const xmlChar *) ""));
3244
3245 xmlXPathNodeSetSort(ns);
3246 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3247}
3248
3249/**
3250 * xmlXPathCastToString:
3251 * @val: an XPath object
3252 *
3253 * Converts an existing object to its string() equivalent
3254 *
3255 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003256 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003257 * string object).
3258 */
3259xmlChar *
3260xmlXPathCastToString(xmlXPathObjectPtr val) {
3261 xmlChar *ret = NULL;
3262
3263 if (val == NULL)
3264 return(xmlStrdup((const xmlChar *) ""));
3265 switch (val->type) {
3266 case XPATH_UNDEFINED:
3267#ifdef DEBUG_EXPR
3268 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3269#endif
3270 ret = xmlStrdup((const xmlChar *) "");
3271 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003272 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003273 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003274 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3275 break;
3276 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003277 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003278 case XPATH_BOOLEAN:
3279 ret = xmlXPathCastBooleanToString(val->boolval);
3280 break;
3281 case XPATH_NUMBER: {
3282 ret = xmlXPathCastNumberToString(val->floatval);
3283 break;
3284 }
3285 case XPATH_USERS:
3286 case XPATH_POINT:
3287 case XPATH_RANGE:
3288 case XPATH_LOCATIONSET:
3289 TODO
3290 ret = xmlStrdup((const xmlChar *) "");
3291 break;
3292 }
3293 return(ret);
3294}
3295
3296/**
3297 * xmlXPathConvertString:
3298 * @val: an XPath object
3299 *
3300 * Converts an existing object to its string() equivalent
3301 *
3302 * Returns the new object, the old one is freed (or the operation
3303 * is done directly on @val)
3304 */
3305xmlXPathObjectPtr
3306xmlXPathConvertString(xmlXPathObjectPtr val) {
3307 xmlChar *res = NULL;
3308
3309 if (val == NULL)
3310 return(xmlXPathNewCString(""));
3311
3312 switch (val->type) {
3313 case XPATH_UNDEFINED:
3314#ifdef DEBUG_EXPR
3315 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3316#endif
3317 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003318 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003319 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003320 res = xmlXPathCastNodeSetToString(val->nodesetval);
3321 break;
3322 case XPATH_STRING:
3323 return(val);
3324 case XPATH_BOOLEAN:
3325 res = xmlXPathCastBooleanToString(val->boolval);
3326 break;
3327 case XPATH_NUMBER:
3328 res = xmlXPathCastNumberToString(val->floatval);
3329 break;
3330 case XPATH_USERS:
3331 case XPATH_POINT:
3332 case XPATH_RANGE:
3333 case XPATH_LOCATIONSET:
3334 TODO;
3335 break;
3336 }
3337 xmlXPathFreeObject(val);
3338 if (res == NULL)
3339 return(xmlXPathNewCString(""));
3340 return(xmlXPathWrapString(res));
3341}
3342
3343/**
3344 * xmlXPathCastBooleanToNumber:
3345 * @val: a boolean
3346 *
3347 * Converts a boolean to its number value
3348 *
3349 * Returns the number value
3350 */
3351double
3352xmlXPathCastBooleanToNumber(int val) {
3353 if (val)
3354 return(1.0);
3355 return(0.0);
3356}
3357
3358/**
3359 * xmlXPathCastStringToNumber:
3360 * @val: a string
3361 *
3362 * Converts a string to its number value
3363 *
3364 * Returns the number value
3365 */
3366double
3367xmlXPathCastStringToNumber(const xmlChar * val) {
3368 return(xmlXPathStringEvalNumber(val));
3369}
3370
3371/**
3372 * xmlXPathCastNodeToNumber:
3373 * @node: a node
3374 *
3375 * Converts a node to its number value
3376 *
3377 * Returns the number value
3378 */
3379double
3380xmlXPathCastNodeToNumber (xmlNodePtr node) {
3381 xmlChar *strval;
3382 double ret;
3383
3384 if (node == NULL)
3385 return(xmlXPathNAN);
3386 strval = xmlXPathCastNodeToString(node);
3387 if (strval == NULL)
3388 return(xmlXPathNAN);
3389 ret = xmlXPathCastStringToNumber(strval);
3390 xmlFree(strval);
3391
3392 return(ret);
3393}
3394
3395/**
3396 * xmlXPathCastNodeSetToNumber:
3397 * @ns: a node-set
3398 *
3399 * Converts a node-set to its number value
3400 *
3401 * Returns the number value
3402 */
3403double
3404xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3405 xmlChar *str;
3406 double ret;
3407
3408 if (ns == NULL)
3409 return(xmlXPathNAN);
3410 str = xmlXPathCastNodeSetToString(ns);
3411 ret = xmlXPathCastStringToNumber(str);
3412 xmlFree(str);
3413 return(ret);
3414}
3415
3416/**
3417 * xmlXPathCastToNumber:
3418 * @val: an XPath object
3419 *
3420 * Converts an XPath object to its number value
3421 *
3422 * Returns the number value
3423 */
3424double
3425xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3426 double ret = 0.0;
3427
3428 if (val == NULL)
3429 return(xmlXPathNAN);
3430 switch (val->type) {
3431 case XPATH_UNDEFINED:
3432#ifdef DEGUB_EXPR
3433 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3434#endif
3435 ret = xmlXPathNAN;
3436 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003437 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003438 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003439 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3440 break;
3441 case XPATH_STRING:
3442 ret = xmlXPathCastStringToNumber(val->stringval);
3443 break;
3444 case XPATH_NUMBER:
3445 ret = val->floatval;
3446 break;
3447 case XPATH_BOOLEAN:
3448 ret = xmlXPathCastBooleanToNumber(val->boolval);
3449 break;
3450 case XPATH_USERS:
3451 case XPATH_POINT:
3452 case XPATH_RANGE:
3453 case XPATH_LOCATIONSET:
3454 TODO;
3455 ret = xmlXPathNAN;
3456 break;
3457 }
3458 return(ret);
3459}
3460
3461/**
3462 * xmlXPathConvertNumber:
3463 * @val: an XPath object
3464 *
3465 * Converts an existing object to its number() equivalent
3466 *
3467 * Returns the new object, the old one is freed (or the operation
3468 * is done directly on @val)
3469 */
3470xmlXPathObjectPtr
3471xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3472 xmlXPathObjectPtr ret;
3473
3474 if (val == NULL)
3475 return(xmlXPathNewFloat(0.0));
3476 if (val->type == XPATH_NUMBER)
3477 return(val);
3478 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3479 xmlXPathFreeObject(val);
3480 return(ret);
3481}
3482
3483/**
3484 * xmlXPathCastNumberToBoolean:
3485 * @val: a number
3486 *
3487 * Converts a number to its boolean value
3488 *
3489 * Returns the boolean value
3490 */
3491int
3492xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003493 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003494 return(0);
3495 return(1);
3496}
3497
3498/**
3499 * xmlXPathCastStringToBoolean:
3500 * @val: a string
3501 *
3502 * Converts a string to its boolean value
3503 *
3504 * Returns the boolean value
3505 */
3506int
3507xmlXPathCastStringToBoolean (const xmlChar *val) {
3508 if ((val == NULL) || (xmlStrlen(val) == 0))
3509 return(0);
3510 return(1);
3511}
3512
3513/**
3514 * xmlXPathCastNodeSetToBoolean:
3515 * @ns: a node-set
3516 *
3517 * Converts a node-set to its boolean value
3518 *
3519 * Returns the boolean value
3520 */
3521int
3522xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3523 if ((ns == NULL) || (ns->nodeNr == 0))
3524 return(0);
3525 return(1);
3526}
3527
3528/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003529 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003530 * @val: an XPath object
3531 *
3532 * Converts an XPath object to its boolean value
3533 *
3534 * Returns the boolean value
3535 */
3536int
3537xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3538 int ret = 0;
3539
3540 if (val == NULL)
3541 return(0);
3542 switch (val->type) {
3543 case XPATH_UNDEFINED:
3544#ifdef DEBUG_EXPR
3545 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3546#endif
3547 ret = 0;
3548 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003549 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003550 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003551 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3552 break;
3553 case XPATH_STRING:
3554 ret = xmlXPathCastStringToBoolean(val->stringval);
3555 break;
3556 case XPATH_NUMBER:
3557 ret = xmlXPathCastNumberToBoolean(val->floatval);
3558 break;
3559 case XPATH_BOOLEAN:
3560 ret = val->boolval;
3561 break;
3562 case XPATH_USERS:
3563 case XPATH_POINT:
3564 case XPATH_RANGE:
3565 case XPATH_LOCATIONSET:
3566 TODO;
3567 ret = 0;
3568 break;
3569 }
3570 return(ret);
3571}
3572
3573
3574/**
3575 * xmlXPathConvertBoolean:
3576 * @val: an XPath object
3577 *
3578 * Converts an existing object to its boolean() equivalent
3579 *
3580 * Returns the new object, the old one is freed (or the operation
3581 * is done directly on @val)
3582 */
3583xmlXPathObjectPtr
3584xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3585 xmlXPathObjectPtr ret;
3586
3587 if (val == NULL)
3588 return(xmlXPathNewBoolean(0));
3589 if (val->type == XPATH_BOOLEAN)
3590 return(val);
3591 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3592 xmlXPathFreeObject(val);
3593 return(ret);
3594}
3595
Owen Taylor3473f882001-02-23 17:55:21 +00003596/************************************************************************
3597 * *
3598 * Routines to handle XPath contexts *
3599 * *
3600 ************************************************************************/
3601
3602/**
3603 * xmlXPathNewContext:
3604 * @doc: the XML document
3605 *
3606 * Create a new xmlXPathContext
3607 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003608 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003609 */
3610xmlXPathContextPtr
3611xmlXPathNewContext(xmlDocPtr doc) {
3612 xmlXPathContextPtr ret;
3613
3614 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3615 if (ret == NULL) {
3616 xmlGenericError(xmlGenericErrorContext,
3617 "xmlXPathNewContext: out of memory\n");
3618 return(NULL);
3619 }
3620 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3621 ret->doc = doc;
3622 ret->node = NULL;
3623
3624 ret->varHash = NULL;
3625
3626 ret->nb_types = 0;
3627 ret->max_types = 0;
3628 ret->types = NULL;
3629
3630 ret->funcHash = xmlHashCreate(0);
3631
3632 ret->nb_axis = 0;
3633 ret->max_axis = 0;
3634 ret->axis = NULL;
3635
3636 ret->nsHash = NULL;
3637 ret->user = NULL;
3638
3639 ret->contextSize = -1;
3640 ret->proximityPosition = -1;
3641
3642 xmlXPathRegisterAllFunctions(ret);
3643
3644 return(ret);
3645}
3646
3647/**
3648 * xmlXPathFreeContext:
3649 * @ctxt: the context to free
3650 *
3651 * Free up an xmlXPathContext
3652 */
3653void
3654xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3655 xmlXPathRegisteredNsCleanup(ctxt);
3656 xmlXPathRegisteredFuncsCleanup(ctxt);
3657 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003658 xmlFree(ctxt);
3659}
3660
3661/************************************************************************
3662 * *
3663 * Routines to handle XPath parser contexts *
3664 * *
3665 ************************************************************************/
3666
3667#define CHECK_CTXT(ctxt) \
3668 if (ctxt == NULL) { \
3669 xmlGenericError(xmlGenericErrorContext, \
3670 "%s:%d Internal error: ctxt == NULL\n", \
3671 __FILE__, __LINE__); \
3672 } \
3673
3674
3675#define CHECK_CONTEXT(ctxt) \
3676 if (ctxt == NULL) { \
3677 xmlGenericError(xmlGenericErrorContext, \
3678 "%s:%d Internal error: no context\n", \
3679 __FILE__, __LINE__); \
3680 } \
3681 else if (ctxt->doc == NULL) { \
3682 xmlGenericError(xmlGenericErrorContext, \
3683 "%s:%d Internal error: no document\n", \
3684 __FILE__, __LINE__); \
3685 } \
3686 else if (ctxt->doc->children == NULL) { \
3687 xmlGenericError(xmlGenericErrorContext, \
3688 "%s:%d Internal error: document without root\n", \
3689 __FILE__, __LINE__); \
3690 } \
3691
3692
3693/**
3694 * xmlXPathNewParserContext:
3695 * @str: the XPath expression
3696 * @ctxt: the XPath context
3697 *
3698 * Create a new xmlXPathParserContext
3699 *
3700 * Returns the xmlXPathParserContext just allocated.
3701 */
3702xmlXPathParserContextPtr
3703xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3704 xmlXPathParserContextPtr ret;
3705
3706 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3707 if (ret == NULL) {
3708 xmlGenericError(xmlGenericErrorContext,
3709 "xmlXPathNewParserContext: out of memory\n");
3710 return(NULL);
3711 }
3712 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3713 ret->cur = ret->base = str;
3714 ret->context = ctxt;
3715
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003716 ret->comp = xmlXPathNewCompExpr();
3717 if (ret->comp == NULL) {
3718 xmlFree(ret->valueTab);
3719 xmlFree(ret);
3720 return(NULL);
3721 }
3722
3723 return(ret);
3724}
3725
3726/**
3727 * xmlXPathCompParserContext:
3728 * @comp: the XPath compiled expression
3729 * @ctxt: the XPath context
3730 *
3731 * Create a new xmlXPathParserContext when processing a compiled expression
3732 *
3733 * Returns the xmlXPathParserContext just allocated.
3734 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003735static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003736xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3737 xmlXPathParserContextPtr ret;
3738
3739 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3740 if (ret == NULL) {
3741 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003742 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003743 return(NULL);
3744 }
3745 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3746
Owen Taylor3473f882001-02-23 17:55:21 +00003747 /* Allocate the value stack */
3748 ret->valueTab = (xmlXPathObjectPtr *)
3749 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003750 if (ret->valueTab == NULL) {
3751 xmlFree(ret);
3752 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003753 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003754 return(NULL);
3755 }
Owen Taylor3473f882001-02-23 17:55:21 +00003756 ret->valueNr = 0;
3757 ret->valueMax = 10;
3758 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003759
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003760 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003761 ret->comp = comp;
3762
Owen Taylor3473f882001-02-23 17:55:21 +00003763 return(ret);
3764}
3765
3766/**
3767 * xmlXPathFreeParserContext:
3768 * @ctxt: the context to free
3769 *
3770 * Free up an xmlXPathParserContext
3771 */
3772void
3773xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3774 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003775 xmlFree(ctxt->valueTab);
3776 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003777 if (ctxt->comp)
3778 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003779 xmlFree(ctxt);
3780}
3781
3782/************************************************************************
3783 * *
3784 * The implicit core function library *
3785 * *
3786 ************************************************************************/
3787
Owen Taylor3473f882001-02-23 17:55:21 +00003788/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003789 * xmlXPathNodeStringHash:
3790 * @node: a node pointer
3791 *
3792 * Function computing the beginning of the string value of the node,
3793 * used to speed up comparisons
3794 *
3795 * Returns an int usable as a hash
3796 */
3797static unsigned int
3798xmlXPathNodeValHash(xmlNodePtr node) {
3799 int len = 2;
3800 const xmlChar * string = NULL;
3801 xmlNodePtr tmp = NULL;
3802 unsigned int ret = 0;
3803
3804 if (node == NULL)
3805 return(0);
3806
3807
3808 switch (node->type) {
3809 case XML_COMMENT_NODE:
3810 case XML_PI_NODE:
3811 case XML_CDATA_SECTION_NODE:
3812 case XML_TEXT_NODE:
3813 string = node->content;
3814 if (string == NULL)
3815 return(0);
3816 if (string[0] == 0)
3817 return(0);
3818 return(((unsigned int) string[0]) +
3819 (((unsigned int) string[1]) << 8));
3820 case XML_NAMESPACE_DECL:
3821 string = ((xmlNsPtr)node)->href;
3822 if (string == NULL)
3823 return(0);
3824 if (string[0] == 0)
3825 return(0);
3826 return(((unsigned int) string[0]) +
3827 (((unsigned int) string[1]) << 8));
3828 case XML_ATTRIBUTE_NODE:
3829 tmp = ((xmlAttrPtr) node)->children;
3830 break;
3831 case XML_ELEMENT_NODE:
3832 tmp = node->children;
3833 break;
3834 default:
3835 return(0);
3836 }
3837 while (tmp != NULL) {
3838 switch (tmp->type) {
3839 case XML_COMMENT_NODE:
3840 case XML_PI_NODE:
3841 case XML_CDATA_SECTION_NODE:
3842 case XML_TEXT_NODE:
3843 string = tmp->content;
3844 break;
3845 case XML_NAMESPACE_DECL:
3846 string = ((xmlNsPtr)tmp)->href;
3847 break;
3848 default:
3849 break;
3850 }
3851 if ((string != NULL) && (string[0] != 0)) {
3852 if (string[0] == 0)
3853 return(0);
3854 if (len == 1) {
3855 return(ret + (((unsigned int) string[0]) << 8));
3856 }
3857 if (string[1] == 0) {
3858 len = 1;
3859 ret = (unsigned int) string[0];
3860 } else {
3861 return(((unsigned int) string[0]) +
3862 (((unsigned int) string[1]) << 8));
3863 }
3864 }
3865 /*
3866 * Skip to next node
3867 */
3868 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3869 if (tmp->children->type != XML_ENTITY_DECL) {
3870 tmp = tmp->children;
3871 continue;
3872 }
3873 }
3874 if (tmp == node)
3875 break;
3876
3877 if (tmp->next != NULL) {
3878 tmp = tmp->next;
3879 continue;
3880 }
3881
3882 do {
3883 tmp = tmp->parent;
3884 if (tmp == NULL)
3885 break;
3886 if (tmp == node) {
3887 tmp = NULL;
3888 break;
3889 }
3890 if (tmp->next != NULL) {
3891 tmp = tmp->next;
3892 break;
3893 }
3894 } while (tmp != NULL);
3895 }
3896 return(ret);
3897}
3898
3899/**
3900 * xmlXPathStringHash:
3901 * @string: a string
3902 *
3903 * Function computing the beginning of the string value of the node,
3904 * used to speed up comparisons
3905 *
3906 * Returns an int usable as a hash
3907 */
3908static unsigned int
3909xmlXPathStringHash(const xmlChar * string) {
3910 if (string == NULL)
3911 return((unsigned int) 0);
3912 if (string[0] == 0)
3913 return(0);
3914 return(((unsigned int) string[0]) +
3915 (((unsigned int) string[1]) << 8));
3916}
3917
3918/**
Owen Taylor3473f882001-02-23 17:55:21 +00003919 * xmlXPathCompareNodeSetFloat:
3920 * @ctxt: the XPath Parser context
3921 * @inf: less than (1) or greater than (0)
3922 * @strict: is the comparison strict
3923 * @arg: the node set
3924 * @f: the value
3925 *
3926 * Implement the compare operation between a nodeset and a number
3927 * @ns < @val (1, 1, ...
3928 * @ns <= @val (1, 0, ...
3929 * @ns > @val (0, 1, ...
3930 * @ns >= @val (0, 0, ...
3931 *
3932 * If one object to be compared is a node-set and the other is a number,
3933 * then the comparison will be true if and only if there is a node in the
3934 * node-set such that the result of performing the comparison on the number
3935 * to be compared and on the result of converting the string-value of that
3936 * node to a number using the number function is true.
3937 *
3938 * Returns 0 or 1 depending on the results of the test.
3939 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003940static int
Owen Taylor3473f882001-02-23 17:55:21 +00003941xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3942 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3943 int i, ret = 0;
3944 xmlNodeSetPtr ns;
3945 xmlChar *str2;
3946
3947 if ((f == NULL) || (arg == NULL) ||
3948 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3949 xmlXPathFreeObject(arg);
3950 xmlXPathFreeObject(f);
3951 return(0);
3952 }
3953 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003954 if (ns != NULL) {
3955 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003956 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003957 if (str2 != NULL) {
3958 valuePush(ctxt,
3959 xmlXPathNewString(str2));
3960 xmlFree(str2);
3961 xmlXPathNumberFunction(ctxt, 1);
3962 valuePush(ctxt, xmlXPathObjectCopy(f));
3963 ret = xmlXPathCompareValues(ctxt, inf, strict);
3964 if (ret)
3965 break;
3966 }
3967 }
Owen Taylor3473f882001-02-23 17:55:21 +00003968 }
3969 xmlXPathFreeObject(arg);
3970 xmlXPathFreeObject(f);
3971 return(ret);
3972}
3973
3974/**
3975 * xmlXPathCompareNodeSetString:
3976 * @ctxt: the XPath Parser context
3977 * @inf: less than (1) or greater than (0)
3978 * @strict: is the comparison strict
3979 * @arg: the node set
3980 * @s: the value
3981 *
3982 * Implement the compare operation between a nodeset and a string
3983 * @ns < @val (1, 1, ...
3984 * @ns <= @val (1, 0, ...
3985 * @ns > @val (0, 1, ...
3986 * @ns >= @val (0, 0, ...
3987 *
3988 * If one object to be compared is a node-set and the other is a string,
3989 * then the comparison will be true if and only if there is a node in
3990 * the node-set such that the result of performing the comparison on the
3991 * string-value of the node and the other string is true.
3992 *
3993 * Returns 0 or 1 depending on the results of the test.
3994 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003995static int
Owen Taylor3473f882001-02-23 17:55:21 +00003996xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3997 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3998 int i, ret = 0;
3999 xmlNodeSetPtr ns;
4000 xmlChar *str2;
4001
4002 if ((s == NULL) || (arg == NULL) ||
4003 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4004 xmlXPathFreeObject(arg);
4005 xmlXPathFreeObject(s);
4006 return(0);
4007 }
4008 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004009 if (ns != NULL) {
4010 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004011 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004012 if (str2 != NULL) {
4013 valuePush(ctxt,
4014 xmlXPathNewString(str2));
4015 xmlFree(str2);
4016 valuePush(ctxt, xmlXPathObjectCopy(s));
4017 ret = xmlXPathCompareValues(ctxt, inf, strict);
4018 if (ret)
4019 break;
4020 }
4021 }
Owen Taylor3473f882001-02-23 17:55:21 +00004022 }
4023 xmlXPathFreeObject(arg);
4024 xmlXPathFreeObject(s);
4025 return(ret);
4026}
4027
4028/**
4029 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004030 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004031 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004032 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004033 * @arg2: the second node set object
4034 *
4035 * Implement the compare operation on nodesets:
4036 *
4037 * If both objects to be compared are node-sets, then the comparison
4038 * will be true if and only if there is a node in the first node-set
4039 * and a node in the second node-set such that the result of performing
4040 * the comparison on the string-values of the two nodes is true.
4041 * ....
4042 * When neither object to be compared is a node-set and the operator
4043 * is <=, <, >= or >, then the objects are compared by converting both
4044 * objects to numbers and comparing the numbers according to IEEE 754.
4045 * ....
4046 * The number function converts its argument to a number as follows:
4047 * - a string that consists of optional whitespace followed by an
4048 * optional minus sign followed by a Number followed by whitespace
4049 * is converted to the IEEE 754 number that is nearest (according
4050 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4051 * represented by the string; any other string is converted to NaN
4052 *
4053 * Conclusion all nodes need to be converted first to their string value
4054 * and then the comparison must be done when possible
4055 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004056static int
4057xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004058 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4059 int i, j, init = 0;
4060 double val1;
4061 double *values2;
4062 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004063 xmlNodeSetPtr ns1;
4064 xmlNodeSetPtr ns2;
4065
4066 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004067 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4068 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004069 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004070 }
Owen Taylor3473f882001-02-23 17:55:21 +00004071 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004072 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4073 xmlXPathFreeObject(arg1);
4074 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004075 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004076 }
Owen Taylor3473f882001-02-23 17:55:21 +00004077
4078 ns1 = arg1->nodesetval;
4079 ns2 = arg2->nodesetval;
4080
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004081 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004082 xmlXPathFreeObject(arg1);
4083 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004084 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004085 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004086 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004087 xmlXPathFreeObject(arg1);
4088 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004089 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004090 }
Owen Taylor3473f882001-02-23 17:55:21 +00004091
4092 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4093 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004094 xmlXPathFreeObject(arg1);
4095 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004096 return(0);
4097 }
4098 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004099 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004100 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004101 continue;
4102 for (j = 0;j < ns2->nodeNr;j++) {
4103 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004104 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004105 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004106 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004107 continue;
4108 if (inf && strict)
4109 ret = (val1 < values2[j]);
4110 else 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 if (ret)
4117 break;
4118 }
4119 if (ret)
4120 break;
4121 init = 1;
4122 }
4123 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004124 xmlXPathFreeObject(arg1);
4125 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004126 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004127}
4128
4129/**
4130 * xmlXPathCompareNodeSetValue:
4131 * @ctxt: the XPath Parser context
4132 * @inf: less than (1) or greater than (0)
4133 * @strict: is the comparison strict
4134 * @arg: the node set
4135 * @val: the value
4136 *
4137 * Implement the compare operation between a nodeset and a value
4138 * @ns < @val (1, 1, ...
4139 * @ns <= @val (1, 0, ...
4140 * @ns > @val (0, 1, ...
4141 * @ns >= @val (0, 0, ...
4142 *
4143 * If one object to be compared is a node-set and the other is a boolean,
4144 * then the comparison will be true if and only if the result of performing
4145 * the comparison on the boolean and on the result of converting
4146 * the node-set to a boolean using the boolean function is true.
4147 *
4148 * Returns 0 or 1 depending on the results of the test.
4149 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004150static int
Owen Taylor3473f882001-02-23 17:55:21 +00004151xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4152 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4153 if ((val == NULL) || (arg == NULL) ||
4154 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4155 return(0);
4156
4157 switch(val->type) {
4158 case XPATH_NUMBER:
4159 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4160 case XPATH_NODESET:
4161 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004162 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004163 case XPATH_STRING:
4164 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4165 case XPATH_BOOLEAN:
4166 valuePush(ctxt, arg);
4167 xmlXPathBooleanFunction(ctxt, 1);
4168 valuePush(ctxt, val);
4169 return(xmlXPathCompareValues(ctxt, inf, strict));
4170 default:
4171 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004172 }
4173 return(0);
4174}
4175
4176/**
4177 * xmlXPathEqualNodeSetString
4178 * @arg: the nodeset object argument
4179 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004180 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004181 *
4182 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4183 * If one object to be compared is a node-set and the other is a string,
4184 * then the comparison will be true if and only if there is a node in
4185 * the node-set such that the result of performing the comparison on the
4186 * string-value of the node and the other string is true.
4187 *
4188 * Returns 0 or 1 depending on the results of the test.
4189 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004190static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004191xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004192{
Owen Taylor3473f882001-02-23 17:55:21 +00004193 int i;
4194 xmlNodeSetPtr ns;
4195 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004196 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004197
4198 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004199 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4200 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004201 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004202 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004203 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004204 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004205 if (ns->nodeNr <= 0) {
4206 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004207 return(neq ^ 1);
4208 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004209 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004210 for (i = 0; i < ns->nodeNr; i++) {
4211 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4212 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4213 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4214 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004215 if (neq)
4216 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004217 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004218 } else if (neq) {
4219 if (str2 != NULL)
4220 xmlFree(str2);
4221 return (1);
4222 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004223 if (str2 != NULL)
4224 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004225 } else if (neq)
4226 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004227 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004228 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004229}
4230
4231/**
4232 * xmlXPathEqualNodeSetFloat
4233 * @arg: the nodeset object argument
4234 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004235 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004236 *
4237 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4238 * If one object to be compared is a node-set and the other is a number,
4239 * then the comparison will be true if and only if there is a node in
4240 * the node-set such that the result of performing the comparison on the
4241 * number to be compared and on the result of converting the string-value
4242 * of that node to a number using the number function is true.
4243 *
4244 * Returns 0 or 1 depending on the results of the test.
4245 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004246static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004247xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4248 xmlXPathObjectPtr arg, double f, int neq) {
4249 int i, ret=0;
4250 xmlNodeSetPtr ns;
4251 xmlChar *str2;
4252 xmlXPathObjectPtr val;
4253 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004254
4255 if ((arg == NULL) ||
4256 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4257 return(0);
4258
William M. Brack0c022ad2002-07-12 00:56:01 +00004259 ns = arg->nodesetval;
4260 if (ns != NULL) {
4261 for (i=0;i<ns->nodeNr;i++) {
4262 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4263 if (str2 != NULL) {
4264 valuePush(ctxt, xmlXPathNewString(str2));
4265 xmlFree(str2);
4266 xmlXPathNumberFunction(ctxt, 1);
4267 val = valuePop(ctxt);
4268 v = val->floatval;
4269 xmlXPathFreeObject(val);
4270 if (!xmlXPathIsNaN(v)) {
4271 if ((!neq) && (v==f)) {
4272 ret = 1;
4273 break;
4274 } else if ((neq) && (v!=f)) {
4275 ret = 1;
4276 break;
4277 }
4278 }
4279 }
4280 }
4281 }
4282
4283 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004284}
4285
4286
4287/**
4288 * xmlXPathEqualNodeSets
4289 * @arg1: first nodeset object argument
4290 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004291 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004292 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004293 * Implement the equal / not equal operation on XPath nodesets:
4294 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004295 * If both objects to be compared are node-sets, then the comparison
4296 * will be true if and only if there is a node in the first node-set and
4297 * a node in the second node-set such that the result of performing the
4298 * comparison on the string-values of the two nodes is true.
4299 *
4300 * (needless to say, this is a costly operation)
4301 *
4302 * Returns 0 or 1 depending on the results of the test.
4303 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004304static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004305xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004306 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004307 unsigned int *hashs1;
4308 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004309 xmlChar **values1;
4310 xmlChar **values2;
4311 int ret = 0;
4312 xmlNodeSetPtr ns1;
4313 xmlNodeSetPtr ns2;
4314
4315 if ((arg1 == NULL) ||
4316 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4317 return(0);
4318 if ((arg2 == NULL) ||
4319 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4320 return(0);
4321
4322 ns1 = arg1->nodesetval;
4323 ns2 = arg2->nodesetval;
4324
Daniel Veillard911f49a2001-04-07 15:39:35 +00004325 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004326 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004327 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004328 return(0);
4329
4330 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004331 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004332 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004333 if (neq == 0)
4334 for (i = 0;i < ns1->nodeNr;i++)
4335 for (j = 0;j < ns2->nodeNr;j++)
4336 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4337 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004338
4339 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4340 if (values1 == NULL)
4341 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004342 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4343 if (hashs1 == NULL) {
4344 xmlFree(values1);
4345 return(0);
4346 }
Owen Taylor3473f882001-02-23 17:55:21 +00004347 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4348 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4349 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004350 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004351 xmlFree(values1);
4352 return(0);
4353 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004354 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4355 if (hashs2 == NULL) {
4356 xmlFree(hashs1);
4357 xmlFree(values1);
4358 xmlFree(values2);
4359 return(0);
4360 }
Owen Taylor3473f882001-02-23 17:55:21 +00004361 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4362 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004363 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004364 for (j = 0;j < ns2->nodeNr;j++) {
4365 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004366 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004367 if (hashs1[i] != hashs2[j]) {
4368 if (neq) {
4369 ret = 1;
4370 break;
4371 }
4372 }
4373 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004374 if (values1[i] == NULL)
4375 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4376 if (values2[j] == NULL)
4377 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004378 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004379 if (ret)
4380 break;
4381 }
Owen Taylor3473f882001-02-23 17:55:21 +00004382 }
4383 if (ret)
4384 break;
4385 }
4386 for (i = 0;i < ns1->nodeNr;i++)
4387 if (values1[i] != NULL)
4388 xmlFree(values1[i]);
4389 for (j = 0;j < ns2->nodeNr;j++)
4390 if (values2[j] != NULL)
4391 xmlFree(values2[j]);
4392 xmlFree(values1);
4393 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004394 xmlFree(hashs1);
4395 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004396 return(ret);
4397}
4398
William M. Brack0c022ad2002-07-12 00:56:01 +00004399static int
4400xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4401 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004402 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004403 /*
4404 *At this point we are assured neither arg1 nor arg2
4405 *is a nodeset, so we can just pick the appropriate routine.
4406 */
Owen Taylor3473f882001-02-23 17:55:21 +00004407 switch (arg1->type) {
4408 case XPATH_UNDEFINED:
4409#ifdef DEBUG_EXPR
4410 xmlGenericError(xmlGenericErrorContext,
4411 "Equal: undefined\n");
4412#endif
4413 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004414 case XPATH_BOOLEAN:
4415 switch (arg2->type) {
4416 case XPATH_UNDEFINED:
4417#ifdef DEBUG_EXPR
4418 xmlGenericError(xmlGenericErrorContext,
4419 "Equal: undefined\n");
4420#endif
4421 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004422 case XPATH_BOOLEAN:
4423#ifdef DEBUG_EXPR
4424 xmlGenericError(xmlGenericErrorContext,
4425 "Equal: %d boolean %d \n",
4426 arg1->boolval, arg2->boolval);
4427#endif
4428 ret = (arg1->boolval == arg2->boolval);
4429 break;
4430 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004431 ret = (arg1->boolval ==
4432 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004433 break;
4434 case XPATH_STRING:
4435 if ((arg2->stringval == NULL) ||
4436 (arg2->stringval[0] == 0)) ret = 0;
4437 else
4438 ret = 1;
4439 ret = (arg1->boolval == ret);
4440 break;
4441 case XPATH_USERS:
4442 case XPATH_POINT:
4443 case XPATH_RANGE:
4444 case XPATH_LOCATIONSET:
4445 TODO
4446 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004447 case XPATH_NODESET:
4448 case XPATH_XSLT_TREE:
4449 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004450 }
4451 break;
4452 case XPATH_NUMBER:
4453 switch (arg2->type) {
4454 case XPATH_UNDEFINED:
4455#ifdef DEBUG_EXPR
4456 xmlGenericError(xmlGenericErrorContext,
4457 "Equal: undefined\n");
4458#endif
4459 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004460 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004461 ret = (arg2->boolval==
4462 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004463 break;
4464 case XPATH_STRING:
4465 valuePush(ctxt, arg2);
4466 xmlXPathNumberFunction(ctxt, 1);
4467 arg2 = valuePop(ctxt);
4468 /* no break on purpose */
4469 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004470 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004471 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4472 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004473 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4474 if (xmlXPathIsInf(arg2->floatval) == 1)
4475 ret = 1;
4476 else
4477 ret = 0;
4478 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4479 if (xmlXPathIsInf(arg2->floatval) == -1)
4480 ret = 1;
4481 else
4482 ret = 0;
4483 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4484 if (xmlXPathIsInf(arg1->floatval) == 1)
4485 ret = 1;
4486 else
4487 ret = 0;
4488 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4489 if (xmlXPathIsInf(arg1->floatval) == -1)
4490 ret = 1;
4491 else
4492 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004493 } else {
4494 ret = (arg1->floatval == arg2->floatval);
4495 }
Owen Taylor3473f882001-02-23 17:55:21 +00004496 break;
4497 case XPATH_USERS:
4498 case XPATH_POINT:
4499 case XPATH_RANGE:
4500 case XPATH_LOCATIONSET:
4501 TODO
4502 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004503 case XPATH_NODESET:
4504 case XPATH_XSLT_TREE:
4505 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004506 }
4507 break;
4508 case XPATH_STRING:
4509 switch (arg2->type) {
4510 case XPATH_UNDEFINED:
4511#ifdef DEBUG_EXPR
4512 xmlGenericError(xmlGenericErrorContext,
4513 "Equal: undefined\n");
4514#endif
4515 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004516 case XPATH_BOOLEAN:
4517 if ((arg1->stringval == NULL) ||
4518 (arg1->stringval[0] == 0)) ret = 0;
4519 else
4520 ret = 1;
4521 ret = (arg2->boolval == ret);
4522 break;
4523 case XPATH_STRING:
4524 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4525 break;
4526 case XPATH_NUMBER:
4527 valuePush(ctxt, arg1);
4528 xmlXPathNumberFunction(ctxt, 1);
4529 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004530 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004531 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4532 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004533 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4534 if (xmlXPathIsInf(arg2->floatval) == 1)
4535 ret = 1;
4536 else
4537 ret = 0;
4538 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4539 if (xmlXPathIsInf(arg2->floatval) == -1)
4540 ret = 1;
4541 else
4542 ret = 0;
4543 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4544 if (xmlXPathIsInf(arg1->floatval) == 1)
4545 ret = 1;
4546 else
4547 ret = 0;
4548 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4549 if (xmlXPathIsInf(arg1->floatval) == -1)
4550 ret = 1;
4551 else
4552 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004553 } else {
4554 ret = (arg1->floatval == arg2->floatval);
4555 }
Owen Taylor3473f882001-02-23 17:55:21 +00004556 break;
4557 case XPATH_USERS:
4558 case XPATH_POINT:
4559 case XPATH_RANGE:
4560 case XPATH_LOCATIONSET:
4561 TODO
4562 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004563 case XPATH_NODESET:
4564 case XPATH_XSLT_TREE:
4565 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004566 }
4567 break;
4568 case XPATH_USERS:
4569 case XPATH_POINT:
4570 case XPATH_RANGE:
4571 case XPATH_LOCATIONSET:
4572 TODO
4573 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004574 case XPATH_NODESET:
4575 case XPATH_XSLT_TREE:
4576 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004577 }
4578 xmlXPathFreeObject(arg1);
4579 xmlXPathFreeObject(arg2);
4580 return(ret);
4581}
4582
William M. Brack0c022ad2002-07-12 00:56:01 +00004583/**
4584 * xmlXPathEqualValues:
4585 * @ctxt: the XPath Parser context
4586 *
4587 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4588 *
4589 * Returns 0 or 1 depending on the results of the test.
4590 */
4591int
4592xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4593 xmlXPathObjectPtr arg1, arg2, argtmp;
4594 int ret = 0;
4595
4596 arg2 = valuePop(ctxt);
4597 arg1 = valuePop(ctxt);
4598 if ((arg1 == NULL) || (arg2 == NULL)) {
4599 if (arg1 != NULL)
4600 xmlXPathFreeObject(arg1);
4601 else
4602 xmlXPathFreeObject(arg2);
4603 XP_ERROR0(XPATH_INVALID_OPERAND);
4604 }
4605
4606 if (arg1 == arg2) {
4607#ifdef DEBUG_EXPR
4608 xmlGenericError(xmlGenericErrorContext,
4609 "Equal: by pointer\n");
4610#endif
4611 return(1);
4612 }
4613
4614 /*
4615 *If either argument is a nodeset, it's a 'special case'
4616 */
4617 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4618 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4619 /*
4620 *Hack it to assure arg1 is the nodeset
4621 */
4622 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4623 argtmp = arg2;
4624 arg2 = arg1;
4625 arg1 = argtmp;
4626 }
4627 switch (arg2->type) {
4628 case XPATH_UNDEFINED:
4629#ifdef DEBUG_EXPR
4630 xmlGenericError(xmlGenericErrorContext,
4631 "Equal: undefined\n");
4632#endif
4633 break;
4634 case XPATH_NODESET:
4635 case XPATH_XSLT_TREE:
4636 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4637 break;
4638 case XPATH_BOOLEAN:
4639 if ((arg1->nodesetval == NULL) ||
4640 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4641 else
4642 ret = 1;
4643 ret = (ret == arg2->boolval);
4644 break;
4645 case XPATH_NUMBER:
4646 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4647 break;
4648 case XPATH_STRING:
4649 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4650 break;
4651 case XPATH_USERS:
4652 case XPATH_POINT:
4653 case XPATH_RANGE:
4654 case XPATH_LOCATIONSET:
4655 TODO
4656 break;
4657 }
4658 xmlXPathFreeObject(arg1);
4659 xmlXPathFreeObject(arg2);
4660 return(ret);
4661 }
4662
4663 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4664}
4665
4666/**
4667 * xmlXPathNotEqualValues:
4668 * @ctxt: the XPath Parser context
4669 *
4670 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4671 *
4672 * Returns 0 or 1 depending on the results of the test.
4673 */
4674int
4675xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4676 xmlXPathObjectPtr arg1, arg2, argtmp;
4677 int ret = 0;
4678
4679 arg2 = valuePop(ctxt);
4680 arg1 = valuePop(ctxt);
4681 if ((arg1 == NULL) || (arg2 == NULL)) {
4682 if (arg1 != NULL)
4683 xmlXPathFreeObject(arg1);
4684 else
4685 xmlXPathFreeObject(arg2);
4686 XP_ERROR0(XPATH_INVALID_OPERAND);
4687 }
4688
4689 if (arg1 == arg2) {
4690#ifdef DEBUG_EXPR
4691 xmlGenericError(xmlGenericErrorContext,
4692 "NotEqual: by pointer\n");
4693#endif
4694 return(0);
4695 }
4696
4697 /*
4698 *If either argument is a nodeset, it's a 'special case'
4699 */
4700 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4701 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4702 /*
4703 *Hack it to assure arg1 is the nodeset
4704 */
4705 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4706 argtmp = arg2;
4707 arg2 = arg1;
4708 arg1 = argtmp;
4709 }
4710 switch (arg2->type) {
4711 case XPATH_UNDEFINED:
4712#ifdef DEBUG_EXPR
4713 xmlGenericError(xmlGenericErrorContext,
4714 "NotEqual: undefined\n");
4715#endif
4716 break;
4717 case XPATH_NODESET:
4718 case XPATH_XSLT_TREE:
4719 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4720 break;
4721 case XPATH_BOOLEAN:
4722 if ((arg1->nodesetval == NULL) ||
4723 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4724 else
4725 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004726 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004727 break;
4728 case XPATH_NUMBER:
4729 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4730 break;
4731 case XPATH_STRING:
4732 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4733 break;
4734 case XPATH_USERS:
4735 case XPATH_POINT:
4736 case XPATH_RANGE:
4737 case XPATH_LOCATIONSET:
4738 TODO
4739 break;
4740 }
4741 xmlXPathFreeObject(arg1);
4742 xmlXPathFreeObject(arg2);
4743 return(ret);
4744 }
4745
4746 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4747}
Owen Taylor3473f882001-02-23 17:55:21 +00004748
4749/**
4750 * xmlXPathCompareValues:
4751 * @ctxt: the XPath Parser context
4752 * @inf: less than (1) or greater than (0)
4753 * @strict: is the comparison strict
4754 *
4755 * Implement the compare operation on XPath objects:
4756 * @arg1 < @arg2 (1, 1, ...
4757 * @arg1 <= @arg2 (1, 0, ...
4758 * @arg1 > @arg2 (0, 1, ...
4759 * @arg1 >= @arg2 (0, 0, ...
4760 *
4761 * When neither object to be compared is a node-set and the operator is
4762 * <=, <, >=, >, then the objects are compared by converted both objects
4763 * to numbers and comparing the numbers according to IEEE 754. The <
4764 * comparison will be true if and only if the first number is less than the
4765 * second number. The <= comparison will be true if and only if the first
4766 * number is less than or equal to the second number. The > comparison
4767 * will be true if and only if the first number is greater than the second
4768 * number. The >= comparison will be true if and only if the first number
4769 * is greater than or equal to the second number.
4770 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004771 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004772 */
4773int
4774xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004775 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004776 xmlXPathObjectPtr arg1, arg2;
4777
William M. Brack0c022ad2002-07-12 00:56:01 +00004778 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004779 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004780 if ((arg1 == NULL) || (arg2 == NULL)) {
4781 if (arg1 != NULL)
4782 xmlXPathFreeObject(arg1);
4783 else
4784 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004785 XP_ERROR0(XPATH_INVALID_OPERAND);
4786 }
4787
William M. Brack0c022ad2002-07-12 00:56:01 +00004788 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4789 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4790 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4791 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004792 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004793 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004794 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004795 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4796 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004797 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004798 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4799 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004800 }
4801 }
4802 return(ret);
4803 }
4804
4805 if (arg1->type != XPATH_NUMBER) {
4806 valuePush(ctxt, arg1);
4807 xmlXPathNumberFunction(ctxt, 1);
4808 arg1 = valuePop(ctxt);
4809 }
4810 if (arg1->type != XPATH_NUMBER) {
4811 xmlXPathFreeObject(arg1);
4812 xmlXPathFreeObject(arg2);
4813 XP_ERROR0(XPATH_INVALID_OPERAND);
4814 }
4815 if (arg2->type != XPATH_NUMBER) {
4816 valuePush(ctxt, arg2);
4817 xmlXPathNumberFunction(ctxt, 1);
4818 arg2 = valuePop(ctxt);
4819 }
4820 if (arg2->type != XPATH_NUMBER) {
4821 xmlXPathFreeObject(arg1);
4822 xmlXPathFreeObject(arg2);
4823 XP_ERROR0(XPATH_INVALID_OPERAND);
4824 }
4825 /*
4826 * Add tests for infinity and nan
4827 * => feedback on 3.4 for Inf and NaN
4828 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004829 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004830 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004831 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004832 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004833 arg1i=xmlXPathIsInf(arg1->floatval);
4834 arg2i=xmlXPathIsInf(arg2->floatval);
4835 if (inf && strict) {
4836 if ((arg1i == -1 && arg2i != -1) ||
4837 (arg2i == 1 && arg1i != 1)) {
4838 ret = 1;
4839 } else if (arg1i == 0 && arg2i == 0) {
4840 ret = (arg1->floatval < arg2->floatval);
4841 } else {
4842 ret = 0;
4843 }
4844 }
4845 else if (inf && !strict) {
4846 if (arg1i == -1 || arg2i == 1) {
4847 ret = 1;
4848 } else if (arg1i == 0 && arg2i == 0) {
4849 ret = (arg1->floatval <= arg2->floatval);
4850 } else {
4851 ret = 0;
4852 }
4853 }
4854 else if (!inf && strict) {
4855 if ((arg1i == 1 && arg2i != 1) ||
4856 (arg2i == -1 && arg1i != -1)) {
4857 ret = 1;
4858 } else if (arg1i == 0 && arg2i == 0) {
4859 ret = (arg1->floatval > arg2->floatval);
4860 } else {
4861 ret = 0;
4862 }
4863 }
4864 else if (!inf && !strict) {
4865 if (arg1i == 1 || arg2i == -1) {
4866 ret = 1;
4867 } else if (arg1i == 0 && arg2i == 0) {
4868 ret = (arg1->floatval >= arg2->floatval);
4869 } else {
4870 ret = 0;
4871 }
4872 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004873 }
Owen Taylor3473f882001-02-23 17:55:21 +00004874 xmlXPathFreeObject(arg1);
4875 xmlXPathFreeObject(arg2);
4876 return(ret);
4877}
4878
4879/**
4880 * xmlXPathValueFlipSign:
4881 * @ctxt: the XPath Parser context
4882 *
4883 * Implement the unary - operation on an XPath object
4884 * The numeric operators convert their operands to numbers as if
4885 * by calling the number function.
4886 */
4887void
4888xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004889 CAST_TO_NUMBER;
4890 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004891 if (xmlXPathIsNaN(ctxt->value->floatval))
4892 ctxt->value->floatval=xmlXPathNAN;
4893 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4894 ctxt->value->floatval=xmlXPathNINF;
4895 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4896 ctxt->value->floatval=xmlXPathPINF;
4897 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004898 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4899 ctxt->value->floatval = xmlXPathNZERO;
4900 else
4901 ctxt->value->floatval = 0;
4902 }
4903 else
4904 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004905}
4906
4907/**
4908 * xmlXPathAddValues:
4909 * @ctxt: the XPath Parser context
4910 *
4911 * Implement the add operation on XPath objects:
4912 * The numeric operators convert their operands to numbers as if
4913 * by calling the number function.
4914 */
4915void
4916xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4917 xmlXPathObjectPtr arg;
4918 double val;
4919
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004920 arg = valuePop(ctxt);
4921 if (arg == NULL)
4922 XP_ERROR(XPATH_INVALID_OPERAND);
4923 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004924 xmlXPathFreeObject(arg);
4925
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004926 CAST_TO_NUMBER;
4927 CHECK_TYPE(XPATH_NUMBER);
4928 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004929}
4930
4931/**
4932 * xmlXPathSubValues:
4933 * @ctxt: the XPath Parser context
4934 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004935 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004936 * The numeric operators convert their operands to numbers as if
4937 * by calling the number function.
4938 */
4939void
4940xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4941 xmlXPathObjectPtr arg;
4942 double val;
4943
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004944 arg = valuePop(ctxt);
4945 if (arg == NULL)
4946 XP_ERROR(XPATH_INVALID_OPERAND);
4947 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004948 xmlXPathFreeObject(arg);
4949
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004950 CAST_TO_NUMBER;
4951 CHECK_TYPE(XPATH_NUMBER);
4952 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004953}
4954
4955/**
4956 * xmlXPathMultValues:
4957 * @ctxt: the XPath Parser context
4958 *
4959 * Implement the multiply operation on XPath objects:
4960 * The numeric operators convert their operands to numbers as if
4961 * by calling the number function.
4962 */
4963void
4964xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4965 xmlXPathObjectPtr arg;
4966 double val;
4967
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004968 arg = valuePop(ctxt);
4969 if (arg == NULL)
4970 XP_ERROR(XPATH_INVALID_OPERAND);
4971 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004972 xmlXPathFreeObject(arg);
4973
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004974 CAST_TO_NUMBER;
4975 CHECK_TYPE(XPATH_NUMBER);
4976 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004977}
4978
4979/**
4980 * xmlXPathDivValues:
4981 * @ctxt: the XPath Parser context
4982 *
4983 * Implement the div operation on XPath objects @arg1 / @arg2:
4984 * The numeric operators convert their operands to numbers as if
4985 * by calling the number function.
4986 */
4987void
4988xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4989 xmlXPathObjectPtr arg;
4990 double val;
4991
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004992 arg = valuePop(ctxt);
4993 if (arg == NULL)
4994 XP_ERROR(XPATH_INVALID_OPERAND);
4995 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004996 xmlXPathFreeObject(arg);
4997
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004998 CAST_TO_NUMBER;
4999 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005000 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5001 ctxt->value->floatval = xmlXPathNAN;
5002 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005003 if (ctxt->value->floatval == 0)
5004 ctxt->value->floatval = xmlXPathNAN;
5005 else if (ctxt->value->floatval > 0)
5006 ctxt->value->floatval = xmlXPathNINF;
5007 else if (ctxt->value->floatval < 0)
5008 ctxt->value->floatval = xmlXPathPINF;
5009 }
5010 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005011 if (ctxt->value->floatval == 0)
5012 ctxt->value->floatval = xmlXPathNAN;
5013 else if (ctxt->value->floatval > 0)
5014 ctxt->value->floatval = xmlXPathPINF;
5015 else if (ctxt->value->floatval < 0)
5016 ctxt->value->floatval = xmlXPathNINF;
5017 } else
5018 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005019}
5020
5021/**
5022 * xmlXPathModValues:
5023 * @ctxt: the XPath Parser context
5024 *
5025 * Implement the mod operation on XPath objects: @arg1 / @arg2
5026 * The numeric operators convert their operands to numbers as if
5027 * by calling the number function.
5028 */
5029void
5030xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5031 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005032 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005033
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005034 arg = valuePop(ctxt);
5035 if (arg == NULL)
5036 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005037 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005038 xmlXPathFreeObject(arg);
5039
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005040 CAST_TO_NUMBER;
5041 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005042 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005043 if (arg2 == 0)
5044 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005045 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005046 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005047 }
Owen Taylor3473f882001-02-23 17:55:21 +00005048}
5049
5050/************************************************************************
5051 * *
5052 * The traversal functions *
5053 * *
5054 ************************************************************************/
5055
Owen Taylor3473f882001-02-23 17:55:21 +00005056/*
5057 * A traversal function enumerates nodes along an axis.
5058 * Initially it must be called with NULL, and it indicates
5059 * termination on the axis by returning NULL.
5060 */
5061typedef xmlNodePtr (*xmlXPathTraversalFunction)
5062 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5063
5064/**
5065 * xmlXPathNextSelf:
5066 * @ctxt: the XPath Parser context
5067 * @cur: the current node in the traversal
5068 *
5069 * Traversal function for the "self" direction
5070 * The self axis contains just the context node itself
5071 *
5072 * Returns the next element following that axis
5073 */
5074xmlNodePtr
5075xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5076 if (cur == NULL)
5077 return(ctxt->context->node);
5078 return(NULL);
5079}
5080
5081/**
5082 * xmlXPathNextChild:
5083 * @ctxt: the XPath Parser context
5084 * @cur: the current node in the traversal
5085 *
5086 * Traversal function for the "child" direction
5087 * The child axis contains the children of the context node in document order.
5088 *
5089 * Returns the next element following that axis
5090 */
5091xmlNodePtr
5092xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5093 if (cur == NULL) {
5094 if (ctxt->context->node == NULL) return(NULL);
5095 switch (ctxt->context->node->type) {
5096 case XML_ELEMENT_NODE:
5097 case XML_TEXT_NODE:
5098 case XML_CDATA_SECTION_NODE:
5099 case XML_ENTITY_REF_NODE:
5100 case XML_ENTITY_NODE:
5101 case XML_PI_NODE:
5102 case XML_COMMENT_NODE:
5103 case XML_NOTATION_NODE:
5104 case XML_DTD_NODE:
5105 return(ctxt->context->node->children);
5106 case XML_DOCUMENT_NODE:
5107 case XML_DOCUMENT_TYPE_NODE:
5108 case XML_DOCUMENT_FRAG_NODE:
5109 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005110#ifdef LIBXML_DOCB_ENABLED
5111 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005112#endif
5113 return(((xmlDocPtr) ctxt->context->node)->children);
5114 case XML_ELEMENT_DECL:
5115 case XML_ATTRIBUTE_DECL:
5116 case XML_ENTITY_DECL:
5117 case XML_ATTRIBUTE_NODE:
5118 case XML_NAMESPACE_DECL:
5119 case XML_XINCLUDE_START:
5120 case XML_XINCLUDE_END:
5121 return(NULL);
5122 }
5123 return(NULL);
5124 }
5125 if ((cur->type == XML_DOCUMENT_NODE) ||
5126 (cur->type == XML_HTML_DOCUMENT_NODE))
5127 return(NULL);
5128 return(cur->next);
5129}
5130
5131/**
5132 * xmlXPathNextDescendant:
5133 * @ctxt: the XPath Parser context
5134 * @cur: the current node in the traversal
5135 *
5136 * Traversal function for the "descendant" direction
5137 * the descendant axis contains the descendants of the context node in document
5138 * order; a descendant is a child or a child of a child and so on.
5139 *
5140 * Returns the next element following that axis
5141 */
5142xmlNodePtr
5143xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5144 if (cur == NULL) {
5145 if (ctxt->context->node == NULL)
5146 return(NULL);
5147 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5148 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5149 return(NULL);
5150
5151 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5152 return(ctxt->context->doc->children);
5153 return(ctxt->context->node->children);
5154 }
5155
Daniel Veillard567e1b42001-08-01 15:53:47 +00005156 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005157 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00005158 return(cur->children);
5159 }
5160
5161 if (cur == ctxt->context->node) return(NULL);
5162
Owen Taylor3473f882001-02-23 17:55:21 +00005163 if (cur->next != NULL) return(cur->next);
5164
5165 do {
5166 cur = cur->parent;
5167 if (cur == NULL) return(NULL);
5168 if (cur == ctxt->context->node) return(NULL);
5169 if (cur->next != NULL) {
5170 cur = cur->next;
5171 return(cur);
5172 }
5173 } while (cur != NULL);
5174 return(cur);
5175}
5176
5177/**
5178 * xmlXPathNextDescendantOrSelf:
5179 * @ctxt: the XPath Parser context
5180 * @cur: the current node in the traversal
5181 *
5182 * Traversal function for the "descendant-or-self" direction
5183 * the descendant-or-self axis contains the context node and the descendants
5184 * of the context node in document order; thus the context node is the first
5185 * node on the axis, and the first child of the context node is the second node
5186 * on the axis
5187 *
5188 * Returns the next element following that axis
5189 */
5190xmlNodePtr
5191xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5192 if (cur == NULL) {
5193 if (ctxt->context->node == NULL)
5194 return(NULL);
5195 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5196 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5197 return(NULL);
5198 return(ctxt->context->node);
5199 }
5200
5201 return(xmlXPathNextDescendant(ctxt, cur));
5202}
5203
5204/**
5205 * xmlXPathNextParent:
5206 * @ctxt: the XPath Parser context
5207 * @cur: the current node in the traversal
5208 *
5209 * Traversal function for the "parent" direction
5210 * The parent axis contains the parent of the context node, if there is one.
5211 *
5212 * Returns the next element following that axis
5213 */
5214xmlNodePtr
5215xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5216 /*
5217 * the parent of an attribute or namespace node is the element
5218 * to which the attribute or namespace node is attached
5219 * Namespace handling !!!
5220 */
5221 if (cur == NULL) {
5222 if (ctxt->context->node == NULL) return(NULL);
5223 switch (ctxt->context->node->type) {
5224 case XML_ELEMENT_NODE:
5225 case XML_TEXT_NODE:
5226 case XML_CDATA_SECTION_NODE:
5227 case XML_ENTITY_REF_NODE:
5228 case XML_ENTITY_NODE:
5229 case XML_PI_NODE:
5230 case XML_COMMENT_NODE:
5231 case XML_NOTATION_NODE:
5232 case XML_DTD_NODE:
5233 case XML_ELEMENT_DECL:
5234 case XML_ATTRIBUTE_DECL:
5235 case XML_XINCLUDE_START:
5236 case XML_XINCLUDE_END:
5237 case XML_ENTITY_DECL:
5238 if (ctxt->context->node->parent == NULL)
5239 return((xmlNodePtr) ctxt->context->doc);
5240 return(ctxt->context->node->parent);
5241 case XML_ATTRIBUTE_NODE: {
5242 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5243
5244 return(att->parent);
5245 }
5246 case XML_DOCUMENT_NODE:
5247 case XML_DOCUMENT_TYPE_NODE:
5248 case XML_DOCUMENT_FRAG_NODE:
5249 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005250#ifdef LIBXML_DOCB_ENABLED
5251 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005252#endif
5253 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005254 case XML_NAMESPACE_DECL: {
5255 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5256
5257 if ((ns->next != NULL) &&
5258 (ns->next->type != XML_NAMESPACE_DECL))
5259 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005260 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005261 }
Owen Taylor3473f882001-02-23 17:55:21 +00005262 }
5263 }
5264 return(NULL);
5265}
5266
5267/**
5268 * xmlXPathNextAncestor:
5269 * @ctxt: the XPath Parser context
5270 * @cur: the current node in the traversal
5271 *
5272 * Traversal function for the "ancestor" direction
5273 * the ancestor axis contains the ancestors of the context node; the ancestors
5274 * of the context node consist of the parent of context node and the parent's
5275 * parent and so on; the nodes are ordered in reverse document order; thus the
5276 * parent is the first node on the axis, and the parent's parent is the second
5277 * node on the axis
5278 *
5279 * Returns the next element following that axis
5280 */
5281xmlNodePtr
5282xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5283 /*
5284 * the parent of an attribute or namespace node is the element
5285 * to which the attribute or namespace node is attached
5286 * !!!!!!!!!!!!!
5287 */
5288 if (cur == NULL) {
5289 if (ctxt->context->node == NULL) return(NULL);
5290 switch (ctxt->context->node->type) {
5291 case XML_ELEMENT_NODE:
5292 case XML_TEXT_NODE:
5293 case XML_CDATA_SECTION_NODE:
5294 case XML_ENTITY_REF_NODE:
5295 case XML_ENTITY_NODE:
5296 case XML_PI_NODE:
5297 case XML_COMMENT_NODE:
5298 case XML_DTD_NODE:
5299 case XML_ELEMENT_DECL:
5300 case XML_ATTRIBUTE_DECL:
5301 case XML_ENTITY_DECL:
5302 case XML_NOTATION_NODE:
5303 case XML_XINCLUDE_START:
5304 case XML_XINCLUDE_END:
5305 if (ctxt->context->node->parent == NULL)
5306 return((xmlNodePtr) ctxt->context->doc);
5307 return(ctxt->context->node->parent);
5308 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005309 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005310
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005311 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005312 }
5313 case XML_DOCUMENT_NODE:
5314 case XML_DOCUMENT_TYPE_NODE:
5315 case XML_DOCUMENT_FRAG_NODE:
5316 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005317#ifdef LIBXML_DOCB_ENABLED
5318 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005319#endif
5320 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005321 case XML_NAMESPACE_DECL: {
5322 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5323
5324 if ((ns->next != NULL) &&
5325 (ns->next->type != XML_NAMESPACE_DECL))
5326 return((xmlNodePtr) ns->next);
5327 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005328 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005329 }
Owen Taylor3473f882001-02-23 17:55:21 +00005330 }
5331 return(NULL);
5332 }
5333 if (cur == ctxt->context->doc->children)
5334 return((xmlNodePtr) ctxt->context->doc);
5335 if (cur == (xmlNodePtr) ctxt->context->doc)
5336 return(NULL);
5337 switch (cur->type) {
5338 case XML_ELEMENT_NODE:
5339 case XML_TEXT_NODE:
5340 case XML_CDATA_SECTION_NODE:
5341 case XML_ENTITY_REF_NODE:
5342 case XML_ENTITY_NODE:
5343 case XML_PI_NODE:
5344 case XML_COMMENT_NODE:
5345 case XML_NOTATION_NODE:
5346 case XML_DTD_NODE:
5347 case XML_ELEMENT_DECL:
5348 case XML_ATTRIBUTE_DECL:
5349 case XML_ENTITY_DECL:
5350 case XML_XINCLUDE_START:
5351 case XML_XINCLUDE_END:
5352 return(cur->parent);
5353 case XML_ATTRIBUTE_NODE: {
5354 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5355
5356 return(att->parent);
5357 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005358 case XML_NAMESPACE_DECL: {
5359 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5360
5361 if ((ns->next != NULL) &&
5362 (ns->next->type != XML_NAMESPACE_DECL))
5363 return((xmlNodePtr) ns->next);
5364 /* Bad, how did that namespace ended-up there ? */
5365 return(NULL);
5366 }
Owen Taylor3473f882001-02-23 17:55:21 +00005367 case XML_DOCUMENT_NODE:
5368 case XML_DOCUMENT_TYPE_NODE:
5369 case XML_DOCUMENT_FRAG_NODE:
5370 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005371#ifdef LIBXML_DOCB_ENABLED
5372 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005373#endif
5374 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005375 }
5376 return(NULL);
5377}
5378
5379/**
5380 * xmlXPathNextAncestorOrSelf:
5381 * @ctxt: the XPath Parser context
5382 * @cur: the current node in the traversal
5383 *
5384 * Traversal function for the "ancestor-or-self" direction
5385 * he ancestor-or-self axis contains the context node and ancestors of
5386 * the context node in reverse document order; thus the context node is
5387 * the first node on the axis, and the context node's parent the second;
5388 * parent here is defined the same as with the parent axis.
5389 *
5390 * Returns the next element following that axis
5391 */
5392xmlNodePtr
5393xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5394 if (cur == NULL)
5395 return(ctxt->context->node);
5396 return(xmlXPathNextAncestor(ctxt, cur));
5397}
5398
5399/**
5400 * xmlXPathNextFollowingSibling:
5401 * @ctxt: the XPath Parser context
5402 * @cur: the current node in the traversal
5403 *
5404 * Traversal function for the "following-sibling" direction
5405 * The following-sibling axis contains the following siblings of the context
5406 * node in document order.
5407 *
5408 * Returns the next element following that axis
5409 */
5410xmlNodePtr
5411xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5412 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5413 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5414 return(NULL);
5415 if (cur == (xmlNodePtr) ctxt->context->doc)
5416 return(NULL);
5417 if (cur == NULL)
5418 return(ctxt->context->node->next);
5419 return(cur->next);
5420}
5421
5422/**
5423 * xmlXPathNextPrecedingSibling:
5424 * @ctxt: the XPath Parser context
5425 * @cur: the current node in the traversal
5426 *
5427 * Traversal function for the "preceding-sibling" direction
5428 * The preceding-sibling axis contains the preceding siblings of the context
5429 * node in reverse document order; the first preceding sibling is first on the
5430 * axis; the sibling preceding that node is the second on the axis and so on.
5431 *
5432 * Returns the next element following that axis
5433 */
5434xmlNodePtr
5435xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5436 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5437 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5438 return(NULL);
5439 if (cur == (xmlNodePtr) ctxt->context->doc)
5440 return(NULL);
5441 if (cur == NULL)
5442 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005443 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5444 cur = cur->prev;
5445 if (cur == NULL)
5446 return(ctxt->context->node->prev);
5447 }
Owen Taylor3473f882001-02-23 17:55:21 +00005448 return(cur->prev);
5449}
5450
5451/**
5452 * xmlXPathNextFollowing:
5453 * @ctxt: the XPath Parser context
5454 * @cur: the current node in the traversal
5455 *
5456 * Traversal function for the "following" direction
5457 * The following axis contains all nodes in the same document as the context
5458 * node that are after the context node in document order, excluding any
5459 * descendants and excluding attribute nodes and namespace nodes; the nodes
5460 * are ordered in document order
5461 *
5462 * Returns the next element following that axis
5463 */
5464xmlNodePtr
5465xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5466 if (cur != NULL && cur->children != NULL)
5467 return cur->children ;
5468 if (cur == NULL) cur = ctxt->context->node;
5469 if (cur == NULL) return(NULL) ; /* ERROR */
5470 if (cur->next != NULL) return(cur->next) ;
5471 do {
5472 cur = cur->parent;
5473 if (cur == NULL) return(NULL);
5474 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5475 if (cur->next != NULL) return(cur->next);
5476 } while (cur != NULL);
5477 return(cur);
5478}
5479
5480/*
5481 * xmlXPathIsAncestor:
5482 * @ancestor: the ancestor node
5483 * @node: the current node
5484 *
5485 * Check that @ancestor is a @node's ancestor
5486 *
5487 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5488 */
5489static int
5490xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5491 if ((ancestor == NULL) || (node == NULL)) return(0);
5492 /* nodes need to be in the same document */
5493 if (ancestor->doc != node->doc) return(0);
5494 /* avoid searching if ancestor or node is the root node */
5495 if (ancestor == (xmlNodePtr) node->doc) return(1);
5496 if (node == (xmlNodePtr) ancestor->doc) return(0);
5497 while (node->parent != NULL) {
5498 if (node->parent == ancestor)
5499 return(1);
5500 node = node->parent;
5501 }
5502 return(0);
5503}
5504
5505/**
5506 * xmlXPathNextPreceding:
5507 * @ctxt: the XPath Parser context
5508 * @cur: the current node in the traversal
5509 *
5510 * Traversal function for the "preceding" direction
5511 * the preceding axis contains all nodes in the same document as the context
5512 * node that are before the context node in document order, excluding any
5513 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5514 * ordered in reverse document order
5515 *
5516 * Returns the next element following that axis
5517 */
5518xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005519xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5520{
Owen Taylor3473f882001-02-23 17:55:21 +00005521 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005522 cur = ctxt->context->node;
5523 if (cur == NULL)
5524 return (NULL);
5525 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5526 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005527 do {
5528 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005529 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5530 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005531 }
5532
5533 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005534 if (cur == NULL)
5535 return (NULL);
5536 if (cur == ctxt->context->doc->children)
5537 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005538 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005539 return (cur);
5540}
5541
5542/**
5543 * xmlXPathNextPrecedingInternal:
5544 * @ctxt: the XPath Parser context
5545 * @cur: the current node in the traversal
5546 *
5547 * Traversal function for the "preceding" direction
5548 * the preceding axis contains all nodes in the same document as the context
5549 * node that are before the context node in document order, excluding any
5550 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5551 * ordered in reverse document order
5552 * This is a faster implementation but internal only since it requires a
5553 * state kept in the parser context: ctxt->ancestor.
5554 *
5555 * Returns the next element following that axis
5556 */
5557static xmlNodePtr
5558xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5559 xmlNodePtr cur)
5560{
5561 if (cur == NULL) {
5562 cur = ctxt->context->node;
5563 if (cur == NULL)
5564 return (NULL);
5565 ctxt->ancestor = cur->parent;
5566 }
5567 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5568 cur = cur->prev;
5569 while (cur->prev == NULL) {
5570 cur = cur->parent;
5571 if (cur == NULL)
5572 return (NULL);
5573 if (cur == ctxt->context->doc->children)
5574 return (NULL);
5575 if (cur != ctxt->ancestor)
5576 return (cur);
5577 ctxt->ancestor = cur->parent;
5578 }
5579 cur = cur->prev;
5580 while (cur->last != NULL)
5581 cur = cur->last;
5582 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005583}
5584
5585/**
5586 * xmlXPathNextNamespace:
5587 * @ctxt: the XPath Parser context
5588 * @cur: the current attribute in the traversal
5589 *
5590 * Traversal function for the "namespace" direction
5591 * the namespace axis contains the namespace nodes of the context node;
5592 * the order of nodes on this axis is implementation-defined; the axis will
5593 * be empty unless the context node is an element
5594 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005595 * We keep the XML namespace node at the end of the list.
5596 *
Owen Taylor3473f882001-02-23 17:55:21 +00005597 * Returns the next element following that axis
5598 */
5599xmlNodePtr
5600xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5601 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005602 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005603 if (ctxt->context->tmpNsList != NULL)
5604 xmlFree(ctxt->context->tmpNsList);
5605 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005606 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005607 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005608 if (ctxt->context->tmpNsList != NULL) {
5609 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5610 ctxt->context->tmpNsNr++;
5611 }
5612 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005613 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005614 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005615 if (ctxt->context->tmpNsNr > 0) {
5616 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5617 } else {
5618 if (ctxt->context->tmpNsList != NULL)
5619 xmlFree(ctxt->context->tmpNsList);
5620 ctxt->context->tmpNsList = NULL;
5621 return(NULL);
5622 }
Owen Taylor3473f882001-02-23 17:55:21 +00005623}
5624
5625/**
5626 * xmlXPathNextAttribute:
5627 * @ctxt: the XPath Parser context
5628 * @cur: the current attribute in the traversal
5629 *
5630 * Traversal function for the "attribute" direction
5631 * TODO: support DTD inherited default attributes
5632 *
5633 * Returns the next element following that axis
5634 */
5635xmlNodePtr
5636xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005637 if (ctxt->context->node == NULL)
5638 return(NULL);
5639 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5640 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005641 if (cur == NULL) {
5642 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5643 return(NULL);
5644 return((xmlNodePtr)ctxt->context->node->properties);
5645 }
5646 return((xmlNodePtr)cur->next);
5647}
5648
5649/************************************************************************
5650 * *
5651 * NodeTest Functions *
5652 * *
5653 ************************************************************************/
5654
Owen Taylor3473f882001-02-23 17:55:21 +00005655#define IS_FUNCTION 200
5656
Owen Taylor3473f882001-02-23 17:55:21 +00005657
5658/************************************************************************
5659 * *
5660 * Implicit tree core function library *
5661 * *
5662 ************************************************************************/
5663
5664/**
5665 * xmlXPathRoot:
5666 * @ctxt: the XPath Parser context
5667 *
5668 * Initialize the context to the root of the document
5669 */
5670void
5671xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5672 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5673 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5674}
5675
5676/************************************************************************
5677 * *
5678 * The explicit core function library *
5679 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5680 * *
5681 ************************************************************************/
5682
5683
5684/**
5685 * xmlXPathLastFunction:
5686 * @ctxt: the XPath Parser context
5687 * @nargs: the number of arguments
5688 *
5689 * Implement the last() XPath function
5690 * number last()
5691 * The last function returns the number of nodes in the context node list.
5692 */
5693void
5694xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5695 CHECK_ARITY(0);
5696 if (ctxt->context->contextSize >= 0) {
5697 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5698#ifdef DEBUG_EXPR
5699 xmlGenericError(xmlGenericErrorContext,
5700 "last() : %d\n", ctxt->context->contextSize);
5701#endif
5702 } else {
5703 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5704 }
5705}
5706
5707/**
5708 * xmlXPathPositionFunction:
5709 * @ctxt: the XPath Parser context
5710 * @nargs: the number of arguments
5711 *
5712 * Implement the position() XPath function
5713 * number position()
5714 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005715 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005716 * will be equal to last().
5717 */
5718void
5719xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5720 CHECK_ARITY(0);
5721 if (ctxt->context->proximityPosition >= 0) {
5722 valuePush(ctxt,
5723 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5724#ifdef DEBUG_EXPR
5725 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5726 ctxt->context->proximityPosition);
5727#endif
5728 } else {
5729 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5730 }
5731}
5732
5733/**
5734 * xmlXPathCountFunction:
5735 * @ctxt: the XPath Parser context
5736 * @nargs: the number of arguments
5737 *
5738 * Implement the count() XPath function
5739 * number count(node-set)
5740 */
5741void
5742xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5743 xmlXPathObjectPtr cur;
5744
5745 CHECK_ARITY(1);
5746 if ((ctxt->value == NULL) ||
5747 ((ctxt->value->type != XPATH_NODESET) &&
5748 (ctxt->value->type != XPATH_XSLT_TREE)))
5749 XP_ERROR(XPATH_INVALID_TYPE);
5750 cur = valuePop(ctxt);
5751
Daniel Veillard911f49a2001-04-07 15:39:35 +00005752 if ((cur == NULL) || (cur->nodesetval == NULL))
5753 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005754 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005755 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005756 } else {
5757 if ((cur->nodesetval->nodeNr != 1) ||
5758 (cur->nodesetval->nodeTab == NULL)) {
5759 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5760 } else {
5761 xmlNodePtr tmp;
5762 int i = 0;
5763
5764 tmp = cur->nodesetval->nodeTab[0];
5765 if (tmp != NULL) {
5766 tmp = tmp->children;
5767 while (tmp != NULL) {
5768 tmp = tmp->next;
5769 i++;
5770 }
5771 }
5772 valuePush(ctxt, xmlXPathNewFloat((double) i));
5773 }
5774 }
Owen Taylor3473f882001-02-23 17:55:21 +00005775 xmlXPathFreeObject(cur);
5776}
5777
5778/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005779 * xmlXPathGetElementsByIds:
5780 * @doc: the document
5781 * @ids: a whitespace separated list of IDs
5782 *
5783 * Selects elements by their unique ID.
5784 *
5785 * Returns a node-set of selected elements.
5786 */
5787static xmlNodeSetPtr
5788xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5789 xmlNodeSetPtr ret;
5790 const xmlChar *cur = ids;
5791 xmlChar *ID;
5792 xmlAttrPtr attr;
5793 xmlNodePtr elem = NULL;
5794
5795 ret = xmlXPathNodeSetCreate(NULL);
5796
5797 while (IS_BLANK(*cur)) cur++;
5798 while (*cur != 0) {
5799 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5800 (*cur == '.') || (*cur == '-') ||
5801 (*cur == '_') || (*cur == ':') ||
5802 (IS_COMBINING(*cur)) ||
5803 (IS_EXTENDER(*cur)))
5804 cur++;
5805
5806 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5807
5808 ID = xmlStrndup(ids, cur - ids);
5809 attr = xmlGetID(doc, ID);
5810 if (attr != NULL) {
5811 elem = attr->parent;
5812 xmlXPathNodeSetAdd(ret, elem);
5813 }
5814 if (ID != NULL)
5815 xmlFree(ID);
5816
5817 while (IS_BLANK(*cur)) cur++;
5818 ids = cur;
5819 }
5820 return(ret);
5821}
5822
5823/**
Owen Taylor3473f882001-02-23 17:55:21 +00005824 * xmlXPathIdFunction:
5825 * @ctxt: the XPath Parser context
5826 * @nargs: the number of arguments
5827 *
5828 * Implement the id() XPath function
5829 * node-set id(object)
5830 * The id function selects elements by their unique ID
5831 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5832 * then the result is the union of the result of applying id to the
5833 * string value of each of the nodes in the argument node-set. When the
5834 * argument to id is of any other type, the argument is converted to a
5835 * string as if by a call to the string function; the string is split
5836 * into a whitespace-separated list of tokens (whitespace is any sequence
5837 * of characters matching the production S); the result is a node-set
5838 * containing the elements in the same document as the context node that
5839 * have a unique ID equal to any of the tokens in the list.
5840 */
5841void
5842xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005843 xmlChar *tokens;
5844 xmlNodeSetPtr ret;
5845 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005846
5847 CHECK_ARITY(1);
5848 obj = valuePop(ctxt);
5849 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005850 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005851 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005852 int i;
5853
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005854 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005855
Daniel Veillard911f49a2001-04-07 15:39:35 +00005856 if (obj->nodesetval != NULL) {
5857 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005858 tokens =
5859 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5860 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5861 ret = xmlXPathNodeSetMerge(ret, ns);
5862 xmlXPathFreeNodeSet(ns);
5863 if (tokens != NULL)
5864 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005865 }
Owen Taylor3473f882001-02-23 17:55:21 +00005866 }
5867
5868 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005869 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005870 return;
5871 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005872 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005873
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005874 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5875 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005876
Owen Taylor3473f882001-02-23 17:55:21 +00005877 xmlXPathFreeObject(obj);
5878 return;
5879}
5880
5881/**
5882 * xmlXPathLocalNameFunction:
5883 * @ctxt: the XPath Parser context
5884 * @nargs: the number of arguments
5885 *
5886 * Implement the local-name() XPath function
5887 * string local-name(node-set?)
5888 * The local-name function returns a string containing the local part
5889 * of the name of the node in the argument node-set that is first in
5890 * document order. If the node-set is empty or the first node has no
5891 * name, an empty string is returned. If the argument is omitted it
5892 * defaults to the context node.
5893 */
5894void
5895xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5896 xmlXPathObjectPtr cur;
5897
5898 if (nargs == 0) {
5899 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5900 nargs = 1;
5901 }
5902
5903 CHECK_ARITY(1);
5904 if ((ctxt->value == NULL) ||
5905 ((ctxt->value->type != XPATH_NODESET) &&
5906 (ctxt->value->type != XPATH_XSLT_TREE)))
5907 XP_ERROR(XPATH_INVALID_TYPE);
5908 cur = valuePop(ctxt);
5909
Daniel Veillard911f49a2001-04-07 15:39:35 +00005910 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005911 valuePush(ctxt, xmlXPathNewCString(""));
5912 } else {
5913 int i = 0; /* Should be first in document order !!!!! */
5914 switch (cur->nodesetval->nodeTab[i]->type) {
5915 case XML_ELEMENT_NODE:
5916 case XML_ATTRIBUTE_NODE:
5917 case XML_PI_NODE:
5918 valuePush(ctxt,
5919 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5920 break;
5921 case XML_NAMESPACE_DECL:
5922 valuePush(ctxt, xmlXPathNewString(
5923 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5924 break;
5925 default:
5926 valuePush(ctxt, xmlXPathNewCString(""));
5927 }
5928 }
5929 xmlXPathFreeObject(cur);
5930}
5931
5932/**
5933 * xmlXPathNamespaceURIFunction:
5934 * @ctxt: the XPath Parser context
5935 * @nargs: the number of arguments
5936 *
5937 * Implement the namespace-uri() XPath function
5938 * string namespace-uri(node-set?)
5939 * The namespace-uri function returns a string containing the
5940 * namespace URI of the expanded name of the node in the argument
5941 * node-set that is first in document order. If the node-set is empty,
5942 * the first node has no name, or the expanded name has no namespace
5943 * URI, an empty string is returned. If the argument is omitted it
5944 * defaults to the context node.
5945 */
5946void
5947xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5948 xmlXPathObjectPtr cur;
5949
5950 if (nargs == 0) {
5951 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5952 nargs = 1;
5953 }
5954 CHECK_ARITY(1);
5955 if ((ctxt->value == NULL) ||
5956 ((ctxt->value->type != XPATH_NODESET) &&
5957 (ctxt->value->type != XPATH_XSLT_TREE)))
5958 XP_ERROR(XPATH_INVALID_TYPE);
5959 cur = valuePop(ctxt);
5960
Daniel Veillard911f49a2001-04-07 15:39:35 +00005961 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005962 valuePush(ctxt, xmlXPathNewCString(""));
5963 } else {
5964 int i = 0; /* Should be first in document order !!!!! */
5965 switch (cur->nodesetval->nodeTab[i]->type) {
5966 case XML_ELEMENT_NODE:
5967 case XML_ATTRIBUTE_NODE:
5968 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5969 valuePush(ctxt, xmlXPathNewCString(""));
5970 else
5971 valuePush(ctxt, xmlXPathNewString(
5972 cur->nodesetval->nodeTab[i]->ns->href));
5973 break;
5974 default:
5975 valuePush(ctxt, xmlXPathNewCString(""));
5976 }
5977 }
5978 xmlXPathFreeObject(cur);
5979}
5980
5981/**
5982 * xmlXPathNameFunction:
5983 * @ctxt: the XPath Parser context
5984 * @nargs: the number of arguments
5985 *
5986 * Implement the name() XPath function
5987 * string name(node-set?)
5988 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005989 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005990 * order. The QName must represent the name with respect to the namespace
5991 * declarations in effect on the node whose name is being represented.
5992 * Typically, this will be the form in which the name occurred in the XML
5993 * source. This need not be the case if there are namespace declarations
5994 * in effect on the node that associate multiple prefixes with the same
5995 * namespace. However, an implementation may include information about
5996 * the original prefix in its representation of nodes; in this case, an
5997 * implementation can ensure that the returned string is always the same
5998 * as the QName used in the XML source. If the argument it omitted it
5999 * defaults to the context node.
6000 * Libxml keep the original prefix so the "real qualified name" used is
6001 * returned.
6002 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006003static void
Daniel Veillard04383752001-07-08 14:27:15 +00006004xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6005{
Owen Taylor3473f882001-02-23 17:55:21 +00006006 xmlXPathObjectPtr cur;
6007
6008 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006009 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6010 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006011 }
6012
6013 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006014 if ((ctxt->value == NULL) ||
6015 ((ctxt->value->type != XPATH_NODESET) &&
6016 (ctxt->value->type != XPATH_XSLT_TREE)))
6017 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006018 cur = valuePop(ctxt);
6019
Daniel Veillard911f49a2001-04-07 15:39:35 +00006020 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006021 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006022 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006023 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006024
Daniel Veillard04383752001-07-08 14:27:15 +00006025 switch (cur->nodesetval->nodeTab[i]->type) {
6026 case XML_ELEMENT_NODE:
6027 case XML_ATTRIBUTE_NODE:
6028 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6029 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
6030 valuePush(ctxt,
6031 xmlXPathNewString(cur->nodesetval->
6032 nodeTab[i]->name));
6033
6034 else {
6035 char name[2000];
6036
6037 snprintf(name, sizeof(name), "%s:%s",
6038 (char *) cur->nodesetval->nodeTab[i]->ns->
6039 prefix,
6040 (char *) cur->nodesetval->nodeTab[i]->name);
6041 name[sizeof(name) - 1] = 0;
6042 valuePush(ctxt, xmlXPathNewCString(name));
6043 }
6044 break;
6045 default:
6046 valuePush(ctxt,
6047 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6048 xmlXPathLocalNameFunction(ctxt, 1);
6049 }
Owen Taylor3473f882001-02-23 17:55:21 +00006050 }
6051 xmlXPathFreeObject(cur);
6052}
6053
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006054
6055/**
Owen Taylor3473f882001-02-23 17:55:21 +00006056 * xmlXPathStringFunction:
6057 * @ctxt: the XPath Parser context
6058 * @nargs: the number of arguments
6059 *
6060 * Implement the string() XPath function
6061 * string string(object?)
6062 * he string function converts an object to a string as follows:
6063 * - A node-set is converted to a string by returning the value of
6064 * the node in the node-set that is first in document order.
6065 * If the node-set is empty, an empty string is returned.
6066 * - A number is converted to a string as follows
6067 * + NaN is converted to the string NaN
6068 * + positive zero is converted to the string 0
6069 * + negative zero is converted to the string 0
6070 * + positive infinity is converted to the string Infinity
6071 * + negative infinity is converted to the string -Infinity
6072 * + if the number is an integer, the number is represented in
6073 * decimal form as a Number with no decimal point and no leading
6074 * zeros, preceded by a minus sign (-) if the number is negative
6075 * + otherwise, the number is represented in decimal form as a
6076 * Number including a decimal point with at least one digit
6077 * before the decimal point and at least one digit after the
6078 * decimal point, preceded by a minus sign (-) if the number
6079 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006080 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006081 * before the decimal point; beyond the one required digit
6082 * after the decimal point there must be as many, but only as
6083 * many, more digits as are needed to uniquely distinguish the
6084 * number from all other IEEE 754 numeric values.
6085 * - The boolean false value is converted to the string false.
6086 * The boolean true value is converted to the string true.
6087 *
6088 * If the argument is omitted, it defaults to a node-set with the
6089 * context node as its only member.
6090 */
6091void
6092xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6093 xmlXPathObjectPtr cur;
6094
6095 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006096 valuePush(ctxt,
6097 xmlXPathWrapString(
6098 xmlXPathCastNodeToString(ctxt->context->node)));
6099 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006100 }
6101
6102 CHECK_ARITY(1);
6103 cur = valuePop(ctxt);
6104 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006105 cur = xmlXPathConvertString(cur);
6106 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006107}
6108
6109/**
6110 * xmlXPathStringLengthFunction:
6111 * @ctxt: the XPath Parser context
6112 * @nargs: the number of arguments
6113 *
6114 * Implement the string-length() XPath function
6115 * number string-length(string?)
6116 * The string-length returns the number of characters in the string
6117 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6118 * the context node converted to a string, in other words the value
6119 * of the context node.
6120 */
6121void
6122xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6123 xmlXPathObjectPtr cur;
6124
6125 if (nargs == 0) {
6126 if (ctxt->context->node == NULL) {
6127 valuePush(ctxt, xmlXPathNewFloat(0));
6128 } else {
6129 xmlChar *content;
6130
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006131 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006132 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006133 xmlFree(content);
6134 }
6135 return;
6136 }
6137 CHECK_ARITY(1);
6138 CAST_TO_STRING;
6139 CHECK_TYPE(XPATH_STRING);
6140 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006141 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006142 xmlXPathFreeObject(cur);
6143}
6144
6145/**
6146 * xmlXPathConcatFunction:
6147 * @ctxt: the XPath Parser context
6148 * @nargs: the number of arguments
6149 *
6150 * Implement the concat() XPath function
6151 * string concat(string, string, string*)
6152 * The concat function returns the concatenation of its arguments.
6153 */
6154void
6155xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6156 xmlXPathObjectPtr cur, newobj;
6157 xmlChar *tmp;
6158
6159 if (nargs < 2) {
6160 CHECK_ARITY(2);
6161 }
6162
6163 CAST_TO_STRING;
6164 cur = valuePop(ctxt);
6165 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6166 xmlXPathFreeObject(cur);
6167 return;
6168 }
6169 nargs--;
6170
6171 while (nargs > 0) {
6172 CAST_TO_STRING;
6173 newobj = valuePop(ctxt);
6174 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6175 xmlXPathFreeObject(newobj);
6176 xmlXPathFreeObject(cur);
6177 XP_ERROR(XPATH_INVALID_TYPE);
6178 }
6179 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6180 newobj->stringval = cur->stringval;
6181 cur->stringval = tmp;
6182
6183 xmlXPathFreeObject(newobj);
6184 nargs--;
6185 }
6186 valuePush(ctxt, cur);
6187}
6188
6189/**
6190 * xmlXPathContainsFunction:
6191 * @ctxt: the XPath Parser context
6192 * @nargs: the number of arguments
6193 *
6194 * Implement the contains() XPath function
6195 * boolean contains(string, string)
6196 * The contains function returns true if the first argument string
6197 * contains the second argument string, and otherwise returns false.
6198 */
6199void
6200xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6201 xmlXPathObjectPtr hay, needle;
6202
6203 CHECK_ARITY(2);
6204 CAST_TO_STRING;
6205 CHECK_TYPE(XPATH_STRING);
6206 needle = valuePop(ctxt);
6207 CAST_TO_STRING;
6208 hay = valuePop(ctxt);
6209 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6210 xmlXPathFreeObject(hay);
6211 xmlXPathFreeObject(needle);
6212 XP_ERROR(XPATH_INVALID_TYPE);
6213 }
6214 if (xmlStrstr(hay->stringval, needle->stringval))
6215 valuePush(ctxt, xmlXPathNewBoolean(1));
6216 else
6217 valuePush(ctxt, xmlXPathNewBoolean(0));
6218 xmlXPathFreeObject(hay);
6219 xmlXPathFreeObject(needle);
6220}
6221
6222/**
6223 * xmlXPathStartsWithFunction:
6224 * @ctxt: the XPath Parser context
6225 * @nargs: the number of arguments
6226 *
6227 * Implement the starts-with() XPath function
6228 * boolean starts-with(string, string)
6229 * The starts-with function returns true if the first argument string
6230 * starts with the second argument string, and otherwise returns false.
6231 */
6232void
6233xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6234 xmlXPathObjectPtr hay, needle;
6235 int n;
6236
6237 CHECK_ARITY(2);
6238 CAST_TO_STRING;
6239 CHECK_TYPE(XPATH_STRING);
6240 needle = valuePop(ctxt);
6241 CAST_TO_STRING;
6242 hay = valuePop(ctxt);
6243 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6244 xmlXPathFreeObject(hay);
6245 xmlXPathFreeObject(needle);
6246 XP_ERROR(XPATH_INVALID_TYPE);
6247 }
6248 n = xmlStrlen(needle->stringval);
6249 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6250 valuePush(ctxt, xmlXPathNewBoolean(0));
6251 else
6252 valuePush(ctxt, xmlXPathNewBoolean(1));
6253 xmlXPathFreeObject(hay);
6254 xmlXPathFreeObject(needle);
6255}
6256
6257/**
6258 * xmlXPathSubstringFunction:
6259 * @ctxt: the XPath Parser context
6260 * @nargs: the number of arguments
6261 *
6262 * Implement the substring() XPath function
6263 * string substring(string, number, number?)
6264 * The substring function returns the substring of the first argument
6265 * starting at the position specified in the second argument with
6266 * length specified in the third argument. For example,
6267 * substring("12345",2,3) returns "234". If the third argument is not
6268 * specified, it returns the substring starting at the position specified
6269 * in the second argument and continuing to the end of the string. For
6270 * example, substring("12345",2) returns "2345". More precisely, each
6271 * character in the string (see [3.6 Strings]) is considered to have a
6272 * numeric position: the position of the first character is 1, the position
6273 * of the second character is 2 and so on. The returned substring contains
6274 * those characters for which the position of the character is greater than
6275 * or equal to the second argument and, if the third argument is specified,
6276 * less than the sum of the second and third arguments; the comparisons
6277 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6278 * - substring("12345", 1.5, 2.6) returns "234"
6279 * - substring("12345", 0, 3) returns "12"
6280 * - substring("12345", 0 div 0, 3) returns ""
6281 * - substring("12345", 1, 0 div 0) returns ""
6282 * - substring("12345", -42, 1 div 0) returns "12345"
6283 * - substring("12345", -1 div 0, 1 div 0) returns ""
6284 */
6285void
6286xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6287 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006288 double le=0, in;
6289 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006290 xmlChar *ret;
6291
Owen Taylor3473f882001-02-23 17:55:21 +00006292 if (nargs < 2) {
6293 CHECK_ARITY(2);
6294 }
6295 if (nargs > 3) {
6296 CHECK_ARITY(3);
6297 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006298 /*
6299 * take care of possible last (position) argument
6300 */
Owen Taylor3473f882001-02-23 17:55:21 +00006301 if (nargs == 3) {
6302 CAST_TO_NUMBER;
6303 CHECK_TYPE(XPATH_NUMBER);
6304 len = valuePop(ctxt);
6305 le = len->floatval;
6306 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006307 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006308
Owen Taylor3473f882001-02-23 17:55:21 +00006309 CAST_TO_NUMBER;
6310 CHECK_TYPE(XPATH_NUMBER);
6311 start = valuePop(ctxt);
6312 in = start->floatval;
6313 xmlXPathFreeObject(start);
6314 CAST_TO_STRING;
6315 CHECK_TYPE(XPATH_STRING);
6316 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006317 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006318
Daniel Veillard97ac1312001-05-30 19:14:17 +00006319 /*
6320 * If last pos not present, calculate last position
6321 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006322 if (nargs != 3) {
6323 le = (double)m;
6324 if (in < 1.0)
6325 in = 1.0;
6326 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006327
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006328 /* Need to check for the special cases where either
6329 * the index is NaN, the length is NaN, or both
6330 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006331 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006332 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006333 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006334 * To meet the requirements of the spec, the arguments
6335 * must be converted to integer format before
6336 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006337 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006338 * First we go to integer form, rounding up
6339 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006340 */
6341 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006342 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006343
Daniel Veillard9e412302002-06-10 15:59:44 +00006344 if (xmlXPathIsInf(le) == 1) {
6345 l = m;
6346 if (i < 1)
6347 i = 1;
6348 }
6349 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6350 l = 0;
6351 else {
6352 l = (int) le;
6353 if (((double)l)+0.5 <= le) l++;
6354 }
6355
6356 /* Now we normalize inidices */
6357 i -= 1;
6358 l += i;
6359 if (i < 0)
6360 i = 0;
6361 if (l > m)
6362 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006363
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006364 /* number of chars to copy */
6365 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006366
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006367 ret = xmlUTF8Strsub(str->stringval, i, l);
6368 }
6369 else {
6370 ret = NULL;
6371 }
6372
Owen Taylor3473f882001-02-23 17:55:21 +00006373 if (ret == NULL)
6374 valuePush(ctxt, xmlXPathNewCString(""));
6375 else {
6376 valuePush(ctxt, xmlXPathNewString(ret));
6377 xmlFree(ret);
6378 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006379
Owen Taylor3473f882001-02-23 17:55:21 +00006380 xmlXPathFreeObject(str);
6381}
6382
6383/**
6384 * xmlXPathSubstringBeforeFunction:
6385 * @ctxt: the XPath Parser context
6386 * @nargs: the number of arguments
6387 *
6388 * Implement the substring-before() XPath function
6389 * string substring-before(string, string)
6390 * The substring-before function returns the substring of the first
6391 * argument string that precedes the first occurrence of the second
6392 * argument string in the first argument string, or the empty string
6393 * if the first argument string does not contain the second argument
6394 * string. For example, substring-before("1999/04/01","/") returns 1999.
6395 */
6396void
6397xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6398 xmlXPathObjectPtr str;
6399 xmlXPathObjectPtr find;
6400 xmlBufferPtr target;
6401 const xmlChar *point;
6402 int offset;
6403
6404 CHECK_ARITY(2);
6405 CAST_TO_STRING;
6406 find = valuePop(ctxt);
6407 CAST_TO_STRING;
6408 str = valuePop(ctxt);
6409
6410 target = xmlBufferCreate();
6411 if (target) {
6412 point = xmlStrstr(str->stringval, find->stringval);
6413 if (point) {
6414 offset = (int)(point - str->stringval);
6415 xmlBufferAdd(target, str->stringval, offset);
6416 }
6417 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6418 xmlBufferFree(target);
6419 }
6420
6421 xmlXPathFreeObject(str);
6422 xmlXPathFreeObject(find);
6423}
6424
6425/**
6426 * xmlXPathSubstringAfterFunction:
6427 * @ctxt: the XPath Parser context
6428 * @nargs: the number of arguments
6429 *
6430 * Implement the substring-after() XPath function
6431 * string substring-after(string, string)
6432 * The substring-after function returns the substring of the first
6433 * argument string that follows the first occurrence of the second
6434 * argument string in the first argument string, or the empty stringi
6435 * if the first argument string does not contain the second argument
6436 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6437 * and substring-after("1999/04/01","19") returns 99/04/01.
6438 */
6439void
6440xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6441 xmlXPathObjectPtr str;
6442 xmlXPathObjectPtr find;
6443 xmlBufferPtr target;
6444 const xmlChar *point;
6445 int offset;
6446
6447 CHECK_ARITY(2);
6448 CAST_TO_STRING;
6449 find = valuePop(ctxt);
6450 CAST_TO_STRING;
6451 str = valuePop(ctxt);
6452
6453 target = xmlBufferCreate();
6454 if (target) {
6455 point = xmlStrstr(str->stringval, find->stringval);
6456 if (point) {
6457 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6458 xmlBufferAdd(target, &str->stringval[offset],
6459 xmlStrlen(str->stringval) - offset);
6460 }
6461 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6462 xmlBufferFree(target);
6463 }
6464
6465 xmlXPathFreeObject(str);
6466 xmlXPathFreeObject(find);
6467}
6468
6469/**
6470 * xmlXPathNormalizeFunction:
6471 * @ctxt: the XPath Parser context
6472 * @nargs: the number of arguments
6473 *
6474 * Implement the normalize-space() XPath function
6475 * string normalize-space(string?)
6476 * The normalize-space function returns the argument string with white
6477 * space normalized by stripping leading and trailing whitespace
6478 * and replacing sequences of whitespace characters by a single
6479 * space. Whitespace characters are the same allowed by the S production
6480 * in XML. If the argument is omitted, it defaults to the context
6481 * node converted to a string, in other words the value of the context node.
6482 */
6483void
6484xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6485 xmlXPathObjectPtr obj = NULL;
6486 xmlChar *source = NULL;
6487 xmlBufferPtr target;
6488 xmlChar blank;
6489
6490 if (nargs == 0) {
6491 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006492 valuePush(ctxt,
6493 xmlXPathWrapString(
6494 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006495 nargs = 1;
6496 }
6497
6498 CHECK_ARITY(1);
6499 CAST_TO_STRING;
6500 CHECK_TYPE(XPATH_STRING);
6501 obj = valuePop(ctxt);
6502 source = obj->stringval;
6503
6504 target = xmlBufferCreate();
6505 if (target && source) {
6506
6507 /* Skip leading whitespaces */
6508 while (IS_BLANK(*source))
6509 source++;
6510
6511 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6512 blank = 0;
6513 while (*source) {
6514 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006515 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006516 } else {
6517 if (blank) {
6518 xmlBufferAdd(target, &blank, 1);
6519 blank = 0;
6520 }
6521 xmlBufferAdd(target, source, 1);
6522 }
6523 source++;
6524 }
6525
6526 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6527 xmlBufferFree(target);
6528 }
6529 xmlXPathFreeObject(obj);
6530}
6531
6532/**
6533 * xmlXPathTranslateFunction:
6534 * @ctxt: the XPath Parser context
6535 * @nargs: the number of arguments
6536 *
6537 * Implement the translate() XPath function
6538 * string translate(string, string, string)
6539 * The translate function returns the first argument string with
6540 * occurrences of characters in the second argument string replaced
6541 * by the character at the corresponding position in the third argument
6542 * string. For example, translate("bar","abc","ABC") returns the string
6543 * BAr. If there is a character in the second argument string with no
6544 * character at a corresponding position in the third argument string
6545 * (because the second argument string is longer than the third argument
6546 * string), then occurrences of that character in the first argument
6547 * string are removed. For example, translate("--aaa--","abc-","ABC")
6548 * returns "AAA". If a character occurs more than once in second
6549 * argument string, then the first occurrence determines the replacement
6550 * character. If the third argument string is longer than the second
6551 * argument string, then excess characters are ignored.
6552 */
6553void
6554xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006555 xmlXPathObjectPtr str;
6556 xmlXPathObjectPtr from;
6557 xmlXPathObjectPtr to;
6558 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006559 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006560 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006561 xmlChar *point;
6562 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006563
Daniel Veillarde043ee12001-04-16 14:08:07 +00006564 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006565
Daniel Veillarde043ee12001-04-16 14:08:07 +00006566 CAST_TO_STRING;
6567 to = valuePop(ctxt);
6568 CAST_TO_STRING;
6569 from = valuePop(ctxt);
6570 CAST_TO_STRING;
6571 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006572
Daniel Veillarde043ee12001-04-16 14:08:07 +00006573 target = xmlBufferCreate();
6574 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006575 max = xmlUTF8Strlen(to->stringval);
6576 for (cptr = str->stringval; (ch=*cptr); ) {
6577 offset = xmlUTF8Strloc(from->stringval, cptr);
6578 if (offset >= 0) {
6579 if (offset < max) {
6580 point = xmlUTF8Strpos(to->stringval, offset);
6581 if (point)
6582 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6583 }
6584 } else
6585 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6586
6587 /* Step to next character in input */
6588 cptr++;
6589 if ( ch & 0x80 ) {
6590 /* if not simple ascii, verify proper format */
6591 if ( (ch & 0xc0) != 0xc0 ) {
6592 xmlGenericError(xmlGenericErrorContext,
6593 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6594 break;
6595 }
6596 /* then skip over remaining bytes for this char */
6597 while ( (ch <<= 1) & 0x80 )
6598 if ( (*cptr++ & 0xc0) != 0x80 ) {
6599 xmlGenericError(xmlGenericErrorContext,
6600 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6601 break;
6602 }
6603 if (ch & 0x80) /* must have had error encountered */
6604 break;
6605 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006606 }
Owen Taylor3473f882001-02-23 17:55:21 +00006607 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006608 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6609 xmlBufferFree(target);
6610 xmlXPathFreeObject(str);
6611 xmlXPathFreeObject(from);
6612 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006613}
6614
6615/**
6616 * xmlXPathBooleanFunction:
6617 * @ctxt: the XPath Parser context
6618 * @nargs: the number of arguments
6619 *
6620 * Implement the boolean() XPath function
6621 * boolean boolean(object)
6622 * he boolean function converts its argument to a boolean as follows:
6623 * - a number is true if and only if it is neither positive or
6624 * negative zero nor NaN
6625 * - a node-set is true if and only if it is non-empty
6626 * - a string is true if and only if its length is non-zero
6627 */
6628void
6629xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6630 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006631
6632 CHECK_ARITY(1);
6633 cur = valuePop(ctxt);
6634 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006635 cur = xmlXPathConvertBoolean(cur);
6636 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006637}
6638
6639/**
6640 * xmlXPathNotFunction:
6641 * @ctxt: the XPath Parser context
6642 * @nargs: the number of arguments
6643 *
6644 * Implement the not() XPath function
6645 * boolean not(boolean)
6646 * The not function returns true if its argument is false,
6647 * and false otherwise.
6648 */
6649void
6650xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6651 CHECK_ARITY(1);
6652 CAST_TO_BOOLEAN;
6653 CHECK_TYPE(XPATH_BOOLEAN);
6654 ctxt->value->boolval = ! ctxt->value->boolval;
6655}
6656
6657/**
6658 * xmlXPathTrueFunction:
6659 * @ctxt: the XPath Parser context
6660 * @nargs: the number of arguments
6661 *
6662 * Implement the true() XPath function
6663 * boolean true()
6664 */
6665void
6666xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6667 CHECK_ARITY(0);
6668 valuePush(ctxt, xmlXPathNewBoolean(1));
6669}
6670
6671/**
6672 * xmlXPathFalseFunction:
6673 * @ctxt: the XPath Parser context
6674 * @nargs: the number of arguments
6675 *
6676 * Implement the false() XPath function
6677 * boolean false()
6678 */
6679void
6680xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6681 CHECK_ARITY(0);
6682 valuePush(ctxt, xmlXPathNewBoolean(0));
6683}
6684
6685/**
6686 * xmlXPathLangFunction:
6687 * @ctxt: the XPath Parser context
6688 * @nargs: the number of arguments
6689 *
6690 * Implement the lang() XPath function
6691 * boolean lang(string)
6692 * The lang function returns true or false depending on whether the
6693 * language of the context node as specified by xml:lang attributes
6694 * is the same as or is a sublanguage of the language specified by
6695 * the argument string. The language of the context node is determined
6696 * by the value of the xml:lang attribute on the context node, or, if
6697 * the context node has no xml:lang attribute, by the value of the
6698 * xml:lang attribute on the nearest ancestor of the context node that
6699 * has an xml:lang attribute. If there is no such attribute, then lang
6700 * returns false. If there is such an attribute, then lang returns
6701 * true if the attribute value is equal to the argument ignoring case,
6702 * or if there is some suffix starting with - such that the attribute
6703 * value is equal to the argument ignoring that suffix of the attribute
6704 * value and ignoring case.
6705 */
6706void
6707xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6708 xmlXPathObjectPtr val;
6709 const xmlChar *theLang;
6710 const xmlChar *lang;
6711 int ret = 0;
6712 int i;
6713
6714 CHECK_ARITY(1);
6715 CAST_TO_STRING;
6716 CHECK_TYPE(XPATH_STRING);
6717 val = valuePop(ctxt);
6718 lang = val->stringval;
6719 theLang = xmlNodeGetLang(ctxt->context->node);
6720 if ((theLang != NULL) && (lang != NULL)) {
6721 for (i = 0;lang[i] != 0;i++)
6722 if (toupper(lang[i]) != toupper(theLang[i]))
6723 goto not_equal;
6724 ret = 1;
6725 }
6726not_equal:
6727 xmlXPathFreeObject(val);
6728 valuePush(ctxt, xmlXPathNewBoolean(ret));
6729}
6730
6731/**
6732 * xmlXPathNumberFunction:
6733 * @ctxt: the XPath Parser context
6734 * @nargs: the number of arguments
6735 *
6736 * Implement the number() XPath function
6737 * number number(object?)
6738 */
6739void
6740xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6741 xmlXPathObjectPtr cur;
6742 double res;
6743
6744 if (nargs == 0) {
6745 if (ctxt->context->node == NULL) {
6746 valuePush(ctxt, xmlXPathNewFloat(0.0));
6747 } else {
6748 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6749
6750 res = xmlXPathStringEvalNumber(content);
6751 valuePush(ctxt, xmlXPathNewFloat(res));
6752 xmlFree(content);
6753 }
6754 return;
6755 }
6756
6757 CHECK_ARITY(1);
6758 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006759 cur = xmlXPathConvertNumber(cur);
6760 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006761}
6762
6763/**
6764 * xmlXPathSumFunction:
6765 * @ctxt: the XPath Parser context
6766 * @nargs: the number of arguments
6767 *
6768 * Implement the sum() XPath function
6769 * number sum(node-set)
6770 * The sum function returns the sum of the values of the nodes in
6771 * the argument node-set.
6772 */
6773void
6774xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6775 xmlXPathObjectPtr cur;
6776 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006777 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006778
6779 CHECK_ARITY(1);
6780 if ((ctxt->value == NULL) ||
6781 ((ctxt->value->type != XPATH_NODESET) &&
6782 (ctxt->value->type != XPATH_XSLT_TREE)))
6783 XP_ERROR(XPATH_INVALID_TYPE);
6784 cur = valuePop(ctxt);
6785
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006786 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006787 valuePush(ctxt, xmlXPathNewFloat(0.0));
6788 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006789 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6790 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006791 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006792 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006793 }
6794 xmlXPathFreeObject(cur);
6795}
6796
6797/**
6798 * xmlXPathFloorFunction:
6799 * @ctxt: the XPath Parser context
6800 * @nargs: the number of arguments
6801 *
6802 * Implement the floor() XPath function
6803 * number floor(number)
6804 * The floor function returns the largest (closest to positive infinity)
6805 * number that is not greater than the argument and that is an integer.
6806 */
6807void
6808xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006809 double f;
6810
Owen Taylor3473f882001-02-23 17:55:21 +00006811 CHECK_ARITY(1);
6812 CAST_TO_NUMBER;
6813 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006814
6815 f = (double)((int) ctxt->value->floatval);
6816 if (f != ctxt->value->floatval) {
6817 if (ctxt->value->floatval > 0)
6818 ctxt->value->floatval = f;
6819 else
6820 ctxt->value->floatval = f - 1;
6821 }
Owen Taylor3473f882001-02-23 17:55:21 +00006822}
6823
6824/**
6825 * xmlXPathCeilingFunction:
6826 * @ctxt: the XPath Parser context
6827 * @nargs: the number of arguments
6828 *
6829 * Implement the ceiling() XPath function
6830 * number ceiling(number)
6831 * The ceiling function returns the smallest (closest to negative infinity)
6832 * number that is not less than the argument and that is an integer.
6833 */
6834void
6835xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6836 double f;
6837
6838 CHECK_ARITY(1);
6839 CAST_TO_NUMBER;
6840 CHECK_TYPE(XPATH_NUMBER);
6841
6842#if 0
6843 ctxt->value->floatval = ceil(ctxt->value->floatval);
6844#else
6845 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006846 if (f != ctxt->value->floatval) {
6847 if (ctxt->value->floatval > 0)
6848 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006849 else {
6850 if (ctxt->value->floatval < 0 && f == 0)
6851 ctxt->value->floatval = xmlXPathNZERO;
6852 else
6853 ctxt->value->floatval = f;
6854 }
6855
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006856 }
Owen Taylor3473f882001-02-23 17:55:21 +00006857#endif
6858}
6859
6860/**
6861 * xmlXPathRoundFunction:
6862 * @ctxt: the XPath Parser context
6863 * @nargs: the number of arguments
6864 *
6865 * Implement the round() XPath function
6866 * number round(number)
6867 * The round function returns the number that is closest to the
6868 * argument and that is an integer. If there are two such numbers,
6869 * then the one that is even is returned.
6870 */
6871void
6872xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6873 double f;
6874
6875 CHECK_ARITY(1);
6876 CAST_TO_NUMBER;
6877 CHECK_TYPE(XPATH_NUMBER);
6878
Daniel Veillardcda96922001-08-21 10:56:31 +00006879 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6880 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6881 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006882 (ctxt->value->floatval == 0.0))
6883 return;
6884
Owen Taylor3473f882001-02-23 17:55:21 +00006885 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006886 if (ctxt->value->floatval < 0) {
6887 if (ctxt->value->floatval < f - 0.5)
6888 ctxt->value->floatval = f - 1;
6889 else
6890 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006891 if (ctxt->value->floatval == 0)
6892 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006893 } else {
6894 if (ctxt->value->floatval < f + 0.5)
6895 ctxt->value->floatval = f;
6896 else
6897 ctxt->value->floatval = f + 1;
6898 }
Owen Taylor3473f882001-02-23 17:55:21 +00006899}
6900
6901/************************************************************************
6902 * *
6903 * The Parser *
6904 * *
6905 ************************************************************************/
6906
6907/*
6908 * a couple of forward declarations since we use a recursive call based
6909 * implementation.
6910 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006911static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006912static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006913static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006914static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00006915static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6916 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006917
6918/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006919 * xmlXPathCurrentChar:
6920 * @ctxt: the XPath parser context
6921 * @cur: pointer to the beginning of the char
6922 * @len: pointer to the length of the char read
6923 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006924 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006925 * bytes in the input buffer.
6926 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006927 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006928 */
6929
6930static int
6931xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6932 unsigned char c;
6933 unsigned int val;
6934 const xmlChar *cur;
6935
6936 if (ctxt == NULL)
6937 return(0);
6938 cur = ctxt->cur;
6939
6940 /*
6941 * We are supposed to handle UTF8, check it's valid
6942 * From rfc2044: encoding of the Unicode values on UTF-8:
6943 *
6944 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6945 * 0000 0000-0000 007F 0xxxxxxx
6946 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6947 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6948 *
6949 * Check for the 0x110000 limit too
6950 */
6951 c = *cur;
6952 if (c & 0x80) {
6953 if ((cur[1] & 0xc0) != 0x80)
6954 goto encoding_error;
6955 if ((c & 0xe0) == 0xe0) {
6956
6957 if ((cur[2] & 0xc0) != 0x80)
6958 goto encoding_error;
6959 if ((c & 0xf0) == 0xf0) {
6960 if (((c & 0xf8) != 0xf0) ||
6961 ((cur[3] & 0xc0) != 0x80))
6962 goto encoding_error;
6963 /* 4-byte code */
6964 *len = 4;
6965 val = (cur[0] & 0x7) << 18;
6966 val |= (cur[1] & 0x3f) << 12;
6967 val |= (cur[2] & 0x3f) << 6;
6968 val |= cur[3] & 0x3f;
6969 } else {
6970 /* 3-byte code */
6971 *len = 3;
6972 val = (cur[0] & 0xf) << 12;
6973 val |= (cur[1] & 0x3f) << 6;
6974 val |= cur[2] & 0x3f;
6975 }
6976 } else {
6977 /* 2-byte code */
6978 *len = 2;
6979 val = (cur[0] & 0x1f) << 6;
6980 val |= cur[1] & 0x3f;
6981 }
6982 if (!IS_CHAR(val)) {
6983 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6984 }
6985 return(val);
6986 } else {
6987 /* 1-byte code */
6988 *len = 1;
6989 return((int) *cur);
6990 }
6991encoding_error:
6992 /*
6993 * If we detect an UTF8 error that probably mean that the
6994 * input encoding didn't get properly advertized in the
6995 * declaration header. Report the error and switch the encoding
6996 * to ISO-Latin-1 (if you don't like this policy, just declare the
6997 * encoding !)
6998 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006999 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007000 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007001}
7002
7003/**
Owen Taylor3473f882001-02-23 17:55:21 +00007004 * xmlXPathParseNCName:
7005 * @ctxt: the XPath Parser context
7006 *
7007 * parse an XML namespace non qualified name.
7008 *
7009 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7010 *
7011 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7012 * CombiningChar | Extender
7013 *
7014 * Returns the namespace name or NULL
7015 */
7016
7017xmlChar *
7018xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007019 const xmlChar *in;
7020 xmlChar *ret;
7021 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007022
Daniel Veillard2156a562001-04-28 12:24:34 +00007023 /*
7024 * Accelerator for simple ASCII names
7025 */
7026 in = ctxt->cur;
7027 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7028 ((*in >= 0x41) && (*in <= 0x5A)) ||
7029 (*in == '_')) {
7030 in++;
7031 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7032 ((*in >= 0x41) && (*in <= 0x5A)) ||
7033 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007034 (*in == '_') || (*in == '.') ||
7035 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007036 in++;
7037 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7038 (*in == '[') || (*in == ']') || (*in == ':') ||
7039 (*in == '@') || (*in == '*')) {
7040 count = in - ctxt->cur;
7041 if (count == 0)
7042 return(NULL);
7043 ret = xmlStrndup(ctxt->cur, count);
7044 ctxt->cur = in;
7045 return(ret);
7046 }
7047 }
7048 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007049}
7050
Daniel Veillard2156a562001-04-28 12:24:34 +00007051
Owen Taylor3473f882001-02-23 17:55:21 +00007052/**
7053 * xmlXPathParseQName:
7054 * @ctxt: the XPath Parser context
7055 * @prefix: a xmlChar **
7056 *
7057 * parse an XML qualified name
7058 *
7059 * [NS 5] QName ::= (Prefix ':')? LocalPart
7060 *
7061 * [NS 6] Prefix ::= NCName
7062 *
7063 * [NS 7] LocalPart ::= NCName
7064 *
7065 * Returns the function returns the local part, and prefix is updated
7066 * to get the Prefix if any.
7067 */
7068
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007069static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007070xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7071 xmlChar *ret = NULL;
7072
7073 *prefix = NULL;
7074 ret = xmlXPathParseNCName(ctxt);
7075 if (CUR == ':') {
7076 *prefix = ret;
7077 NEXT;
7078 ret = xmlXPathParseNCName(ctxt);
7079 }
7080 return(ret);
7081}
7082
7083/**
7084 * xmlXPathParseName:
7085 * @ctxt: the XPath Parser context
7086 *
7087 * parse an XML name
7088 *
7089 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7090 * CombiningChar | Extender
7091 *
7092 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7093 *
7094 * Returns the namespace name or NULL
7095 */
7096
7097xmlChar *
7098xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007099 const xmlChar *in;
7100 xmlChar *ret;
7101 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007102
Daniel Veillard61d80a22001-04-27 17:13:01 +00007103 /*
7104 * Accelerator for simple ASCII names
7105 */
7106 in = ctxt->cur;
7107 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7108 ((*in >= 0x41) && (*in <= 0x5A)) ||
7109 (*in == '_') || (*in == ':')) {
7110 in++;
7111 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7112 ((*in >= 0x41) && (*in <= 0x5A)) ||
7113 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007114 (*in == '_') || (*in == '-') ||
7115 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007116 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007117 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007118 count = in - ctxt->cur;
7119 ret = xmlStrndup(ctxt->cur, count);
7120 ctxt->cur = in;
7121 return(ret);
7122 }
7123 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007124 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007125}
7126
Daniel Veillard61d80a22001-04-27 17:13:01 +00007127static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007128xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007129 xmlChar buf[XML_MAX_NAMELEN + 5];
7130 int len = 0, l;
7131 int c;
7132
7133 /*
7134 * Handler for more complex cases
7135 */
7136 c = CUR_CHAR(l);
7137 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007138 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7139 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007140 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007141 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007142 return(NULL);
7143 }
7144
7145 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7146 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7147 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007148 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007149 (IS_COMBINING(c)) ||
7150 (IS_EXTENDER(c)))) {
7151 COPY_BUF(l,buf,len,c);
7152 NEXTL(l);
7153 c = CUR_CHAR(l);
7154 if (len >= XML_MAX_NAMELEN) {
7155 /*
7156 * Okay someone managed to make a huge name, so he's ready to pay
7157 * for the processing speed.
7158 */
7159 xmlChar *buffer;
7160 int max = len * 2;
7161
7162 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7163 if (buffer == NULL) {
7164 XP_ERROR0(XPATH_MEMORY_ERROR);
7165 }
7166 memcpy(buffer, buf, len);
7167 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7168 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007169 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007170 (IS_COMBINING(c)) ||
7171 (IS_EXTENDER(c))) {
7172 if (len + 10 > max) {
7173 max *= 2;
7174 buffer = (xmlChar *) xmlRealloc(buffer,
7175 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007176 if (buffer == NULL) {
7177 XP_ERROR0(XPATH_MEMORY_ERROR);
7178 }
7179 }
7180 COPY_BUF(l,buffer,len,c);
7181 NEXTL(l);
7182 c = CUR_CHAR(l);
7183 }
7184 buffer[len] = 0;
7185 return(buffer);
7186 }
7187 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007188 if (len == 0)
7189 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007190 return(xmlStrndup(buf, len));
7191}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007192
7193#define MAX_FRAC 20
7194
7195static double my_pow10[MAX_FRAC] = {
7196 1.0, 10.0, 100.0, 1000.0, 10000.0,
7197 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7198 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7199 100000000000000.0,
7200 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7201 1000000000000000000.0, 10000000000000000000.0
7202};
7203
Owen Taylor3473f882001-02-23 17:55:21 +00007204/**
7205 * xmlXPathStringEvalNumber:
7206 * @str: A string to scan
7207 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007208 * [30a] Float ::= Number ('e' Digits?)?
7209 *
Owen Taylor3473f882001-02-23 17:55:21 +00007210 * [30] Number ::= Digits ('.' Digits?)?
7211 * | '.' Digits
7212 * [31] Digits ::= [0-9]+
7213 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007214 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007215 * In complement of the Number expression, this function also handles
7216 * negative values : '-' Number.
7217 *
7218 * Returns the double value.
7219 */
7220double
7221xmlXPathStringEvalNumber(const xmlChar *str) {
7222 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007223 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007224 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007225 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007226 int exponent = 0;
7227 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007228#ifdef __GNUC__
7229 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007230 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007231#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007232 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007233 while (IS_BLANK(*cur)) cur++;
7234 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7235 return(xmlXPathNAN);
7236 }
7237 if (*cur == '-') {
7238 isneg = 1;
7239 cur++;
7240 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007241
7242#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007243 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007244 * tmp/temp is a workaround against a gcc compiler bug
7245 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007246 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007247 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007248 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007249 ret = ret * 10;
7250 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007251 ok = 1;
7252 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007253 temp = (double) tmp;
7254 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007255 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007256#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007257 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007258 while ((*cur >= '0') && (*cur <= '9')) {
7259 ret = ret * 10 + (*cur - '0');
7260 ok = 1;
7261 cur++;
7262 }
7263#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007264
Owen Taylor3473f882001-02-23 17:55:21 +00007265 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007266 int v, frac = 0;
7267 double fraction = 0;
7268
Owen Taylor3473f882001-02-23 17:55:21 +00007269 cur++;
7270 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7271 return(xmlXPathNAN);
7272 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007273 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7274 v = (*cur - '0');
7275 fraction = fraction * 10 + v;
7276 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007277 cur++;
7278 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007279 fraction /= my_pow10[frac];
7280 ret = ret + fraction;
7281 while ((*cur >= '0') && (*cur <= '9'))
7282 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007283 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007284 if ((*cur == 'e') || (*cur == 'E')) {
7285 cur++;
7286 if (*cur == '-') {
7287 is_exponent_negative = 1;
7288 cur++;
7289 }
7290 while ((*cur >= '0') && (*cur <= '9')) {
7291 exponent = exponent * 10 + (*cur - '0');
7292 cur++;
7293 }
7294 }
Owen Taylor3473f882001-02-23 17:55:21 +00007295 while (IS_BLANK(*cur)) cur++;
7296 if (*cur != 0) return(xmlXPathNAN);
7297 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007298 if (is_exponent_negative) exponent = -exponent;
7299 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007300 return(ret);
7301}
7302
7303/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007304 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007305 * @ctxt: the XPath Parser context
7306 *
7307 * [30] Number ::= Digits ('.' Digits?)?
7308 * | '.' Digits
7309 * [31] Digits ::= [0-9]+
7310 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007311 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007312 *
7313 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007314static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007315xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7316{
Owen Taylor3473f882001-02-23 17:55:21 +00007317 double ret = 0.0;
7318 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007319 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007320 int exponent = 0;
7321 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007322#ifdef __GNUC__
7323 unsigned long tmp = 0;
7324 double temp;
7325#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007326
7327 CHECK_ERROR;
7328 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7329 XP_ERROR(XPATH_NUMBER_ERROR);
7330 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007331#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007332 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007333 * tmp/temp is a workaround against a gcc compiler bug
7334 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007335 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007336 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007337 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007338 ret = ret * 10;
7339 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007340 ok = 1;
7341 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007342 temp = (double) tmp;
7343 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007344 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007345#else
7346 ret = 0;
7347 while ((CUR >= '0') && (CUR <= '9')) {
7348 ret = ret * 10 + (CUR - '0');
7349 ok = 1;
7350 NEXT;
7351 }
7352#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007353 if (CUR == '.') {
7354 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007355 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7356 XP_ERROR(XPATH_NUMBER_ERROR);
7357 }
7358 while ((CUR >= '0') && (CUR <= '9')) {
7359 mult /= 10;
7360 ret = ret + (CUR - '0') * mult;
7361 NEXT;
7362 }
Owen Taylor3473f882001-02-23 17:55:21 +00007363 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007364 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007365 NEXT;
7366 if (CUR == '-') {
7367 is_exponent_negative = 1;
7368 NEXT;
7369 }
7370 while ((CUR >= '0') && (CUR <= '9')) {
7371 exponent = exponent * 10 + (CUR - '0');
7372 NEXT;
7373 }
7374 if (is_exponent_negative)
7375 exponent = -exponent;
7376 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007377 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007378 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007379 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007380}
7381
7382/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007383 * xmlXPathParseLiteral:
7384 * @ctxt: the XPath Parser context
7385 *
7386 * Parse a Literal
7387 *
7388 * [29] Literal ::= '"' [^"]* '"'
7389 * | "'" [^']* "'"
7390 *
7391 * Returns the value found or NULL in case of error
7392 */
7393static xmlChar *
7394xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7395 const xmlChar *q;
7396 xmlChar *ret = NULL;
7397
7398 if (CUR == '"') {
7399 NEXT;
7400 q = CUR_PTR;
7401 while ((IS_CHAR(CUR)) && (CUR != '"'))
7402 NEXT;
7403 if (!IS_CHAR(CUR)) {
7404 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7405 } else {
7406 ret = xmlStrndup(q, CUR_PTR - q);
7407 NEXT;
7408 }
7409 } else if (CUR == '\'') {
7410 NEXT;
7411 q = CUR_PTR;
7412 while ((IS_CHAR(CUR)) && (CUR != '\''))
7413 NEXT;
7414 if (!IS_CHAR(CUR)) {
7415 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7416 } else {
7417 ret = xmlStrndup(q, CUR_PTR - q);
7418 NEXT;
7419 }
7420 } else {
7421 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7422 }
7423 return(ret);
7424}
7425
7426/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007427 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007428 * @ctxt: the XPath Parser context
7429 *
7430 * Parse a Literal and push it on the stack.
7431 *
7432 * [29] Literal ::= '"' [^"]* '"'
7433 * | "'" [^']* "'"
7434 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007435 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007436 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007437static void
7438xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007439 const xmlChar *q;
7440 xmlChar *ret = NULL;
7441
7442 if (CUR == '"') {
7443 NEXT;
7444 q = CUR_PTR;
7445 while ((IS_CHAR(CUR)) && (CUR != '"'))
7446 NEXT;
7447 if (!IS_CHAR(CUR)) {
7448 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7449 } else {
7450 ret = xmlStrndup(q, CUR_PTR - q);
7451 NEXT;
7452 }
7453 } else if (CUR == '\'') {
7454 NEXT;
7455 q = CUR_PTR;
7456 while ((IS_CHAR(CUR)) && (CUR != '\''))
7457 NEXT;
7458 if (!IS_CHAR(CUR)) {
7459 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7460 } else {
7461 ret = xmlStrndup(q, CUR_PTR - q);
7462 NEXT;
7463 }
7464 } else {
7465 XP_ERROR(XPATH_START_LITERAL_ERROR);
7466 }
7467 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007468 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7469 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007470 xmlFree(ret);
7471}
7472
7473/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007474 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007475 * @ctxt: the XPath Parser context
7476 *
7477 * Parse a VariableReference, evaluate it and push it on the stack.
7478 *
7479 * The variable bindings consist of a mapping from variable names
7480 * to variable values. The value of a variable is an object, which
7481 * of any of the types that are possible for the value of an expression,
7482 * and may also be of additional types not specified here.
7483 *
7484 * Early evaluation is possible since:
7485 * The variable bindings [...] used to evaluate a subexpression are
7486 * always the same as those used to evaluate the containing expression.
7487 *
7488 * [36] VariableReference ::= '$' QName
7489 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007490static void
7491xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007492 xmlChar *name;
7493 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007494
7495 SKIP_BLANKS;
7496 if (CUR != '$') {
7497 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7498 }
7499 NEXT;
7500 name = xmlXPathParseQName(ctxt, &prefix);
7501 if (name == NULL) {
7502 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7503 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007504 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007505 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7506 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007507 SKIP_BLANKS;
7508}
7509
7510/**
7511 * xmlXPathIsNodeType:
7512 * @ctxt: the XPath Parser context
7513 * @name: a name string
7514 *
7515 * Is the name given a NodeType one.
7516 *
7517 * [38] NodeType ::= 'comment'
7518 * | 'text'
7519 * | 'processing-instruction'
7520 * | 'node'
7521 *
7522 * Returns 1 if true 0 otherwise
7523 */
7524int
7525xmlXPathIsNodeType(const xmlChar *name) {
7526 if (name == NULL)
7527 return(0);
7528
Daniel Veillard1971ee22002-01-31 20:29:19 +00007529 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007530 return(1);
7531 if (xmlStrEqual(name, BAD_CAST "text"))
7532 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007533 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007534 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007535 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007536 return(1);
7537 return(0);
7538}
7539
7540/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007541 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007542 * @ctxt: the XPath Parser context
7543 *
7544 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7545 * [17] Argument ::= Expr
7546 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007547 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007548 * pushed on the stack
7549 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007550static void
7551xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007552 xmlChar *name;
7553 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007554 int nbargs = 0;
7555
7556 name = xmlXPathParseQName(ctxt, &prefix);
7557 if (name == NULL) {
7558 XP_ERROR(XPATH_EXPR_ERROR);
7559 }
7560 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007561#ifdef DEBUG_EXPR
7562 if (prefix == NULL)
7563 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7564 name);
7565 else
7566 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7567 prefix, name);
7568#endif
7569
Owen Taylor3473f882001-02-23 17:55:21 +00007570 if (CUR != '(') {
7571 XP_ERROR(XPATH_EXPR_ERROR);
7572 }
7573 NEXT;
7574 SKIP_BLANKS;
7575
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007576 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007577 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007578 int op1 = ctxt->comp->last;
7579 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007580 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007581 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007582 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007583 nbargs++;
7584 if (CUR == ')') break;
7585 if (CUR != ',') {
7586 XP_ERROR(XPATH_EXPR_ERROR);
7587 }
7588 NEXT;
7589 SKIP_BLANKS;
7590 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007591 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7592 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007593 NEXT;
7594 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007595}
7596
7597/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007598 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007599 * @ctxt: the XPath Parser context
7600 *
7601 * [15] PrimaryExpr ::= VariableReference
7602 * | '(' Expr ')'
7603 * | Literal
7604 * | Number
7605 * | FunctionCall
7606 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007607 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007608 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007609static void
7610xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007611 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007612 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007613 else if (CUR == '(') {
7614 NEXT;
7615 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007616 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007617 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007618 if (CUR != ')') {
7619 XP_ERROR(XPATH_EXPR_ERROR);
7620 }
7621 NEXT;
7622 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007623 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007624 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007625 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007626 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007627 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007628 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007629 }
7630 SKIP_BLANKS;
7631}
7632
7633/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007634 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007635 * @ctxt: the XPath Parser context
7636 *
7637 * [20] FilterExpr ::= PrimaryExpr
7638 * | FilterExpr Predicate
7639 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007640 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007641 * Square brackets are used to filter expressions in the same way that
7642 * they are used in location paths. It is an error if the expression to
7643 * be filtered does not evaluate to a node-set. The context node list
7644 * used for evaluating the expression in square brackets is the node-set
7645 * to be filtered listed in document order.
7646 */
7647
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007648static void
7649xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7650 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007651 CHECK_ERROR;
7652 SKIP_BLANKS;
7653
7654 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007655 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007656 SKIP_BLANKS;
7657 }
7658
7659
7660}
7661
7662/**
7663 * xmlXPathScanName:
7664 * @ctxt: the XPath Parser context
7665 *
7666 * Trickery: parse an XML name but without consuming the input flow
7667 * Needed to avoid insanity in the parser state.
7668 *
7669 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7670 * CombiningChar | Extender
7671 *
7672 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7673 *
7674 * [6] Names ::= Name (S Name)*
7675 *
7676 * Returns the Name parsed or NULL
7677 */
7678
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007679static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007680xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7681 xmlChar buf[XML_MAX_NAMELEN];
7682 int len = 0;
7683
7684 SKIP_BLANKS;
7685 if (!IS_LETTER(CUR) && (CUR != '_') &&
7686 (CUR != ':')) {
7687 return(NULL);
7688 }
7689
7690 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7691 (NXT(len) == '.') || (NXT(len) == '-') ||
7692 (NXT(len) == '_') || (NXT(len) == ':') ||
7693 (IS_COMBINING(NXT(len))) ||
7694 (IS_EXTENDER(NXT(len)))) {
7695 buf[len] = NXT(len);
7696 len++;
7697 if (len >= XML_MAX_NAMELEN) {
7698 xmlGenericError(xmlGenericErrorContext,
7699 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7700 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7701 (NXT(len) == '.') || (NXT(len) == '-') ||
7702 (NXT(len) == '_') || (NXT(len) == ':') ||
7703 (IS_COMBINING(NXT(len))) ||
7704 (IS_EXTENDER(NXT(len))))
7705 len++;
7706 break;
7707 }
7708 }
7709 return(xmlStrndup(buf, len));
7710}
7711
7712/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007713 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007714 * @ctxt: the XPath Parser context
7715 *
7716 * [19] PathExpr ::= LocationPath
7717 * | FilterExpr
7718 * | FilterExpr '/' RelativeLocationPath
7719 * | FilterExpr '//' RelativeLocationPath
7720 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007721 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007722 * The / operator and // operators combine an arbitrary expression
7723 * and a relative location path. It is an error if the expression
7724 * does not evaluate to a node-set.
7725 * The / operator does composition in the same way as when / is
7726 * used in a location path. As in location paths, // is short for
7727 * /descendant-or-self::node()/.
7728 */
7729
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007730static void
7731xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007732 int lc = 1; /* Should we branch to LocationPath ? */
7733 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7734
7735 SKIP_BLANKS;
7736 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007737 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007738 lc = 0;
7739 } else if (CUR == '*') {
7740 /* relative or absolute location path */
7741 lc = 1;
7742 } else if (CUR == '/') {
7743 /* relative or absolute location path */
7744 lc = 1;
7745 } else if (CUR == '@') {
7746 /* relative abbreviated attribute location path */
7747 lc = 1;
7748 } else if (CUR == '.') {
7749 /* relative abbreviated attribute location path */
7750 lc = 1;
7751 } else {
7752 /*
7753 * Problem is finding if we have a name here whether it's:
7754 * - a nodetype
7755 * - a function call in which case it's followed by '('
7756 * - an axis in which case it's followed by ':'
7757 * - a element name
7758 * We do an a priori analysis here rather than having to
7759 * maintain parsed token content through the recursive function
7760 * calls. This looks uglier but makes the code quite easier to
7761 * read/write/debug.
7762 */
7763 SKIP_BLANKS;
7764 name = xmlXPathScanName(ctxt);
7765 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7766#ifdef DEBUG_STEP
7767 xmlGenericError(xmlGenericErrorContext,
7768 "PathExpr: Axis\n");
7769#endif
7770 lc = 1;
7771 xmlFree(name);
7772 } else if (name != NULL) {
7773 int len =xmlStrlen(name);
7774 int blank = 0;
7775
7776
7777 while (NXT(len) != 0) {
7778 if (NXT(len) == '/') {
7779 /* element name */
7780#ifdef DEBUG_STEP
7781 xmlGenericError(xmlGenericErrorContext,
7782 "PathExpr: AbbrRelLocation\n");
7783#endif
7784 lc = 1;
7785 break;
7786 } else if (IS_BLANK(NXT(len))) {
7787 /* skip to next */
7788 blank = 1;
7789 } else if (NXT(len) == ':') {
7790#ifdef DEBUG_STEP
7791 xmlGenericError(xmlGenericErrorContext,
7792 "PathExpr: AbbrRelLocation\n");
7793#endif
7794 lc = 1;
7795 break;
7796 } else if ((NXT(len) == '(')) {
7797 /* Note Type or Function */
7798 if (xmlXPathIsNodeType(name)) {
7799#ifdef DEBUG_STEP
7800 xmlGenericError(xmlGenericErrorContext,
7801 "PathExpr: Type search\n");
7802#endif
7803 lc = 1;
7804 } else {
7805#ifdef DEBUG_STEP
7806 xmlGenericError(xmlGenericErrorContext,
7807 "PathExpr: function call\n");
7808#endif
7809 lc = 0;
7810 }
7811 break;
7812 } else if ((NXT(len) == '[')) {
7813 /* element name */
7814#ifdef DEBUG_STEP
7815 xmlGenericError(xmlGenericErrorContext,
7816 "PathExpr: AbbrRelLocation\n");
7817#endif
7818 lc = 1;
7819 break;
7820 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7821 (NXT(len) == '=')) {
7822 lc = 1;
7823 break;
7824 } else {
7825 lc = 1;
7826 break;
7827 }
7828 len++;
7829 }
7830 if (NXT(len) == 0) {
7831#ifdef DEBUG_STEP
7832 xmlGenericError(xmlGenericErrorContext,
7833 "PathExpr: AbbrRelLocation\n");
7834#endif
7835 /* element name */
7836 lc = 1;
7837 }
7838 xmlFree(name);
7839 } else {
7840 /* make sure all cases are covered explicitely */
7841 XP_ERROR(XPATH_EXPR_ERROR);
7842 }
7843 }
7844
7845 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007846 if (CUR == '/') {
7847 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7848 } else {
7849 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007850 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007851 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007852 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007853 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007854 CHECK_ERROR;
7855 if ((CUR == '/') && (NXT(1) == '/')) {
7856 SKIP(2);
7857 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007858
7859 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7860 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7861 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7862
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007863 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007864 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007865 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007866 }
7867 }
7868 SKIP_BLANKS;
7869}
7870
7871/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007872 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007873 * @ctxt: the XPath Parser context
7874 *
7875 * [18] UnionExpr ::= PathExpr
7876 * | UnionExpr '|' PathExpr
7877 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007878 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007879 */
7880
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007881static void
7882xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7883 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007884 CHECK_ERROR;
7885 SKIP_BLANKS;
7886 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007887 int op1 = ctxt->comp->last;
7888 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007889
7890 NEXT;
7891 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007892 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007893
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007894 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7895
Owen Taylor3473f882001-02-23 17:55:21 +00007896 SKIP_BLANKS;
7897 }
Owen Taylor3473f882001-02-23 17:55:21 +00007898}
7899
7900/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007901 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007902 * @ctxt: the XPath Parser context
7903 *
7904 * [27] UnaryExpr ::= UnionExpr
7905 * | '-' UnaryExpr
7906 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007907 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007908 */
7909
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007910static void
7911xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007912 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007913 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007914
7915 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007916 while (CUR == '-') {
7917 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007918 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007919 NEXT;
7920 SKIP_BLANKS;
7921 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007922
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007923 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007924 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007925 if (found) {
7926 if (minus)
7927 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7928 else
7929 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007930 }
7931}
7932
7933/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007934 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007935 * @ctxt: the XPath Parser context
7936 *
7937 * [26] MultiplicativeExpr ::= UnaryExpr
7938 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7939 * | MultiplicativeExpr 'div' UnaryExpr
7940 * | MultiplicativeExpr 'mod' UnaryExpr
7941 * [34] MultiplyOperator ::= '*'
7942 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007943 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007944 */
7945
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007946static void
7947xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7948 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007949 CHECK_ERROR;
7950 SKIP_BLANKS;
7951 while ((CUR == '*') ||
7952 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7953 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7954 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007955 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007956
7957 if (CUR == '*') {
7958 op = 0;
7959 NEXT;
7960 } else if (CUR == 'd') {
7961 op = 1;
7962 SKIP(3);
7963 } else if (CUR == 'm') {
7964 op = 2;
7965 SKIP(3);
7966 }
7967 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007968 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007969 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007970 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007971 SKIP_BLANKS;
7972 }
7973}
7974
7975/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007976 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007977 * @ctxt: the XPath Parser context
7978 *
7979 * [25] AdditiveExpr ::= MultiplicativeExpr
7980 * | AdditiveExpr '+' MultiplicativeExpr
7981 * | AdditiveExpr '-' MultiplicativeExpr
7982 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007983 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007984 */
7985
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007986static void
7987xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007988
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007989 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007990 CHECK_ERROR;
7991 SKIP_BLANKS;
7992 while ((CUR == '+') || (CUR == '-')) {
7993 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007994 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007995
7996 if (CUR == '+') plus = 1;
7997 else plus = 0;
7998 NEXT;
7999 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008000 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008001 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008002 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008003 SKIP_BLANKS;
8004 }
8005}
8006
8007/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008008 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008009 * @ctxt: the XPath Parser context
8010 *
8011 * [24] RelationalExpr ::= AdditiveExpr
8012 * | RelationalExpr '<' AdditiveExpr
8013 * | RelationalExpr '>' AdditiveExpr
8014 * | RelationalExpr '<=' AdditiveExpr
8015 * | RelationalExpr '>=' AdditiveExpr
8016 *
8017 * A <= B > C is allowed ? Answer from James, yes with
8018 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8019 * which is basically what got implemented.
8020 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008021 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008022 * on the stack
8023 */
8024
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008025static void
8026xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8027 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008028 CHECK_ERROR;
8029 SKIP_BLANKS;
8030 while ((CUR == '<') ||
8031 (CUR == '>') ||
8032 ((CUR == '<') && (NXT(1) == '=')) ||
8033 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008034 int inf, strict;
8035 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008036
8037 if (CUR == '<') inf = 1;
8038 else inf = 0;
8039 if (NXT(1) == '=') strict = 0;
8040 else strict = 1;
8041 NEXT;
8042 if (!strict) NEXT;
8043 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008044 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008045 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008046 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008047 SKIP_BLANKS;
8048 }
8049}
8050
8051/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008052 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008053 * @ctxt: the XPath Parser context
8054 *
8055 * [23] EqualityExpr ::= RelationalExpr
8056 * | EqualityExpr '=' RelationalExpr
8057 * | EqualityExpr '!=' RelationalExpr
8058 *
8059 * A != B != C is allowed ? Answer from James, yes with
8060 * (RelationalExpr = RelationalExpr) = RelationalExpr
8061 * (RelationalExpr != RelationalExpr) != RelationalExpr
8062 * which is basically what got implemented.
8063 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008064 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008065 *
8066 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008067static void
8068xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8069 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008070 CHECK_ERROR;
8071 SKIP_BLANKS;
8072 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008073 int eq;
8074 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008075
8076 if (CUR == '=') eq = 1;
8077 else eq = 0;
8078 NEXT;
8079 if (!eq) NEXT;
8080 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008081 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008082 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008083 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008084 SKIP_BLANKS;
8085 }
8086}
8087
8088/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008089 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008090 * @ctxt: the XPath Parser context
8091 *
8092 * [22] AndExpr ::= EqualityExpr
8093 * | AndExpr 'and' EqualityExpr
8094 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008095 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008096 *
8097 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008098static void
8099xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8100 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008101 CHECK_ERROR;
8102 SKIP_BLANKS;
8103 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008104 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008105 SKIP(3);
8106 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008107 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008108 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008109 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008110 SKIP_BLANKS;
8111 }
8112}
8113
8114/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008115 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008116 * @ctxt: the XPath Parser context
8117 *
8118 * [14] Expr ::= OrExpr
8119 * [21] OrExpr ::= AndExpr
8120 * | OrExpr 'or' AndExpr
8121 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008122 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008123 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008124static void
8125xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8126 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008127 CHECK_ERROR;
8128 SKIP_BLANKS;
8129 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008130 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008131 SKIP(2);
8132 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008133 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008134 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008135 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8136 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008137 SKIP_BLANKS;
8138 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008139 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8140 /* more ops could be optimized too */
8141 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8142 }
Owen Taylor3473f882001-02-23 17:55:21 +00008143}
8144
8145/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008146 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008147 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008148 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008149 *
8150 * [8] Predicate ::= '[' PredicateExpr ']'
8151 * [9] PredicateExpr ::= Expr
8152 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008153 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008154 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008155static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008156xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008157 int op1 = ctxt->comp->last;
8158
8159 SKIP_BLANKS;
8160 if (CUR != '[') {
8161 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8162 }
8163 NEXT;
8164 SKIP_BLANKS;
8165
8166 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008167 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008168 CHECK_ERROR;
8169
8170 if (CUR != ']') {
8171 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8172 }
8173
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008174 if (filter)
8175 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8176 else
8177 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008178
8179 NEXT;
8180 SKIP_BLANKS;
8181}
8182
8183/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008184 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008185 * @ctxt: the XPath Parser context
8186 * @test: pointer to a xmlXPathTestVal
8187 * @type: pointer to a xmlXPathTypeVal
8188 * @prefix: placeholder for a possible name prefix
8189 *
8190 * [7] NodeTest ::= NameTest
8191 * | NodeType '(' ')'
8192 * | 'processing-instruction' '(' Literal ')'
8193 *
8194 * [37] NameTest ::= '*'
8195 * | NCName ':' '*'
8196 * | QName
8197 * [38] NodeType ::= 'comment'
8198 * | 'text'
8199 * | 'processing-instruction'
8200 * | 'node'
8201 *
8202 * Returns the name found and update @test, @type and @prefix appropriately
8203 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008204static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008205xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8206 xmlXPathTypeVal *type, const xmlChar **prefix,
8207 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008208 int blanks;
8209
8210 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8211 STRANGE;
8212 return(NULL);
8213 }
8214 *type = 0;
8215 *test = 0;
8216 *prefix = NULL;
8217 SKIP_BLANKS;
8218
8219 if ((name == NULL) && (CUR == '*')) {
8220 /*
8221 * All elements
8222 */
8223 NEXT;
8224 *test = NODE_TEST_ALL;
8225 return(NULL);
8226 }
8227
8228 if (name == NULL)
8229 name = xmlXPathParseNCName(ctxt);
8230 if (name == NULL) {
8231 XP_ERROR0(XPATH_EXPR_ERROR);
8232 }
8233
8234 blanks = IS_BLANK(CUR);
8235 SKIP_BLANKS;
8236 if (CUR == '(') {
8237 NEXT;
8238 /*
8239 * NodeType or PI search
8240 */
8241 if (xmlStrEqual(name, BAD_CAST "comment"))
8242 *type = NODE_TYPE_COMMENT;
8243 else if (xmlStrEqual(name, BAD_CAST "node"))
8244 *type = NODE_TYPE_NODE;
8245 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8246 *type = NODE_TYPE_PI;
8247 else if (xmlStrEqual(name, BAD_CAST "text"))
8248 *type = NODE_TYPE_TEXT;
8249 else {
8250 if (name != NULL)
8251 xmlFree(name);
8252 XP_ERROR0(XPATH_EXPR_ERROR);
8253 }
8254
8255 *test = NODE_TEST_TYPE;
8256
8257 SKIP_BLANKS;
8258 if (*type == NODE_TYPE_PI) {
8259 /*
8260 * Specific case: search a PI by name.
8261 */
Owen Taylor3473f882001-02-23 17:55:21 +00008262 if (name != NULL)
8263 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008264 name = NULL;
8265 if (CUR != ')') {
8266 name = xmlXPathParseLiteral(ctxt);
8267 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008268 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008269 SKIP_BLANKS;
8270 }
Owen Taylor3473f882001-02-23 17:55:21 +00008271 }
8272 if (CUR != ')') {
8273 if (name != NULL)
8274 xmlFree(name);
8275 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8276 }
8277 NEXT;
8278 return(name);
8279 }
8280 *test = NODE_TEST_NAME;
8281 if ((!blanks) && (CUR == ':')) {
8282 NEXT;
8283
8284 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008285 * Since currently the parser context don't have a
8286 * namespace list associated:
8287 * The namespace name for this prefix can be computed
8288 * only at evaluation time. The compilation is done
8289 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008290 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008291#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008292 *prefix = xmlXPathNsLookup(ctxt->context, name);
8293 if (name != NULL)
8294 xmlFree(name);
8295 if (*prefix == NULL) {
8296 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8297 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008298#else
8299 *prefix = name;
8300#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008301
8302 if (CUR == '*') {
8303 /*
8304 * All elements
8305 */
8306 NEXT;
8307 *test = NODE_TEST_ALL;
8308 return(NULL);
8309 }
8310
8311 name = xmlXPathParseNCName(ctxt);
8312 if (name == NULL) {
8313 XP_ERROR0(XPATH_EXPR_ERROR);
8314 }
8315 }
8316 return(name);
8317}
8318
8319/**
8320 * xmlXPathIsAxisName:
8321 * @name: a preparsed name token
8322 *
8323 * [6] AxisName ::= 'ancestor'
8324 * | 'ancestor-or-self'
8325 * | 'attribute'
8326 * | 'child'
8327 * | 'descendant'
8328 * | 'descendant-or-self'
8329 * | 'following'
8330 * | 'following-sibling'
8331 * | 'namespace'
8332 * | 'parent'
8333 * | 'preceding'
8334 * | 'preceding-sibling'
8335 * | 'self'
8336 *
8337 * Returns the axis or 0
8338 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008339static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008340xmlXPathIsAxisName(const xmlChar *name) {
8341 xmlXPathAxisVal ret = 0;
8342 switch (name[0]) {
8343 case 'a':
8344 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8345 ret = AXIS_ANCESTOR;
8346 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8347 ret = AXIS_ANCESTOR_OR_SELF;
8348 if (xmlStrEqual(name, BAD_CAST "attribute"))
8349 ret = AXIS_ATTRIBUTE;
8350 break;
8351 case 'c':
8352 if (xmlStrEqual(name, BAD_CAST "child"))
8353 ret = AXIS_CHILD;
8354 break;
8355 case 'd':
8356 if (xmlStrEqual(name, BAD_CAST "descendant"))
8357 ret = AXIS_DESCENDANT;
8358 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8359 ret = AXIS_DESCENDANT_OR_SELF;
8360 break;
8361 case 'f':
8362 if (xmlStrEqual(name, BAD_CAST "following"))
8363 ret = AXIS_FOLLOWING;
8364 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8365 ret = AXIS_FOLLOWING_SIBLING;
8366 break;
8367 case 'n':
8368 if (xmlStrEqual(name, BAD_CAST "namespace"))
8369 ret = AXIS_NAMESPACE;
8370 break;
8371 case 'p':
8372 if (xmlStrEqual(name, BAD_CAST "parent"))
8373 ret = AXIS_PARENT;
8374 if (xmlStrEqual(name, BAD_CAST "preceding"))
8375 ret = AXIS_PRECEDING;
8376 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8377 ret = AXIS_PRECEDING_SIBLING;
8378 break;
8379 case 's':
8380 if (xmlStrEqual(name, BAD_CAST "self"))
8381 ret = AXIS_SELF;
8382 break;
8383 }
8384 return(ret);
8385}
8386
8387/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008388 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008389 * @ctxt: the XPath Parser context
8390 *
8391 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8392 * | AbbreviatedStep
8393 *
8394 * [12] AbbreviatedStep ::= '.' | '..'
8395 *
8396 * [5] AxisSpecifier ::= AxisName '::'
8397 * | AbbreviatedAxisSpecifier
8398 *
8399 * [13] AbbreviatedAxisSpecifier ::= '@'?
8400 *
8401 * Modified for XPtr range support as:
8402 *
8403 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8404 * | AbbreviatedStep
8405 * | 'range-to' '(' Expr ')' Predicate*
8406 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008407 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008408 * A location step of . is short for self::node(). This is
8409 * particularly useful in conjunction with //. For example, the
8410 * location path .//para is short for
8411 * self::node()/descendant-or-self::node()/child::para
8412 * and so will select all para descendant elements of the context
8413 * node.
8414 * Similarly, a location step of .. is short for parent::node().
8415 * For example, ../title is short for parent::node()/child::title
8416 * and so will select the title children of the parent of the context
8417 * node.
8418 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008419static void
8420xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008421#ifdef LIBXML_XPTR_ENABLED
8422 int rangeto = 0;
8423 int op2 = -1;
8424#endif
8425
Owen Taylor3473f882001-02-23 17:55:21 +00008426 SKIP_BLANKS;
8427 if ((CUR == '.') && (NXT(1) == '.')) {
8428 SKIP(2);
8429 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008430 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8431 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008432 } else if (CUR == '.') {
8433 NEXT;
8434 SKIP_BLANKS;
8435 } else {
8436 xmlChar *name = NULL;
8437 const xmlChar *prefix = NULL;
8438 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008439 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008440 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008441 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008442
8443 /*
8444 * The modification needed for XPointer change to the production
8445 */
8446#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008447 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008448 name = xmlXPathParseNCName(ctxt);
8449 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008450 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008451 xmlFree(name);
8452 SKIP_BLANKS;
8453 if (CUR != '(') {
8454 XP_ERROR(XPATH_EXPR_ERROR);
8455 }
8456 NEXT;
8457 SKIP_BLANKS;
8458
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008459 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008460 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008461 CHECK_ERROR;
8462
8463 SKIP_BLANKS;
8464 if (CUR != ')') {
8465 XP_ERROR(XPATH_EXPR_ERROR);
8466 }
8467 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008468 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008469 goto eval_predicates;
8470 }
8471 }
8472#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008473 if (CUR == '*') {
8474 axis = AXIS_CHILD;
8475 } else {
8476 if (name == NULL)
8477 name = xmlXPathParseNCName(ctxt);
8478 if (name != NULL) {
8479 axis = xmlXPathIsAxisName(name);
8480 if (axis != 0) {
8481 SKIP_BLANKS;
8482 if ((CUR == ':') && (NXT(1) == ':')) {
8483 SKIP(2);
8484 xmlFree(name);
8485 name = NULL;
8486 } else {
8487 /* an element name can conflict with an axis one :-\ */
8488 axis = AXIS_CHILD;
8489 }
Owen Taylor3473f882001-02-23 17:55:21 +00008490 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008491 axis = AXIS_CHILD;
8492 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008493 } else if (CUR == '@') {
8494 NEXT;
8495 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008496 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008497 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008498 }
Owen Taylor3473f882001-02-23 17:55:21 +00008499 }
8500
8501 CHECK_ERROR;
8502
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008503 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008504 if (test == 0)
8505 return;
8506
8507#ifdef DEBUG_STEP
8508 xmlGenericError(xmlGenericErrorContext,
8509 "Basis : computing new set\n");
8510#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008511
Owen Taylor3473f882001-02-23 17:55:21 +00008512#ifdef DEBUG_STEP
8513 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008514 if (ctxt->value == NULL)
8515 xmlGenericError(xmlGenericErrorContext, "no value\n");
8516 else if (ctxt->value->nodesetval == NULL)
8517 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8518 else
8519 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008520#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008521
8522eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008523 op1 = ctxt->comp->last;
8524 ctxt->comp->last = -1;
8525
Owen Taylor3473f882001-02-23 17:55:21 +00008526 SKIP_BLANKS;
8527 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008528 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008529 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008530
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008531#ifdef LIBXML_XPTR_ENABLED
8532 if (rangeto) {
8533 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8534 } else
8535#endif
8536 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8537 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008538
Owen Taylor3473f882001-02-23 17:55:21 +00008539 }
8540#ifdef DEBUG_STEP
8541 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008542 if (ctxt->value == NULL)
8543 xmlGenericError(xmlGenericErrorContext, "no value\n");
8544 else if (ctxt->value->nodesetval == NULL)
8545 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8546 else
8547 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8548 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008549#endif
8550}
8551
8552/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008553 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008554 * @ctxt: the XPath Parser context
8555 *
8556 * [3] RelativeLocationPath ::= Step
8557 * | RelativeLocationPath '/' Step
8558 * | AbbreviatedRelativeLocationPath
8559 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8560 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008561 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008562 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008563static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008564xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008565(xmlXPathParserContextPtr ctxt) {
8566 SKIP_BLANKS;
8567 if ((CUR == '/') && (NXT(1) == '/')) {
8568 SKIP(2);
8569 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008570 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8571 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008572 } else if (CUR == '/') {
8573 NEXT;
8574 SKIP_BLANKS;
8575 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008576 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008577 SKIP_BLANKS;
8578 while (CUR == '/') {
8579 if ((CUR == '/') && (NXT(1) == '/')) {
8580 SKIP(2);
8581 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008582 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008583 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008584 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008585 } else if (CUR == '/') {
8586 NEXT;
8587 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008588 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008589 }
8590 SKIP_BLANKS;
8591 }
8592}
8593
8594/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008595 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008596 * @ctxt: the XPath Parser context
8597 *
8598 * [1] LocationPath ::= RelativeLocationPath
8599 * | AbsoluteLocationPath
8600 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8601 * | AbbreviatedAbsoluteLocationPath
8602 * [10] AbbreviatedAbsoluteLocationPath ::=
8603 * '//' RelativeLocationPath
8604 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008605 * Compile a location path
8606 *
Owen Taylor3473f882001-02-23 17:55:21 +00008607 * // is short for /descendant-or-self::node()/. For example,
8608 * //para is short for /descendant-or-self::node()/child::para and
8609 * so will select any para element in the document (even a para element
8610 * that is a document element will be selected by //para since the
8611 * document element node is a child of the root node); div//para is
8612 * short for div/descendant-or-self::node()/child::para and so will
8613 * select all para descendants of div children.
8614 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008615static void
8616xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008617 SKIP_BLANKS;
8618 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008619 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008620 } else {
8621 while (CUR == '/') {
8622 if ((CUR == '/') && (NXT(1) == '/')) {
8623 SKIP(2);
8624 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008625 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8626 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008627 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008628 } else if (CUR == '/') {
8629 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008630 SKIP_BLANKS;
8631 if ((CUR != 0 ) &&
8632 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8633 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008634 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008635 }
8636 }
8637 }
8638}
8639
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008640/************************************************************************
8641 * *
8642 * XPath precompiled expression evaluation *
8643 * *
8644 ************************************************************************/
8645
Daniel Veillardf06307e2001-07-03 10:35:50 +00008646static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008647xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8648
8649/**
8650 * xmlXPathNodeCollectAndTest:
8651 * @ctxt: the XPath Parser context
8652 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008653 * @first: pointer to the first element in document order
8654 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008655 *
8656 * This is the function implementing a step: based on the current list
8657 * of nodes, it builds up a new list, looking at all nodes under that
8658 * axis and selecting them it also do the predicate filtering
8659 *
8660 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008661 *
8662 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008663 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008664static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008665xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008666 xmlXPathStepOpPtr op,
8667 xmlNodePtr * first, xmlNodePtr * last)
8668{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008669 xmlXPathAxisVal axis = op->value;
8670 xmlXPathTestVal test = op->value2;
8671 xmlXPathTypeVal type = op->value3;
8672 const xmlChar *prefix = op->value4;
8673 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008674 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008675
8676#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008677 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008678#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008679 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008680 xmlNodeSetPtr ret, list;
8681 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008682 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008683 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008684 xmlNodePtr cur = NULL;
8685 xmlXPathObjectPtr obj;
8686 xmlNodeSetPtr nodelist;
8687 xmlNodePtr tmp;
8688
Daniel Veillardf06307e2001-07-03 10:35:50 +00008689 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008690 obj = valuePop(ctxt);
8691 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008692 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008693 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008694 URI = xmlXPathNsLookup(ctxt->context, prefix);
8695 if (URI == NULL)
8696 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008697 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008698#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008699 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008700#endif
8701 switch (axis) {
8702 case AXIS_ANCESTOR:
8703#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008704 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008705#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008706 first = NULL;
8707 next = xmlXPathNextAncestor;
8708 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008709 case AXIS_ANCESTOR_OR_SELF:
8710#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008711 xmlGenericError(xmlGenericErrorContext,
8712 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008713#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008714 first = NULL;
8715 next = xmlXPathNextAncestorOrSelf;
8716 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008717 case AXIS_ATTRIBUTE:
8718#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008719 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008720#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008721 first = NULL;
8722 last = NULL;
8723 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008724 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008725 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008726 case AXIS_CHILD:
8727#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008728 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008729#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008730 last = NULL;
8731 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008732 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008733 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008734 case AXIS_DESCENDANT:
8735#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008736 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008737#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008738 last = NULL;
8739 next = xmlXPathNextDescendant;
8740 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008741 case AXIS_DESCENDANT_OR_SELF:
8742#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008743 xmlGenericError(xmlGenericErrorContext,
8744 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008745#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008746 last = NULL;
8747 next = xmlXPathNextDescendantOrSelf;
8748 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008749 case AXIS_FOLLOWING:
8750#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008751 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008752#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008753 last = NULL;
8754 next = xmlXPathNextFollowing;
8755 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008756 case AXIS_FOLLOWING_SIBLING:
8757#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008758 xmlGenericError(xmlGenericErrorContext,
8759 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008760#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008761 last = NULL;
8762 next = xmlXPathNextFollowingSibling;
8763 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008764 case AXIS_NAMESPACE:
8765#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008766 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008767#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008768 first = NULL;
8769 last = NULL;
8770 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008771 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008772 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008773 case AXIS_PARENT:
8774#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008775 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008776#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008777 first = NULL;
8778 next = xmlXPathNextParent;
8779 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008780 case AXIS_PRECEDING:
8781#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008782 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008783#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008784 first = NULL;
8785 next = xmlXPathNextPrecedingInternal;
8786 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008787 case AXIS_PRECEDING_SIBLING:
8788#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008789 xmlGenericError(xmlGenericErrorContext,
8790 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008791#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008792 first = NULL;
8793 next = xmlXPathNextPrecedingSibling;
8794 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008795 case AXIS_SELF:
8796#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008797 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008798#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008799 first = NULL;
8800 last = NULL;
8801 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008802 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008803 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008804 }
8805 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008806 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008807
8808 nodelist = obj->nodesetval;
8809 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008810 xmlXPathFreeObject(obj);
8811 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8812 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008813 }
8814 addNode = xmlXPathNodeSetAddUnique;
8815 ret = NULL;
8816#ifdef DEBUG_STEP
8817 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008818 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008819 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008820 case NODE_TEST_NONE:
8821 xmlGenericError(xmlGenericErrorContext,
8822 " searching for none !!!\n");
8823 break;
8824 case NODE_TEST_TYPE:
8825 xmlGenericError(xmlGenericErrorContext,
8826 " searching for type %d\n", type);
8827 break;
8828 case NODE_TEST_PI:
8829 xmlGenericError(xmlGenericErrorContext,
8830 " searching for PI !!!\n");
8831 break;
8832 case NODE_TEST_ALL:
8833 xmlGenericError(xmlGenericErrorContext,
8834 " searching for *\n");
8835 break;
8836 case NODE_TEST_NS:
8837 xmlGenericError(xmlGenericErrorContext,
8838 " searching for namespace %s\n",
8839 prefix);
8840 break;
8841 case NODE_TEST_NAME:
8842 xmlGenericError(xmlGenericErrorContext,
8843 " searching for name %s\n", name);
8844 if (prefix != NULL)
8845 xmlGenericError(xmlGenericErrorContext,
8846 " with namespace %s\n", prefix);
8847 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008848 }
8849 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8850#endif
8851 /*
8852 * 2.3 Node Tests
8853 * - For the attribute axis, the principal node type is attribute.
8854 * - For the namespace axis, the principal node type is namespace.
8855 * - For other axes, the principal node type is element.
8856 *
8857 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008858 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008859 * select all element children of the context node
8860 */
8861 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008862 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008863 ctxt->context->node = nodelist->nodeTab[i];
8864
Daniel Veillardf06307e2001-07-03 10:35:50 +00008865 cur = NULL;
8866 list = xmlXPathNodeSetCreate(NULL);
8867 do {
8868 cur = next(ctxt, cur);
8869 if (cur == NULL)
8870 break;
8871 if ((first != NULL) && (*first == cur))
8872 break;
8873 if (((t % 256) == 0) &&
8874 (first != NULL) && (*first != NULL) &&
8875 (xmlXPathCmpNodes(*first, cur) >= 0))
8876 break;
8877 if ((last != NULL) && (*last == cur))
8878 break;
8879 if (((t % 256) == 0) &&
8880 (last != NULL) && (*last != NULL) &&
8881 (xmlXPathCmpNodes(cur, *last) >= 0))
8882 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008883 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008884#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008885 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8886#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008887 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008888 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008889 ctxt->context->node = tmp;
8890 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008891 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008892 if ((cur->type == type) ||
8893 ((type == NODE_TYPE_NODE) &&
8894 ((cur->type == XML_DOCUMENT_NODE) ||
8895 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8896 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008897 (cur->type == XML_NAMESPACE_DECL) ||
8898 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008899 (cur->type == XML_PI_NODE) ||
8900 (cur->type == XML_COMMENT_NODE) ||
8901 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008902 (cur->type == XML_TEXT_NODE))) ||
8903 ((type == NODE_TYPE_TEXT) &&
8904 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008905#ifdef DEBUG_STEP
8906 n++;
8907#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008908 addNode(list, cur);
8909 }
8910 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008911 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 if (cur->type == XML_PI_NODE) {
8913 if ((name != NULL) &&
8914 (!xmlStrEqual(name, cur->name)))
8915 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008916#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008918#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_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008923 if (axis == AXIS_ATTRIBUTE) {
8924 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008925#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008926 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008927#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008928 addNode(list, cur);
8929 }
8930 } else if (axis == AXIS_NAMESPACE) {
8931 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008932#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008933 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008934#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008935 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8936 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008937 }
8938 } else {
8939 if (cur->type == XML_ELEMENT_NODE) {
8940 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008941#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008942 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008943#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008944 addNode(list, cur);
8945 } else if ((cur->ns != NULL) &&
8946 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008947#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008948 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008949#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008950 addNode(list, cur);
8951 }
8952 }
8953 }
8954 break;
8955 case NODE_TEST_NS:{
8956 TODO;
8957 break;
8958 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008959 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008960 switch (cur->type) {
8961 case XML_ELEMENT_NODE:
8962 if (xmlStrEqual(name, cur->name)) {
8963 if (prefix == NULL) {
8964 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008965#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008966 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008967#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008968 addNode(list, cur);
8969 }
8970 } else {
8971 if ((cur->ns != NULL) &&
8972 (xmlStrEqual(URI,
8973 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008974#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008976#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008977 addNode(list, cur);
8978 }
8979 }
8980 }
8981 break;
8982 case XML_ATTRIBUTE_NODE:{
8983 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008984
Daniel Veillardf06307e2001-07-03 10:35:50 +00008985 if (xmlStrEqual(name, attr->name)) {
8986 if (prefix == NULL) {
8987 if ((attr->ns == NULL) ||
8988 (attr->ns->prefix == NULL)) {
8989#ifdef DEBUG_STEP
8990 n++;
8991#endif
8992 addNode(list,
8993 (xmlNodePtr) attr);
8994 }
8995 } else {
8996 if ((attr->ns != NULL) &&
8997 (xmlStrEqual(URI,
8998 attr->ns->
8999 href))) {
9000#ifdef DEBUG_STEP
9001 n++;
9002#endif
9003 addNode(list,
9004 (xmlNodePtr) attr);
9005 }
9006 }
9007 }
9008 break;
9009 }
9010 case XML_NAMESPACE_DECL:
9011 if (cur->type == XML_NAMESPACE_DECL) {
9012 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009013
Daniel Veillardf06307e2001-07-03 10:35:50 +00009014 if ((ns->prefix != NULL) && (name != NULL)
9015 && (xmlStrEqual(ns->prefix, name))) {
9016#ifdef DEBUG_STEP
9017 n++;
9018#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009019 xmlXPathNodeSetAddNs(list,
9020 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009021 }
9022 }
9023 break;
9024 default:
9025 break;
9026 }
9027 break;
9028 break;
9029 }
9030 } while (cur != NULL);
9031
9032 /*
9033 * If there is some predicate filtering do it now
9034 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009035 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009036 xmlXPathObjectPtr obj2;
9037
9038 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9039 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9040 CHECK_TYPE0(XPATH_NODESET);
9041 obj2 = valuePop(ctxt);
9042 list = obj2->nodesetval;
9043 obj2->nodesetval = NULL;
9044 xmlXPathFreeObject(obj2);
9045 }
9046 if (ret == NULL) {
9047 ret = list;
9048 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009049 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009050 xmlXPathFreeNodeSet(list);
9051 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009052 }
9053 ctxt->context->node = tmp;
9054#ifdef DEBUG_STEP
9055 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009056 "\nExamined %d nodes, found %d nodes at that step\n",
9057 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009058#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009059 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009060 if ((obj->boolval) && (obj->user != NULL)) {
9061 ctxt->value->boolval = 1;
9062 ctxt->value->user = obj->user;
9063 obj->user = NULL;
9064 obj->boolval = 0;
9065 }
9066 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009067 return(t);
9068}
9069
9070/**
9071 * xmlXPathNodeCollectAndTestNth:
9072 * @ctxt: the XPath Parser context
9073 * @op: the XPath precompiled step operation
9074 * @indx: the index to collect
9075 * @first: pointer to the first element in document order
9076 * @last: pointer to the last element in document order
9077 *
9078 * This is the function implementing a step: based on the current list
9079 * of nodes, it builds up a new list, looking at all nodes under that
9080 * axis and selecting them it also do the predicate filtering
9081 *
9082 * Pushes the new NodeSet resulting from the search.
9083 * Returns the number of node traversed
9084 */
9085static int
9086xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9087 xmlXPathStepOpPtr op, int indx,
9088 xmlNodePtr * first, xmlNodePtr * last)
9089{
9090 xmlXPathAxisVal axis = op->value;
9091 xmlXPathTestVal test = op->value2;
9092 xmlXPathTypeVal type = op->value3;
9093 const xmlChar *prefix = op->value4;
9094 const xmlChar *name = op->value5;
9095 const xmlChar *URI = NULL;
9096 int n = 0, t = 0;
9097
9098 int i;
9099 xmlNodeSetPtr list;
9100 xmlXPathTraversalFunction next = NULL;
9101 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9102 xmlNodePtr cur = NULL;
9103 xmlXPathObjectPtr obj;
9104 xmlNodeSetPtr nodelist;
9105 xmlNodePtr tmp;
9106
9107 CHECK_TYPE0(XPATH_NODESET);
9108 obj = valuePop(ctxt);
9109 addNode = xmlXPathNodeSetAdd;
9110 if (prefix != NULL) {
9111 URI = xmlXPathNsLookup(ctxt->context, prefix);
9112 if (URI == NULL)
9113 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9114 }
9115#ifdef DEBUG_STEP_NTH
9116 xmlGenericError(xmlGenericErrorContext, "new step : ");
9117 if (first != NULL) {
9118 if (*first != NULL)
9119 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9120 (*first)->name);
9121 else
9122 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9123 }
9124 if (last != NULL) {
9125 if (*last != NULL)
9126 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9127 (*last)->name);
9128 else
9129 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9130 }
9131#endif
9132 switch (axis) {
9133 case AXIS_ANCESTOR:
9134#ifdef DEBUG_STEP_NTH
9135 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9136#endif
9137 first = NULL;
9138 next = xmlXPathNextAncestor;
9139 break;
9140 case AXIS_ANCESTOR_OR_SELF:
9141#ifdef DEBUG_STEP_NTH
9142 xmlGenericError(xmlGenericErrorContext,
9143 "axis 'ancestors-or-self' ");
9144#endif
9145 first = NULL;
9146 next = xmlXPathNextAncestorOrSelf;
9147 break;
9148 case AXIS_ATTRIBUTE:
9149#ifdef DEBUG_STEP_NTH
9150 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9151#endif
9152 first = NULL;
9153 last = NULL;
9154 next = xmlXPathNextAttribute;
9155 break;
9156 case AXIS_CHILD:
9157#ifdef DEBUG_STEP_NTH
9158 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9159#endif
9160 last = NULL;
9161 next = xmlXPathNextChild;
9162 break;
9163 case AXIS_DESCENDANT:
9164#ifdef DEBUG_STEP_NTH
9165 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9166#endif
9167 last = NULL;
9168 next = xmlXPathNextDescendant;
9169 break;
9170 case AXIS_DESCENDANT_OR_SELF:
9171#ifdef DEBUG_STEP_NTH
9172 xmlGenericError(xmlGenericErrorContext,
9173 "axis 'descendant-or-self' ");
9174#endif
9175 last = NULL;
9176 next = xmlXPathNextDescendantOrSelf;
9177 break;
9178 case AXIS_FOLLOWING:
9179#ifdef DEBUG_STEP_NTH
9180 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9181#endif
9182 last = NULL;
9183 next = xmlXPathNextFollowing;
9184 break;
9185 case AXIS_FOLLOWING_SIBLING:
9186#ifdef DEBUG_STEP_NTH
9187 xmlGenericError(xmlGenericErrorContext,
9188 "axis 'following-siblings' ");
9189#endif
9190 last = NULL;
9191 next = xmlXPathNextFollowingSibling;
9192 break;
9193 case AXIS_NAMESPACE:
9194#ifdef DEBUG_STEP_NTH
9195 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9196#endif
9197 last = NULL;
9198 first = NULL;
9199 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9200 break;
9201 case AXIS_PARENT:
9202#ifdef DEBUG_STEP_NTH
9203 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9204#endif
9205 first = NULL;
9206 next = xmlXPathNextParent;
9207 break;
9208 case AXIS_PRECEDING:
9209#ifdef DEBUG_STEP_NTH
9210 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9211#endif
9212 first = NULL;
9213 next = xmlXPathNextPrecedingInternal;
9214 break;
9215 case AXIS_PRECEDING_SIBLING:
9216#ifdef DEBUG_STEP_NTH
9217 xmlGenericError(xmlGenericErrorContext,
9218 "axis 'preceding-sibling' ");
9219#endif
9220 first = NULL;
9221 next = xmlXPathNextPrecedingSibling;
9222 break;
9223 case AXIS_SELF:
9224#ifdef DEBUG_STEP_NTH
9225 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9226#endif
9227 first = NULL;
9228 last = NULL;
9229 next = xmlXPathNextSelf;
9230 break;
9231 }
9232 if (next == NULL)
9233 return(0);
9234
9235 nodelist = obj->nodesetval;
9236 if (nodelist == NULL) {
9237 xmlXPathFreeObject(obj);
9238 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9239 return(0);
9240 }
9241 addNode = xmlXPathNodeSetAddUnique;
9242#ifdef DEBUG_STEP_NTH
9243 xmlGenericError(xmlGenericErrorContext,
9244 " context contains %d nodes\n", nodelist->nodeNr);
9245 switch (test) {
9246 case NODE_TEST_NONE:
9247 xmlGenericError(xmlGenericErrorContext,
9248 " searching for none !!!\n");
9249 break;
9250 case NODE_TEST_TYPE:
9251 xmlGenericError(xmlGenericErrorContext,
9252 " searching for type %d\n", type);
9253 break;
9254 case NODE_TEST_PI:
9255 xmlGenericError(xmlGenericErrorContext,
9256 " searching for PI !!!\n");
9257 break;
9258 case NODE_TEST_ALL:
9259 xmlGenericError(xmlGenericErrorContext,
9260 " searching for *\n");
9261 break;
9262 case NODE_TEST_NS:
9263 xmlGenericError(xmlGenericErrorContext,
9264 " searching for namespace %s\n",
9265 prefix);
9266 break;
9267 case NODE_TEST_NAME:
9268 xmlGenericError(xmlGenericErrorContext,
9269 " searching for name %s\n", name);
9270 if (prefix != NULL)
9271 xmlGenericError(xmlGenericErrorContext,
9272 " with namespace %s\n", prefix);
9273 break;
9274 }
9275 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9276#endif
9277 /*
9278 * 2.3 Node Tests
9279 * - For the attribute axis, the principal node type is attribute.
9280 * - For the namespace axis, the principal node type is namespace.
9281 * - For other axes, the principal node type is element.
9282 *
9283 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009284 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009285 * select all element children of the context node
9286 */
9287 tmp = ctxt->context->node;
9288 list = xmlXPathNodeSetCreate(NULL);
9289 for (i = 0; i < nodelist->nodeNr; i++) {
9290 ctxt->context->node = nodelist->nodeTab[i];
9291
9292 cur = NULL;
9293 n = 0;
9294 do {
9295 cur = next(ctxt, cur);
9296 if (cur == NULL)
9297 break;
9298 if ((first != NULL) && (*first == cur))
9299 break;
9300 if (((t % 256) == 0) &&
9301 (first != NULL) && (*first != NULL) &&
9302 (xmlXPathCmpNodes(*first, cur) >= 0))
9303 break;
9304 if ((last != NULL) && (*last == cur))
9305 break;
9306 if (((t % 256) == 0) &&
9307 (last != NULL) && (*last != NULL) &&
9308 (xmlXPathCmpNodes(cur, *last) >= 0))
9309 break;
9310 t++;
9311 switch (test) {
9312 case NODE_TEST_NONE:
9313 ctxt->context->node = tmp;
9314 STRANGE return(0);
9315 case NODE_TEST_TYPE:
9316 if ((cur->type == type) ||
9317 ((type == NODE_TYPE_NODE) &&
9318 ((cur->type == XML_DOCUMENT_NODE) ||
9319 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9320 (cur->type == XML_ELEMENT_NODE) ||
9321 (cur->type == XML_PI_NODE) ||
9322 (cur->type == XML_COMMENT_NODE) ||
9323 (cur->type == XML_CDATA_SECTION_NODE) ||
9324 (cur->type == XML_TEXT_NODE)))) {
9325 n++;
9326 if (n == indx)
9327 addNode(list, cur);
9328 }
9329 break;
9330 case NODE_TEST_PI:
9331 if (cur->type == XML_PI_NODE) {
9332 if ((name != NULL) &&
9333 (!xmlStrEqual(name, cur->name)))
9334 break;
9335 n++;
9336 if (n == indx)
9337 addNode(list, cur);
9338 }
9339 break;
9340 case NODE_TEST_ALL:
9341 if (axis == AXIS_ATTRIBUTE) {
9342 if (cur->type == XML_ATTRIBUTE_NODE) {
9343 n++;
9344 if (n == indx)
9345 addNode(list, cur);
9346 }
9347 } else if (axis == AXIS_NAMESPACE) {
9348 if (cur->type == XML_NAMESPACE_DECL) {
9349 n++;
9350 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009351 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9352 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009353 }
9354 } else {
9355 if (cur->type == XML_ELEMENT_NODE) {
9356 if (prefix == NULL) {
9357 n++;
9358 if (n == indx)
9359 addNode(list, cur);
9360 } else if ((cur->ns != NULL) &&
9361 (xmlStrEqual(URI, cur->ns->href))) {
9362 n++;
9363 if (n == indx)
9364 addNode(list, cur);
9365 }
9366 }
9367 }
9368 break;
9369 case NODE_TEST_NS:{
9370 TODO;
9371 break;
9372 }
9373 case NODE_TEST_NAME:
9374 switch (cur->type) {
9375 case XML_ELEMENT_NODE:
9376 if (xmlStrEqual(name, cur->name)) {
9377 if (prefix == NULL) {
9378 if (cur->ns == NULL) {
9379 n++;
9380 if (n == indx)
9381 addNode(list, cur);
9382 }
9383 } else {
9384 if ((cur->ns != NULL) &&
9385 (xmlStrEqual(URI,
9386 cur->ns->href))) {
9387 n++;
9388 if (n == indx)
9389 addNode(list, cur);
9390 }
9391 }
9392 }
9393 break;
9394 case XML_ATTRIBUTE_NODE:{
9395 xmlAttrPtr attr = (xmlAttrPtr) cur;
9396
9397 if (xmlStrEqual(name, attr->name)) {
9398 if (prefix == NULL) {
9399 if ((attr->ns == NULL) ||
9400 (attr->ns->prefix == NULL)) {
9401 n++;
9402 if (n == indx)
9403 addNode(list, cur);
9404 }
9405 } else {
9406 if ((attr->ns != NULL) &&
9407 (xmlStrEqual(URI,
9408 attr->ns->
9409 href))) {
9410 n++;
9411 if (n == indx)
9412 addNode(list, cur);
9413 }
9414 }
9415 }
9416 break;
9417 }
9418 case XML_NAMESPACE_DECL:
9419 if (cur->type == XML_NAMESPACE_DECL) {
9420 xmlNsPtr ns = (xmlNsPtr) cur;
9421
9422 if ((ns->prefix != NULL) && (name != NULL)
9423 && (xmlStrEqual(ns->prefix, name))) {
9424 n++;
9425 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009426 xmlXPathNodeSetAddNs(list,
9427 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009428 }
9429 }
9430 break;
9431 default:
9432 break;
9433 }
9434 break;
9435 break;
9436 }
9437 } while (n < indx);
9438 }
9439 ctxt->context->node = tmp;
9440#ifdef DEBUG_STEP_NTH
9441 xmlGenericError(xmlGenericErrorContext,
9442 "\nExamined %d nodes, found %d nodes at that step\n",
9443 t, list->nodeNr);
9444#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009445 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009446 if ((obj->boolval) && (obj->user != NULL)) {
9447 ctxt->value->boolval = 1;
9448 ctxt->value->user = obj->user;
9449 obj->user = NULL;
9450 obj->boolval = 0;
9451 }
9452 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009453 return(t);
9454}
9455
9456/**
9457 * xmlXPathCompOpEvalFirst:
9458 * @ctxt: the XPath parser context with the compiled expression
9459 * @op: an XPath compiled operation
9460 * @first: the first elem found so far
9461 *
9462 * Evaluate the Precompiled XPath operation searching only the first
9463 * element in document order
9464 *
9465 * Returns the number of examined objects.
9466 */
9467static int
9468xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9469 xmlXPathStepOpPtr op, xmlNodePtr * first)
9470{
9471 int total = 0, cur;
9472 xmlXPathCompExprPtr comp;
9473 xmlXPathObjectPtr arg1, arg2;
9474
Daniel Veillard556c6682001-10-06 09:59:51 +00009475 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009476 comp = ctxt->comp;
9477 switch (op->op) {
9478 case XPATH_OP_END:
9479 return (0);
9480 case XPATH_OP_UNION:
9481 total =
9482 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9483 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009484 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009485 if ((ctxt->value != NULL)
9486 && (ctxt->value->type == XPATH_NODESET)
9487 && (ctxt->value->nodesetval != NULL)
9488 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9489 /*
9490 * limit tree traversing to first node in the result
9491 */
9492 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9493 *first = ctxt->value->nodesetval->nodeTab[0];
9494 }
9495 cur =
9496 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9497 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009498 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009499 CHECK_TYPE0(XPATH_NODESET);
9500 arg2 = valuePop(ctxt);
9501
9502 CHECK_TYPE0(XPATH_NODESET);
9503 arg1 = valuePop(ctxt);
9504
9505 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9506 arg2->nodesetval);
9507 valuePush(ctxt, arg1);
9508 xmlXPathFreeObject(arg2);
9509 /* optimizer */
9510 if (total > cur)
9511 xmlXPathCompSwap(op);
9512 return (total + cur);
9513 case XPATH_OP_ROOT:
9514 xmlXPathRoot(ctxt);
9515 return (0);
9516 case XPATH_OP_NODE:
9517 if (op->ch1 != -1)
9518 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009519 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009520 if (op->ch2 != -1)
9521 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009522 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009523 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9524 return (total);
9525 case XPATH_OP_RESET:
9526 if (op->ch1 != -1)
9527 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009528 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009529 if (op->ch2 != -1)
9530 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009531 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009532 ctxt->context->node = NULL;
9533 return (total);
9534 case XPATH_OP_COLLECT:{
9535 if (op->ch1 == -1)
9536 return (total);
9537
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
9541 /*
9542 * Optimization for [n] selection where n is a number
9543 */
9544 if ((op->ch2 != -1) &&
9545 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9546 (comp->steps[op->ch2].ch1 == -1) &&
9547 (comp->steps[op->ch2].ch2 != -1) &&
9548 (comp->steps[comp->steps[op->ch2].ch2].op ==
9549 XPATH_OP_VALUE)) {
9550 xmlXPathObjectPtr val;
9551
9552 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9553 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9554 int indx = (int) val->floatval;
9555
9556 if (val->floatval == (float) indx) {
9557 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9558 first, NULL);
9559 return (total);
9560 }
9561 }
9562 }
9563 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9564 return (total);
9565 }
9566 case XPATH_OP_VALUE:
9567 valuePush(ctxt,
9568 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9569 return (0);
9570 case XPATH_OP_SORT:
9571 if (op->ch1 != -1)
9572 total +=
9573 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9574 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009575 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009576 if ((ctxt->value != NULL)
9577 && (ctxt->value->type == XPATH_NODESET)
9578 && (ctxt->value->nodesetval != NULL))
9579 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9580 return (total);
9581 default:
9582 return (xmlXPathCompOpEval(ctxt, op));
9583 }
9584}
9585
9586/**
9587 * xmlXPathCompOpEvalLast:
9588 * @ctxt: the XPath parser context with the compiled expression
9589 * @op: an XPath compiled operation
9590 * @last: the last elem found so far
9591 *
9592 * Evaluate the Precompiled XPath operation searching only the last
9593 * element in document order
9594 *
9595 * Returns the number of node traversed
9596 */
9597static int
9598xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9599 xmlNodePtr * last)
9600{
9601 int total = 0, cur;
9602 xmlXPathCompExprPtr comp;
9603 xmlXPathObjectPtr arg1, arg2;
9604
Daniel Veillard556c6682001-10-06 09:59:51 +00009605 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009606 comp = ctxt->comp;
9607 switch (op->op) {
9608 case XPATH_OP_END:
9609 return (0);
9610 case XPATH_OP_UNION:
9611 total =
9612 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009613 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009614 if ((ctxt->value != NULL)
9615 && (ctxt->value->type == XPATH_NODESET)
9616 && (ctxt->value->nodesetval != NULL)
9617 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9618 /*
9619 * limit tree traversing to first node in the result
9620 */
9621 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9622 *last =
9623 ctxt->value->nodesetval->nodeTab[ctxt->value->
9624 nodesetval->nodeNr -
9625 1];
9626 }
9627 cur =
9628 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009629 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009630 if ((ctxt->value != NULL)
9631 && (ctxt->value->type == XPATH_NODESET)
9632 && (ctxt->value->nodesetval != NULL)
9633 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9634 }
9635 CHECK_TYPE0(XPATH_NODESET);
9636 arg2 = valuePop(ctxt);
9637
9638 CHECK_TYPE0(XPATH_NODESET);
9639 arg1 = valuePop(ctxt);
9640
9641 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9642 arg2->nodesetval);
9643 valuePush(ctxt, arg1);
9644 xmlXPathFreeObject(arg2);
9645 /* optimizer */
9646 if (total > cur)
9647 xmlXPathCompSwap(op);
9648 return (total + cur);
9649 case XPATH_OP_ROOT:
9650 xmlXPathRoot(ctxt);
9651 return (0);
9652 case XPATH_OP_NODE:
9653 if (op->ch1 != -1)
9654 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009655 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009656 if (op->ch2 != -1)
9657 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009658 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009659 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9660 return (total);
9661 case XPATH_OP_RESET:
9662 if (op->ch1 != -1)
9663 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009664 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009665 if (op->ch2 != -1)
9666 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009667 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009668 ctxt->context->node = NULL;
9669 return (total);
9670 case XPATH_OP_COLLECT:{
9671 if (op->ch1 == -1)
9672 return (0);
9673
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
9677 /*
9678 * Optimization for [n] selection where n is a number
9679 */
9680 if ((op->ch2 != -1) &&
9681 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9682 (comp->steps[op->ch2].ch1 == -1) &&
9683 (comp->steps[op->ch2].ch2 != -1) &&
9684 (comp->steps[comp->steps[op->ch2].ch2].op ==
9685 XPATH_OP_VALUE)) {
9686 xmlXPathObjectPtr val;
9687
9688 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9689 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9690 int indx = (int) val->floatval;
9691
9692 if (val->floatval == (float) indx) {
9693 total +=
9694 xmlXPathNodeCollectAndTestNth(ctxt, op,
9695 indx, NULL,
9696 last);
9697 return (total);
9698 }
9699 }
9700 }
9701 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9702 return (total);
9703 }
9704 case XPATH_OP_VALUE:
9705 valuePush(ctxt,
9706 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9707 return (0);
9708 case XPATH_OP_SORT:
9709 if (op->ch1 != -1)
9710 total +=
9711 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9712 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009713 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009714 if ((ctxt->value != NULL)
9715 && (ctxt->value->type == XPATH_NODESET)
9716 && (ctxt->value->nodesetval != NULL))
9717 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9718 return (total);
9719 default:
9720 return (xmlXPathCompOpEval(ctxt, op));
9721 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009722}
9723
Owen Taylor3473f882001-02-23 17:55:21 +00009724/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009725 * xmlXPathCompOpEval:
9726 * @ctxt: the XPath parser context with the compiled expression
9727 * @op: an XPath compiled operation
9728 *
9729 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009730 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009731 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009732static int
9733xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9734{
9735 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009736 int equal, ret;
9737 xmlXPathCompExprPtr comp;
9738 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009739 xmlNodePtr bak;
9740 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009741 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009742 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009743
Daniel Veillard556c6682001-10-06 09:59:51 +00009744 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009745 comp = ctxt->comp;
9746 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009747 case XPATH_OP_END:
9748 return (0);
9749 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009750 bakd = ctxt->context->doc;
9751 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009752 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009753 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009754 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009755 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009756 xmlXPathBooleanFunction(ctxt, 1);
9757 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9758 return (total);
9759 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009760 ctxt->context->doc = bakd;
9761 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009762 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009763 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009764 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009765 if (ctxt->error) {
9766 xmlXPathFreeObject(arg2);
9767 return(0);
9768 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009769 xmlXPathBooleanFunction(ctxt, 1);
9770 arg1 = valuePop(ctxt);
9771 arg1->boolval &= arg2->boolval;
9772 valuePush(ctxt, arg1);
9773 xmlXPathFreeObject(arg2);
9774 return (total);
9775 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009776 bakd = ctxt->context->doc;
9777 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009778 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009779 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009780 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009781 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009782 xmlXPathBooleanFunction(ctxt, 1);
9783 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9784 return (total);
9785 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009786 ctxt->context->doc = bakd;
9787 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009788 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009789 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009790 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009791 if (ctxt->error) {
9792 xmlXPathFreeObject(arg2);
9793 return(0);
9794 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009795 xmlXPathBooleanFunction(ctxt, 1);
9796 arg1 = valuePop(ctxt);
9797 arg1->boolval |= arg2->boolval;
9798 valuePush(ctxt, arg1);
9799 xmlXPathFreeObject(arg2);
9800 return (total);
9801 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009802 bakd = ctxt->context->doc;
9803 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009804 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009805 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009806 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009807 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009808 ctxt->context->doc = bakd;
9809 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009810 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009811 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009812 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009813 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009814 if (op->value)
9815 equal = xmlXPathEqualValues(ctxt);
9816 else
9817 equal = xmlXPathNotEqualValues(ctxt);
9818 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009819 return (total);
9820 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009821 bakd = ctxt->context->doc;
9822 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009823 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009824 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009825 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009826 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009827 ctxt->context->doc = bakd;
9828 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009829 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009830 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009831 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009832 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009833 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9834 valuePush(ctxt, xmlXPathNewBoolean(ret));
9835 return (total);
9836 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009837 bakd = ctxt->context->doc;
9838 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009839 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009840 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009841 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009842 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009843 if (op->ch2 != -1) {
9844 ctxt->context->doc = bakd;
9845 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009846 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009847 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009848 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009849 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009850 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009851 if (op->value == 0)
9852 xmlXPathSubValues(ctxt);
9853 else if (op->value == 1)
9854 xmlXPathAddValues(ctxt);
9855 else if (op->value == 2)
9856 xmlXPathValueFlipSign(ctxt);
9857 else if (op->value == 3) {
9858 CAST_TO_NUMBER;
9859 CHECK_TYPE0(XPATH_NUMBER);
9860 }
9861 return (total);
9862 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009863 bakd = ctxt->context->doc;
9864 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009865 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009866 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009867 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009868 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009869 ctxt->context->doc = bakd;
9870 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009871 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009872 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009873 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009874 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009875 if (op->value == 0)
9876 xmlXPathMultValues(ctxt);
9877 else if (op->value == 1)
9878 xmlXPathDivValues(ctxt);
9879 else if (op->value == 2)
9880 xmlXPathModValues(ctxt);
9881 return (total);
9882 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009883 bakd = ctxt->context->doc;
9884 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009885 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009886 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009887 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009888 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009889 ctxt->context->doc = bakd;
9890 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009891 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009892 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009893 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009894 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009895 CHECK_TYPE0(XPATH_NODESET);
9896 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009897
Daniel Veillardf06307e2001-07-03 10:35:50 +00009898 CHECK_TYPE0(XPATH_NODESET);
9899 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009900
Daniel Veillardf06307e2001-07-03 10:35:50 +00009901 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9902 arg2->nodesetval);
9903 valuePush(ctxt, arg1);
9904 xmlXPathFreeObject(arg2);
9905 return (total);
9906 case XPATH_OP_ROOT:
9907 xmlXPathRoot(ctxt);
9908 return (total);
9909 case XPATH_OP_NODE:
9910 if (op->ch1 != -1)
9911 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009912 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009913 if (op->ch2 != -1)
9914 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009915 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009916 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9917 return (total);
9918 case XPATH_OP_RESET:
9919 if (op->ch1 != -1)
9920 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009921 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 if (op->ch2 != -1)
9923 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009924 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009925 ctxt->context->node = NULL;
9926 return (total);
9927 case XPATH_OP_COLLECT:{
9928 if (op->ch1 == -1)
9929 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009930
Daniel Veillardf06307e2001-07-03 10:35:50 +00009931 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009932 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009933
Daniel Veillardf06307e2001-07-03 10:35:50 +00009934 /*
9935 * Optimization for [n] selection where n is a number
9936 */
9937 if ((op->ch2 != -1) &&
9938 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9939 (comp->steps[op->ch2].ch1 == -1) &&
9940 (comp->steps[op->ch2].ch2 != -1) &&
9941 (comp->steps[comp->steps[op->ch2].ch2].op ==
9942 XPATH_OP_VALUE)) {
9943 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009944
Daniel Veillardf06307e2001-07-03 10:35:50 +00009945 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9946 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9947 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009948
Daniel Veillardf06307e2001-07-03 10:35:50 +00009949 if (val->floatval == (float) indx) {
9950 total +=
9951 xmlXPathNodeCollectAndTestNth(ctxt, op,
9952 indx, NULL,
9953 NULL);
9954 return (total);
9955 }
9956 }
9957 }
9958 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9959 return (total);
9960 }
9961 case XPATH_OP_VALUE:
9962 valuePush(ctxt,
9963 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9964 return (total);
9965 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009966 xmlXPathObjectPtr val;
9967
Daniel Veillardf06307e2001-07-03 10:35:50 +00009968 if (op->ch1 != -1)
9969 total +=
9970 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009971 if (op->value5 == NULL) {
9972 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9973 if (val == NULL) {
9974 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9975 return(0);
9976 }
9977 valuePush(ctxt, val);
9978 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009979 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009980
Daniel Veillardf06307e2001-07-03 10:35:50 +00009981 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9982 if (URI == NULL) {
9983 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009984 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009985 op->value4, op->value5);
9986 return (total);
9987 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009988 val = xmlXPathVariableLookupNS(ctxt->context,
9989 op->value4, URI);
9990 if (val == NULL) {
9991 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9992 return(0);
9993 }
9994 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009995 }
9996 return (total);
9997 }
9998 case XPATH_OP_FUNCTION:{
9999 xmlXPathFunction func;
10000 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010001 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010002
10003 if (op->ch1 != -1)
10004 total +=
10005 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010006 if (ctxt->valueNr < op->value) {
10007 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010008 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010009 ctxt->error = XPATH_INVALID_OPERAND;
10010 return (total);
10011 }
10012 for (i = 0; i < op->value; i++)
10013 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10014 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010015 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010016 ctxt->error = XPATH_INVALID_OPERAND;
10017 return (total);
10018 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010019 if (op->cache != NULL)
10020 func = (xmlXPathFunction) op->cache;
10021 else {
10022 const xmlChar *URI = NULL;
10023
10024 if (op->value5 == NULL)
10025 func =
10026 xmlXPathFunctionLookup(ctxt->context,
10027 op->value4);
10028 else {
10029 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10030 if (URI == NULL) {
10031 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010032 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010033 op->value4, op->value5);
10034 return (total);
10035 }
10036 func = xmlXPathFunctionLookupNS(ctxt->context,
10037 op->value4, URI);
10038 }
10039 if (func == NULL) {
10040 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010041 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010042 op->value4);
10043 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010044 }
10045 op->cache = (void *) func;
10046 op->cacheURI = (void *) URI;
10047 }
10048 oldFunc = ctxt->context->function;
10049 oldFuncURI = ctxt->context->functionURI;
10050 ctxt->context->function = op->value4;
10051 ctxt->context->functionURI = op->cacheURI;
10052 func(ctxt, op->value);
10053 ctxt->context->function = oldFunc;
10054 ctxt->context->functionURI = oldFuncURI;
10055 return (total);
10056 }
10057 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010058 bakd = ctxt->context->doc;
10059 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010060 if (op->ch1 != -1)
10061 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010062 ctxt->context->doc = bakd;
10063 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010064 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010065 if (op->ch2 != -1)
10066 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010067 ctxt->context->doc = bakd;
10068 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010069 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010070 return (total);
10071 case XPATH_OP_PREDICATE:
10072 case XPATH_OP_FILTER:{
10073 xmlXPathObjectPtr res;
10074 xmlXPathObjectPtr obj, tmp;
10075 xmlNodeSetPtr newset = NULL;
10076 xmlNodeSetPtr oldset;
10077 xmlNodePtr oldnode;
10078 int i;
10079
10080 /*
10081 * Optimization for ()[1] selection i.e. the first elem
10082 */
10083 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10084 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10085 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10086 xmlXPathObjectPtr val;
10087
10088 val = comp->steps[op->ch2].value4;
10089 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10090 (val->floatval == 1.0)) {
10091 xmlNodePtr first = NULL;
10092
10093 total +=
10094 xmlXPathCompOpEvalFirst(ctxt,
10095 &comp->steps[op->ch1],
10096 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010097 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010098 /*
10099 * The nodeset should be in document order,
10100 * Keep only the first value
10101 */
10102 if ((ctxt->value != NULL) &&
10103 (ctxt->value->type == XPATH_NODESET) &&
10104 (ctxt->value->nodesetval != NULL) &&
10105 (ctxt->value->nodesetval->nodeNr > 1))
10106 ctxt->value->nodesetval->nodeNr = 1;
10107 return (total);
10108 }
10109 }
10110 /*
10111 * Optimization for ()[last()] selection i.e. the last elem
10112 */
10113 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10114 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10115 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10116 int f = comp->steps[op->ch2].ch1;
10117
10118 if ((f != -1) &&
10119 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10120 (comp->steps[f].value5 == NULL) &&
10121 (comp->steps[f].value == 0) &&
10122 (comp->steps[f].value4 != NULL) &&
10123 (xmlStrEqual
10124 (comp->steps[f].value4, BAD_CAST "last"))) {
10125 xmlNodePtr last = NULL;
10126
10127 total +=
10128 xmlXPathCompOpEvalLast(ctxt,
10129 &comp->steps[op->ch1],
10130 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010131 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010132 /*
10133 * The nodeset should be in document order,
10134 * Keep only the last value
10135 */
10136 if ((ctxt->value != NULL) &&
10137 (ctxt->value->type == XPATH_NODESET) &&
10138 (ctxt->value->nodesetval != NULL) &&
10139 (ctxt->value->nodesetval->nodeTab != NULL) &&
10140 (ctxt->value->nodesetval->nodeNr > 1)) {
10141 ctxt->value->nodesetval->nodeTab[0] =
10142 ctxt->value->nodesetval->nodeTab[ctxt->
10143 value->
10144 nodesetval->
10145 nodeNr -
10146 1];
10147 ctxt->value->nodesetval->nodeNr = 1;
10148 }
10149 return (total);
10150 }
10151 }
10152
10153 if (op->ch1 != -1)
10154 total +=
10155 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010156 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010157 if (op->ch2 == -1)
10158 return (total);
10159 if (ctxt->value == NULL)
10160 return (total);
10161
10162 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010163
10164#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010165 /*
10166 * Hum are we filtering the result of an XPointer expression
10167 */
10168 if (ctxt->value->type == XPATH_LOCATIONSET) {
10169 xmlLocationSetPtr newlocset = NULL;
10170 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010171
Daniel Veillardf06307e2001-07-03 10:35:50 +000010172 /*
10173 * Extract the old locset, and then evaluate the result of the
10174 * expression for all the element in the locset. use it to grow
10175 * up a new locset.
10176 */
10177 CHECK_TYPE0(XPATH_LOCATIONSET);
10178 obj = valuePop(ctxt);
10179 oldlocset = obj->user;
10180 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010181
Daniel Veillardf06307e2001-07-03 10:35:50 +000010182 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10183 ctxt->context->contextSize = 0;
10184 ctxt->context->proximityPosition = 0;
10185 if (op->ch2 != -1)
10186 total +=
10187 xmlXPathCompOpEval(ctxt,
10188 &comp->steps[op->ch2]);
10189 res = valuePop(ctxt);
10190 if (res != NULL)
10191 xmlXPathFreeObject(res);
10192 valuePush(ctxt, obj);
10193 CHECK_ERROR0;
10194 return (total);
10195 }
10196 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010197
Daniel Veillardf06307e2001-07-03 10:35:50 +000010198 for (i = 0; i < oldlocset->locNr; i++) {
10199 /*
10200 * Run the evaluation with a node list made of a
10201 * single item in the nodelocset.
10202 */
10203 ctxt->context->node = oldlocset->locTab[i]->user;
10204 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10205 valuePush(ctxt, tmp);
10206 ctxt->context->contextSize = oldlocset->locNr;
10207 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010208
Daniel Veillardf06307e2001-07-03 10:35:50 +000010209 if (op->ch2 != -1)
10210 total +=
10211 xmlXPathCompOpEval(ctxt,
10212 &comp->steps[op->ch2]);
10213 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010214
Daniel Veillardf06307e2001-07-03 10:35:50 +000010215 /*
10216 * The result of the evaluation need to be tested to
10217 * decided whether the filter succeeded or not
10218 */
10219 res = valuePop(ctxt);
10220 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10221 xmlXPtrLocationSetAdd(newlocset,
10222 xmlXPathObjectCopy
10223 (oldlocset->locTab[i]));
10224 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010225
Daniel Veillardf06307e2001-07-03 10:35:50 +000010226 /*
10227 * Cleanup
10228 */
10229 if (res != NULL)
10230 xmlXPathFreeObject(res);
10231 if (ctxt->value == tmp) {
10232 res = valuePop(ctxt);
10233 xmlXPathFreeObject(res);
10234 }
10235
10236 ctxt->context->node = NULL;
10237 }
10238
10239 /*
10240 * The result is used as the new evaluation locset.
10241 */
10242 xmlXPathFreeObject(obj);
10243 ctxt->context->node = NULL;
10244 ctxt->context->contextSize = -1;
10245 ctxt->context->proximityPosition = -1;
10246 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10247 ctxt->context->node = oldnode;
10248 return (total);
10249 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010250#endif /* LIBXML_XPTR_ENABLED */
10251
Daniel Veillardf06307e2001-07-03 10:35:50 +000010252 /*
10253 * Extract the old set, and then evaluate the result of the
10254 * expression for all the element in the set. use it to grow
10255 * up a new set.
10256 */
10257 CHECK_TYPE0(XPATH_NODESET);
10258 obj = valuePop(ctxt);
10259 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010260
Daniel Veillardf06307e2001-07-03 10:35:50 +000010261 oldnode = ctxt->context->node;
10262 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010263
Daniel Veillardf06307e2001-07-03 10:35:50 +000010264 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10265 ctxt->context->contextSize = 0;
10266 ctxt->context->proximityPosition = 0;
10267 if (op->ch2 != -1)
10268 total +=
10269 xmlXPathCompOpEval(ctxt,
10270 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010271 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010272 res = valuePop(ctxt);
10273 if (res != NULL)
10274 xmlXPathFreeObject(res);
10275 valuePush(ctxt, obj);
10276 ctxt->context->node = oldnode;
10277 CHECK_ERROR0;
10278 } else {
10279 /*
10280 * Initialize the new set.
10281 */
10282 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010283
Daniel Veillardf06307e2001-07-03 10:35:50 +000010284 for (i = 0; i < oldset->nodeNr; i++) {
10285 /*
10286 * Run the evaluation with a node list made of
10287 * a single item in the nodeset.
10288 */
10289 ctxt->context->node = oldset->nodeTab[i];
10290 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10291 valuePush(ctxt, tmp);
10292 ctxt->context->contextSize = oldset->nodeNr;
10293 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010294
Daniel Veillardf06307e2001-07-03 10:35:50 +000010295 if (op->ch2 != -1)
10296 total +=
10297 xmlXPathCompOpEval(ctxt,
10298 &comp->steps[op->ch2]);
10299 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010300
Daniel Veillardf06307e2001-07-03 10:35:50 +000010301 /*
10302 * The result of the evaluation need to be tested to
10303 * decided whether the filter succeeded or not
10304 */
10305 res = valuePop(ctxt);
10306 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10307 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10308 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010309
Daniel Veillardf06307e2001-07-03 10:35:50 +000010310 /*
10311 * Cleanup
10312 */
10313 if (res != NULL)
10314 xmlXPathFreeObject(res);
10315 if (ctxt->value == tmp) {
10316 res = valuePop(ctxt);
10317 xmlXPathFreeObject(res);
10318 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010319
Daniel Veillardf06307e2001-07-03 10:35:50 +000010320 ctxt->context->node = NULL;
10321 }
10322
10323 /*
10324 * The result is used as the new evaluation set.
10325 */
10326 xmlXPathFreeObject(obj);
10327 ctxt->context->node = NULL;
10328 ctxt->context->contextSize = -1;
10329 ctxt->context->proximityPosition = -1;
10330 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10331 }
10332 ctxt->context->node = oldnode;
10333 return (total);
10334 }
10335 case XPATH_OP_SORT:
10336 if (op->ch1 != -1)
10337 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010338 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010339 if ((ctxt->value != NULL) &&
10340 (ctxt->value->type == XPATH_NODESET) &&
10341 (ctxt->value->nodesetval != NULL))
10342 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10343 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010344#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010345 case XPATH_OP_RANGETO:{
10346 xmlXPathObjectPtr range;
10347 xmlXPathObjectPtr res, obj;
10348 xmlXPathObjectPtr tmp;
10349 xmlLocationSetPtr newset = NULL;
10350 xmlNodeSetPtr oldset;
10351 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010352
Daniel Veillardf06307e2001-07-03 10:35:50 +000010353 if (op->ch1 != -1)
10354 total +=
10355 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10356 if (op->ch2 == -1)
10357 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010358
Daniel Veillardf06307e2001-07-03 10:35:50 +000010359 CHECK_TYPE0(XPATH_NODESET);
10360 obj = valuePop(ctxt);
10361 oldset = obj->nodesetval;
10362 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010363
Daniel Veillardf06307e2001-07-03 10:35:50 +000010364 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010365
Daniel Veillardf06307e2001-07-03 10:35:50 +000010366 if (oldset != NULL) {
10367 for (i = 0; i < oldset->nodeNr; i++) {
10368 /*
10369 * Run the evaluation with a node list made of a single item
10370 * in the nodeset.
10371 */
10372 ctxt->context->node = oldset->nodeTab[i];
10373 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10374 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010375
Daniel Veillardf06307e2001-07-03 10:35:50 +000010376 if (op->ch2 != -1)
10377 total +=
10378 xmlXPathCompOpEval(ctxt,
10379 &comp->steps[op->ch2]);
10380 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010381
Daniel Veillardf06307e2001-07-03 10:35:50 +000010382 /*
10383 * The result of the evaluation need to be tested to
10384 * decided whether the filter succeeded or not
10385 */
10386 res = valuePop(ctxt);
10387 range =
10388 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10389 res);
10390 if (range != NULL) {
10391 xmlXPtrLocationSetAdd(newset, range);
10392 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010393
Daniel Veillardf06307e2001-07-03 10:35:50 +000010394 /*
10395 * Cleanup
10396 */
10397 if (res != NULL)
10398 xmlXPathFreeObject(res);
10399 if (ctxt->value == tmp) {
10400 res = valuePop(ctxt);
10401 xmlXPathFreeObject(res);
10402 }
10403
10404 ctxt->context->node = NULL;
10405 }
10406 }
10407
10408 /*
10409 * The result is used as the new evaluation set.
10410 */
10411 xmlXPathFreeObject(obj);
10412 ctxt->context->node = NULL;
10413 ctxt->context->contextSize = -1;
10414 ctxt->context->proximityPosition = -1;
10415 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10416 return (total);
10417 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010418#endif /* LIBXML_XPTR_ENABLED */
10419 }
10420 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010421 "XPath: unknown precompiled operation %d\n", op->op);
10422 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010423}
10424
10425/**
10426 * xmlXPathRunEval:
10427 * @ctxt: the XPath parser context with the compiled expression
10428 *
10429 * Evaluate the Precompiled XPath expression in the given context.
10430 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010431static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010432xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10433 xmlXPathCompExprPtr comp;
10434
10435 if ((ctxt == NULL) || (ctxt->comp == NULL))
10436 return;
10437
10438 if (ctxt->valueTab == NULL) {
10439 /* Allocate the value stack */
10440 ctxt->valueTab = (xmlXPathObjectPtr *)
10441 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10442 if (ctxt->valueTab == NULL) {
10443 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010444 }
10445 ctxt->valueNr = 0;
10446 ctxt->valueMax = 10;
10447 ctxt->value = NULL;
10448 }
10449 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010450 if(comp->last < 0) {
10451 xmlGenericError(xmlGenericErrorContext,
10452 "xmlXPathRunEval: last is less than zero\n");
10453 return;
10454 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010455 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10456}
10457
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010458/************************************************************************
10459 * *
10460 * Public interfaces *
10461 * *
10462 ************************************************************************/
10463
10464/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010465 * xmlXPathEvalPredicate:
10466 * @ctxt: the XPath context
10467 * @res: the Predicate Expression evaluation result
10468 *
10469 * Evaluate a predicate result for the current node.
10470 * A PredicateExpr is evaluated by evaluating the Expr and converting
10471 * the result to a boolean. If the result is a number, the result will
10472 * be converted to true if the number is equal to the position of the
10473 * context node in the context node list (as returned by the position
10474 * function) and will be converted to false otherwise; if the result
10475 * is not a number, then the result will be converted as if by a call
10476 * to the boolean function.
10477 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010478 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010479 */
10480int
10481xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10482 if (res == NULL) return(0);
10483 switch (res->type) {
10484 case XPATH_BOOLEAN:
10485 return(res->boolval);
10486 case XPATH_NUMBER:
10487 return(res->floatval == ctxt->proximityPosition);
10488 case XPATH_NODESET:
10489 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010490 if (res->nodesetval == NULL)
10491 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010492 return(res->nodesetval->nodeNr != 0);
10493 case XPATH_STRING:
10494 return((res->stringval != NULL) &&
10495 (xmlStrlen(res->stringval) != 0));
10496 default:
10497 STRANGE
10498 }
10499 return(0);
10500}
10501
10502/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010503 * xmlXPathEvaluatePredicateResult:
10504 * @ctxt: the XPath Parser context
10505 * @res: the Predicate Expression evaluation result
10506 *
10507 * Evaluate a predicate result for the current node.
10508 * A PredicateExpr is evaluated by evaluating the Expr and converting
10509 * the result to a boolean. If the result is a number, the result will
10510 * be converted to true if the number is equal to the position of the
10511 * context node in the context node list (as returned by the position
10512 * function) and will be converted to false otherwise; if the result
10513 * is not a number, then the result will be converted as if by a call
10514 * to the boolean function.
10515 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010516 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010517 */
10518int
10519xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10520 xmlXPathObjectPtr res) {
10521 if (res == NULL) return(0);
10522 switch (res->type) {
10523 case XPATH_BOOLEAN:
10524 return(res->boolval);
10525 case XPATH_NUMBER:
10526 return(res->floatval == ctxt->context->proximityPosition);
10527 case XPATH_NODESET:
10528 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010529 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010530 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010531 return(res->nodesetval->nodeNr != 0);
10532 case XPATH_STRING:
10533 return((res->stringval != NULL) &&
10534 (xmlStrlen(res->stringval) != 0));
10535 default:
10536 STRANGE
10537 }
10538 return(0);
10539}
10540
10541/**
10542 * xmlXPathCompile:
10543 * @str: the XPath expression
10544 *
10545 * Compile an XPath expression
10546 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010547 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010548 * the caller has to free the object.
10549 */
10550xmlXPathCompExprPtr
10551xmlXPathCompile(const xmlChar *str) {
10552 xmlXPathParserContextPtr ctxt;
10553 xmlXPathCompExprPtr comp;
10554
10555 xmlXPathInit();
10556
10557 ctxt = xmlXPathNewParserContext(str, NULL);
10558 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010559
Daniel Veillard40af6492001-04-22 08:50:55 +000010560 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010561 /*
10562 * aleksey: in some cases this line prints *second* error message
10563 * (see bug #78858) and probably this should be fixed.
10564 * However, we are not sure that all error messages are printed
10565 * out in other places. It's not critical so we leave it as-is for now
10566 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010567 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10568 comp = NULL;
10569 } else {
10570 comp = ctxt->comp;
10571 ctxt->comp = NULL;
10572 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010573 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010574 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010575 comp->expr = xmlStrdup(str);
10576#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010577 comp->string = xmlStrdup(str);
10578 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010579#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010580 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010581 return(comp);
10582}
10583
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010584/**
10585 * xmlXPathCompiledEval:
10586 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010587 * @ctx: the XPath context
10588 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010589 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010590 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010591 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010592 * the caller has to free the object.
10593 */
10594xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010595xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010596 xmlXPathParserContextPtr ctxt;
10597 xmlXPathObjectPtr res, tmp, init = NULL;
10598 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010599#ifndef LIBXML_THREAD_ENABLED
10600 static int reentance = 0;
10601#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010602
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010603 if ((comp == NULL) || (ctx == NULL))
10604 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010605 xmlXPathInit();
10606
10607 CHECK_CONTEXT(ctx)
10608
Daniel Veillard81463942001-10-16 12:34:39 +000010609#ifndef LIBXML_THREAD_ENABLED
10610 reentance++;
10611 if (reentance > 1)
10612 xmlXPathDisableOptimizer = 1;
10613#endif
10614
Daniel Veillardf06307e2001-07-03 10:35:50 +000010615#ifdef DEBUG_EVAL_COUNTS
10616 comp->nb++;
10617 if ((comp->string != NULL) && (comp->nb > 100)) {
10618 fprintf(stderr, "100 x %s\n", comp->string);
10619 comp->nb = 0;
10620 }
10621#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010622 ctxt = xmlXPathCompParserContext(comp, ctx);
10623 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010624
10625 if (ctxt->value == NULL) {
10626 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010627 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010628 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010629 } else {
10630 res = valuePop(ctxt);
10631 }
10632
Daniel Veillardf06307e2001-07-03 10:35:50 +000010633
Owen Taylor3473f882001-02-23 17:55:21 +000010634 do {
10635 tmp = valuePop(ctxt);
10636 if (tmp != NULL) {
10637 if (tmp != init)
10638 stack++;
10639 xmlXPathFreeObject(tmp);
10640 }
10641 } while (tmp != NULL);
10642 if ((stack != 0) && (res != NULL)) {
10643 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010644 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010645 stack);
10646 }
10647 if (ctxt->error != XPATH_EXPRESSION_OK) {
10648 xmlXPathFreeObject(res);
10649 res = NULL;
10650 }
10651
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010652
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010653 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010654 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010655#ifndef LIBXML_THREAD_ENABLED
10656 reentance--;
10657#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010658 return(res);
10659}
10660
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010661/**
10662 * xmlXPathEvalExpr:
10663 * @ctxt: the XPath Parser context
10664 *
10665 * Parse and evaluate an XPath expression in the given context,
10666 * then push the result on the context stack
10667 */
10668void
10669xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10670 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010671 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010672 xmlXPathRunEval(ctxt);
10673}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010674
10675/**
10676 * xmlXPathEval:
10677 * @str: the XPath expression
10678 * @ctx: the XPath context
10679 *
10680 * Evaluate the XPath Location Path in the given context.
10681 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010682 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683 * the caller has to free the object.
10684 */
10685xmlXPathObjectPtr
10686xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10687 xmlXPathParserContextPtr ctxt;
10688 xmlXPathObjectPtr res, tmp, init = NULL;
10689 int stack = 0;
10690
10691 xmlXPathInit();
10692
10693 CHECK_CONTEXT(ctx)
10694
10695 ctxt = xmlXPathNewParserContext(str, ctx);
10696 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010697
10698 if (ctxt->value == NULL) {
10699 xmlGenericError(xmlGenericErrorContext,
10700 "xmlXPathEval: evaluation failed\n");
10701 res = NULL;
10702 } else if (*ctxt->cur != 0) {
10703 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10704 res = NULL;
10705 } else {
10706 res = valuePop(ctxt);
10707 }
10708
10709 do {
10710 tmp = valuePop(ctxt);
10711 if (tmp != NULL) {
10712 if (tmp != init)
10713 stack++;
10714 xmlXPathFreeObject(tmp);
10715 }
10716 } while (tmp != NULL);
10717 if ((stack != 0) && (res != NULL)) {
10718 xmlGenericError(xmlGenericErrorContext,
10719 "xmlXPathEval: %d object left on the stack\n",
10720 stack);
10721 }
10722 if (ctxt->error != XPATH_EXPRESSION_OK) {
10723 xmlXPathFreeObject(res);
10724 res = NULL;
10725 }
10726
Owen Taylor3473f882001-02-23 17:55:21 +000010727 xmlXPathFreeParserContext(ctxt);
10728 return(res);
10729}
10730
10731/**
10732 * xmlXPathEvalExpression:
10733 * @str: the XPath expression
10734 * @ctxt: the XPath context
10735 *
10736 * Evaluate the XPath expression in the given context.
10737 *
10738 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10739 * the caller has to free the object.
10740 */
10741xmlXPathObjectPtr
10742xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10743 xmlXPathParserContextPtr pctxt;
10744 xmlXPathObjectPtr res, tmp;
10745 int stack = 0;
10746
10747 xmlXPathInit();
10748
10749 CHECK_CONTEXT(ctxt)
10750
10751 pctxt = xmlXPathNewParserContext(str, ctxt);
10752 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010753
10754 if (*pctxt->cur != 0) {
10755 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10756 res = NULL;
10757 } else {
10758 res = valuePop(pctxt);
10759 }
10760 do {
10761 tmp = valuePop(pctxt);
10762 if (tmp != NULL) {
10763 xmlXPathFreeObject(tmp);
10764 stack++;
10765 }
10766 } while (tmp != NULL);
10767 if ((stack != 0) && (res != NULL)) {
10768 xmlGenericError(xmlGenericErrorContext,
10769 "xmlXPathEvalExpression: %d object left on the stack\n",
10770 stack);
10771 }
10772 xmlXPathFreeParserContext(pctxt);
10773 return(res);
10774}
10775
Daniel Veillard42766c02002-08-22 20:52:17 +000010776/************************************************************************
10777 * *
10778 * Extra functions not pertaining to the XPath spec *
10779 * *
10780 ************************************************************************/
10781/**
10782 * xmlXPathEscapeUriFunction:
10783 * @ctxt: the XPath Parser context
10784 * @nargs: the number of arguments
10785 *
10786 * Implement the escape-uri() XPath function
10787 * string escape-uri(string $str, bool $escape-reserved)
10788 *
10789 * This function applies the URI escaping rules defined in section 2 of [RFC
10790 * 2396] to the string supplied as $uri-part, which typically represents all
10791 * or part of a URI. The effect of the function is to replace any special
10792 * character in the string by an escape sequence of the form %xx%yy...,
10793 * where xxyy... is the hexadecimal representation of the octets used to
10794 * represent the character in UTF-8.
10795 *
10796 * The set of characters that are escaped depends on the setting of the
10797 * boolean argument $escape-reserved.
10798 *
10799 * If $escape-reserved is true, all characters are escaped other than lower
10800 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10801 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10802 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10803 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10804 * A-F).
10805 *
10806 * If $escape-reserved is false, the behavior differs in that characters
10807 * referred to in [RFC 2396] as reserved characters are not escaped. These
10808 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10809 *
10810 * [RFC 2396] does not define whether escaped URIs should use lower case or
10811 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10812 * compared using string comparison functions, this function must always use
10813 * the upper-case letters A-F.
10814 *
10815 * Generally, $escape-reserved should be set to true when escaping a string
10816 * that is to form a single part of a URI, and to false when escaping an
10817 * entire URI or URI reference.
10818 *
10819 * In the case of non-ascii characters, the string is encoded according to
10820 * utf-8 and then converted according to RFC 2396.
10821 *
10822 * Examples
10823 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10824 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10825 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10826 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10827 *
10828 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010829static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010830xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10831 xmlXPathObjectPtr str;
10832 int escape_reserved;
10833 xmlBufferPtr target;
10834 xmlChar *cptr;
10835 xmlChar escape[4];
10836
10837 CHECK_ARITY(2);
10838
10839 escape_reserved = xmlXPathPopBoolean(ctxt);
10840
10841 CAST_TO_STRING;
10842 str = valuePop(ctxt);
10843
10844 target = xmlBufferCreate();
10845
10846 escape[0] = '%';
10847 escape[3] = 0;
10848
10849 if (target) {
10850 for (cptr = str->stringval; *cptr; cptr++) {
10851 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10852 (*cptr >= 'a' && *cptr <= 'z') ||
10853 (*cptr >= '0' && *cptr <= '9') ||
10854 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10855 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10856 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10857 (*cptr == '%' &&
10858 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10859 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10860 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10861 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10862 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10863 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10864 (!escape_reserved &&
10865 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10866 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10867 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10868 *cptr == ','))) {
10869 xmlBufferAdd(target, cptr, 1);
10870 } else {
10871 if ((*cptr >> 4) < 10)
10872 escape[1] = '0' + (*cptr >> 4);
10873 else
10874 escape[1] = 'A' - 10 + (*cptr >> 4);
10875 if ((*cptr & 0xF) < 10)
10876 escape[2] = '0' + (*cptr & 0xF);
10877 else
10878 escape[2] = 'A' - 10 + (*cptr & 0xF);
10879
10880 xmlBufferAdd(target, &escape[0], 3);
10881 }
10882 }
10883 }
10884 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10885 xmlBufferFree(target);
10886 xmlXPathFreeObject(str);
10887}
10888
Owen Taylor3473f882001-02-23 17:55:21 +000010889/**
10890 * xmlXPathRegisterAllFunctions:
10891 * @ctxt: the XPath context
10892 *
10893 * Registers all default XPath functions in this context
10894 */
10895void
10896xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10897{
10898 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10899 xmlXPathBooleanFunction);
10900 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10901 xmlXPathCeilingFunction);
10902 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10903 xmlXPathCountFunction);
10904 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10905 xmlXPathConcatFunction);
10906 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10907 xmlXPathContainsFunction);
10908 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10909 xmlXPathIdFunction);
10910 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10911 xmlXPathFalseFunction);
10912 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10913 xmlXPathFloorFunction);
10914 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10915 xmlXPathLastFunction);
10916 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10917 xmlXPathLangFunction);
10918 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10919 xmlXPathLocalNameFunction);
10920 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10921 xmlXPathNotFunction);
10922 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10923 xmlXPathNameFunction);
10924 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10925 xmlXPathNamespaceURIFunction);
10926 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10927 xmlXPathNormalizeFunction);
10928 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10929 xmlXPathNumberFunction);
10930 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10931 xmlXPathPositionFunction);
10932 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10933 xmlXPathRoundFunction);
10934 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10935 xmlXPathStringFunction);
10936 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10937 xmlXPathStringLengthFunction);
10938 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10939 xmlXPathStartsWithFunction);
10940 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10941 xmlXPathSubstringFunction);
10942 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10943 xmlXPathSubstringBeforeFunction);
10944 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10945 xmlXPathSubstringAfterFunction);
10946 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10947 xmlXPathSumFunction);
10948 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10949 xmlXPathTrueFunction);
10950 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10951 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000010952
10953 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
10954 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
10955 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000010956}
10957
10958#endif /* LIBXML_XPATH_ENABLED */