blob: 5da280f717aec894de672604981042188d8cfeb6 [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 /*
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001371 * Speedup using line numbers if availble.
1372 */
1373 if ((node1->type == XML_ELEMENT_NODE) &&
1374 (node2->type == XML_ELEMENT_NODE) &&
1375 (0 != (int) node1->content) && (0 != (int) node2->content)) {
1376 int l1, l2;
1377 l1 = (int) node1->content;
1378 l2 = (int) node2->content;
1379 if (l1 < l2)
1380 return(1);
1381 if (l1 > l2)
1382 return(-1);
1383 }
1384
1385 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001386 * compute depth to root
1387 */
1388 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1389 if (cur == node1)
1390 return(1);
1391 depth2++;
1392 }
1393 root = cur;
1394 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1395 if (cur == node2)
1396 return(-1);
1397 depth1++;
1398 }
1399 /*
1400 * Distinct document (or distinct entities :-( ) case.
1401 */
1402 if (root != cur) {
1403 return(-2);
1404 }
1405 /*
1406 * get the nearest common ancestor.
1407 */
1408 while (depth1 > depth2) {
1409 depth1--;
1410 node1 = node1->parent;
1411 }
1412 while (depth2 > depth1) {
1413 depth2--;
1414 node2 = node2->parent;
1415 }
1416 while (node1->parent != node2->parent) {
1417 node1 = node1->parent;
1418 node2 = node2->parent;
1419 /* should not happen but just in case ... */
1420 if ((node1 == NULL) || (node2 == NULL))
1421 return(-2);
1422 }
1423 /*
1424 * Find who's first.
1425 */
1426 if (node1 == node2->next)
1427 return(-1);
1428 for (cur = node1->next;cur != NULL;cur = cur->next)
1429 if (cur == node2)
1430 return(1);
1431 return(-1); /* assume there is no sibling list corruption */
1432}
1433
1434/**
1435 * xmlXPathNodeSetSort:
1436 * @set: the node set
1437 *
1438 * Sort the node set in document order
1439 */
1440void
1441xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001442 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001443 xmlNodePtr tmp;
1444
1445 if (set == NULL)
1446 return;
1447
1448 /* Use Shell's sort to sort the node-set */
1449 len = set->nodeNr;
1450 for (incr = len / 2; incr > 0; incr /= 2) {
1451 for (i = incr; i < len; i++) {
1452 j = i - incr;
1453 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001454 if (xmlXPathCmpNodes(set->nodeTab[j],
1455 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001456 tmp = set->nodeTab[j];
1457 set->nodeTab[j] = set->nodeTab[j + incr];
1458 set->nodeTab[j + incr] = tmp;
1459 j -= incr;
1460 } else
1461 break;
1462 }
1463 }
1464 }
1465}
1466
1467#define XML_NODESET_DEFAULT 10
1468/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001469 * xmlXPathNodeSetDupNs:
1470 * @node: the parent node of the namespace XPath node
1471 * @ns: the libxml namespace declaration node.
1472 *
1473 * Namespace node in libxml don't match the XPath semantic. In a node set
1474 * the namespace nodes are duplicated and the next pointer is set to the
1475 * parent node in the XPath semantic.
1476 *
1477 * Returns the newly created object.
1478 */
1479static xmlNodePtr
1480xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1481 xmlNsPtr cur;
1482
1483 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1484 return(NULL);
1485 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1486 return((xmlNodePtr) ns);
1487
1488 /*
1489 * Allocate a new Namespace and fill the fields.
1490 */
1491 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1492 if (cur == NULL) {
1493 xmlGenericError(xmlGenericErrorContext,
1494 "xmlXPathNodeSetDupNs : malloc failed\n");
1495 return(NULL);
1496 }
1497 memset(cur, 0, sizeof(xmlNs));
1498 cur->type = XML_NAMESPACE_DECL;
1499 if (ns->href != NULL)
1500 cur->href = xmlStrdup(ns->href);
1501 if (ns->prefix != NULL)
1502 cur->prefix = xmlStrdup(ns->prefix);
1503 cur->next = (xmlNsPtr) node;
1504 return((xmlNodePtr) cur);
1505}
1506
1507/**
1508 * xmlXPathNodeSetFreeNs:
1509 * @ns: the XPath namespace node found in a nodeset.
1510 *
1511 * Namespace node in libxml don't match the XPath semantic. In a node set
1512 * the namespace nodes are duplicated and the next pointer is set to the
1513 * parent node in the XPath semantic. Check if such a node need to be freed
1514 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001515void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001516xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1517 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1518 return;
1519
1520 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1521 if (ns->href != NULL)
1522 xmlFree((xmlChar *)ns->href);
1523 if (ns->prefix != NULL)
1524 xmlFree((xmlChar *)ns->prefix);
1525 xmlFree(ns);
1526 }
1527}
1528
1529/**
Owen Taylor3473f882001-02-23 17:55:21 +00001530 * xmlXPathNodeSetCreate:
1531 * @val: an initial xmlNodePtr, or NULL
1532 *
1533 * Create a new xmlNodeSetPtr of type double and of value @val
1534 *
1535 * Returns the newly created object.
1536 */
1537xmlNodeSetPtr
1538xmlXPathNodeSetCreate(xmlNodePtr val) {
1539 xmlNodeSetPtr ret;
1540
1541 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1542 if (ret == NULL) {
1543 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001544 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001545 return(NULL);
1546 }
1547 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1548 if (val != NULL) {
1549 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1550 sizeof(xmlNodePtr));
1551 if (ret->nodeTab == NULL) {
1552 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001553 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001554 return(NULL);
1555 }
1556 memset(ret->nodeTab, 0 ,
1557 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1558 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001559 if (val->type == XML_NAMESPACE_DECL) {
1560 xmlNsPtr ns = (xmlNsPtr) val;
1561
1562 ret->nodeTab[ret->nodeNr++] =
1563 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1564 } else
1565 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001566 }
1567 return(ret);
1568}
1569
1570/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001571 * xmlXPathNodeSetContains:
1572 * @cur: the node-set
1573 * @val: the node
1574 *
1575 * checks whether @cur contains @val
1576 *
1577 * Returns true (1) if @cur contains @val, false (0) otherwise
1578 */
1579int
1580xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1581 int i;
1582
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001583 if (val->type == XML_NAMESPACE_DECL) {
1584 for (i = 0; i < cur->nodeNr; i++) {
1585 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1586 xmlNsPtr ns1, ns2;
1587
1588 ns1 = (xmlNsPtr) val;
1589 ns2 = (xmlNsPtr) cur->nodeTab[i];
1590 if (ns1 == ns2)
1591 return(1);
1592 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1593 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1594 return(1);
1595 }
1596 }
1597 } else {
1598 for (i = 0; i < cur->nodeNr; i++) {
1599 if (cur->nodeTab[i] == val)
1600 return(1);
1601 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001602 }
1603 return(0);
1604}
1605
1606/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001607 * xmlXPathNodeSetAddNs:
1608 * @cur: the initial node set
1609 * @node: the hosting node
1610 * @ns: a the namespace node
1611 *
1612 * add a new namespace node to an existing NodeSet
1613 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001614void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001615xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1616 int i;
1617
1618 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1619 (node->type != XML_ELEMENT_NODE))
1620 return;
1621
1622 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1623 /*
1624 * check against doublons
1625 */
1626 for (i = 0;i < cur->nodeNr;i++) {
1627 if ((cur->nodeTab[i] != NULL) &&
1628 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001629 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001630 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1631 return;
1632 }
1633
1634 /*
1635 * grow the nodeTab if needed
1636 */
1637 if (cur->nodeMax == 0) {
1638 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1639 sizeof(xmlNodePtr));
1640 if (cur->nodeTab == NULL) {
1641 xmlGenericError(xmlGenericErrorContext,
1642 "xmlXPathNodeSetAdd: out of memory\n");
1643 return;
1644 }
1645 memset(cur->nodeTab, 0 ,
1646 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1647 cur->nodeMax = XML_NODESET_DEFAULT;
1648 } else if (cur->nodeNr == cur->nodeMax) {
1649 xmlNodePtr *temp;
1650
1651 cur->nodeMax *= 2;
1652 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1653 sizeof(xmlNodePtr));
1654 if (temp == NULL) {
1655 xmlGenericError(xmlGenericErrorContext,
1656 "xmlXPathNodeSetAdd: out of memory\n");
1657 return;
1658 }
1659 cur->nodeTab = temp;
1660 }
1661 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1662}
1663
1664/**
Owen Taylor3473f882001-02-23 17:55:21 +00001665 * xmlXPathNodeSetAdd:
1666 * @cur: the initial node set
1667 * @val: a new xmlNodePtr
1668 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001669 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001670 */
1671void
1672xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1673 int i;
1674
1675 if (val == NULL) return;
1676
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001677 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001678 /*
1679 * check against doublons
1680 */
1681 for (i = 0;i < cur->nodeNr;i++)
1682 if (cur->nodeTab[i] == val) return;
1683
1684 /*
1685 * grow the nodeTab if needed
1686 */
1687 if (cur->nodeMax == 0) {
1688 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1689 sizeof(xmlNodePtr));
1690 if (cur->nodeTab == NULL) {
1691 xmlGenericError(xmlGenericErrorContext,
1692 "xmlXPathNodeSetAdd: out of memory\n");
1693 return;
1694 }
1695 memset(cur->nodeTab, 0 ,
1696 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1697 cur->nodeMax = XML_NODESET_DEFAULT;
1698 } else if (cur->nodeNr == cur->nodeMax) {
1699 xmlNodePtr *temp;
1700
1701 cur->nodeMax *= 2;
1702 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1703 sizeof(xmlNodePtr));
1704 if (temp == NULL) {
1705 xmlGenericError(xmlGenericErrorContext,
1706 "xmlXPathNodeSetAdd: out of memory\n");
1707 return;
1708 }
1709 cur->nodeTab = temp;
1710 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001711 if (val->type == XML_NAMESPACE_DECL) {
1712 xmlNsPtr ns = (xmlNsPtr) val;
1713
1714 cur->nodeTab[cur->nodeNr++] =
1715 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1716 } else
1717 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001718}
1719
1720/**
1721 * xmlXPathNodeSetAddUnique:
1722 * @cur: the initial node set
1723 * @val: a new xmlNodePtr
1724 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001725 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001726 * when we are sure the node is not already in the set.
1727 */
1728void
1729xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1730 if (val == NULL) return;
1731
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001732 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001733 /*
1734 * grow the nodeTab if needed
1735 */
1736 if (cur->nodeMax == 0) {
1737 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1738 sizeof(xmlNodePtr));
1739 if (cur->nodeTab == NULL) {
1740 xmlGenericError(xmlGenericErrorContext,
1741 "xmlXPathNodeSetAddUnique: out of memory\n");
1742 return;
1743 }
1744 memset(cur->nodeTab, 0 ,
1745 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1746 cur->nodeMax = XML_NODESET_DEFAULT;
1747 } else if (cur->nodeNr == cur->nodeMax) {
1748 xmlNodePtr *temp;
1749
1750 cur->nodeMax *= 2;
1751 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1752 sizeof(xmlNodePtr));
1753 if (temp == NULL) {
1754 xmlGenericError(xmlGenericErrorContext,
1755 "xmlXPathNodeSetAddUnique: out of memory\n");
1756 return;
1757 }
1758 cur->nodeTab = temp;
1759 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001760 if (val->type == XML_NAMESPACE_DECL) {
1761 xmlNsPtr ns = (xmlNsPtr) val;
1762
1763 cur->nodeTab[cur->nodeNr++] =
1764 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1765 } else
1766 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001767}
1768
1769/**
1770 * xmlXPathNodeSetMerge:
1771 * @val1: the first NodeSet or NULL
1772 * @val2: the second NodeSet
1773 *
1774 * Merges two nodesets, all nodes from @val2 are added to @val1
1775 * if @val1 is NULL, a new set is created and copied from @val2
1776 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001777 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001778 */
1779xmlNodeSetPtr
1780xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001781 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001782
1783 if (val2 == NULL) return(val1);
1784 if (val1 == NULL) {
1785 val1 = xmlXPathNodeSetCreate(NULL);
1786 }
1787
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001788 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001789 initNr = val1->nodeNr;
1790
1791 for (i = 0;i < val2->nodeNr;i++) {
1792 /*
1793 * check against doublons
1794 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001795 skip = 0;
1796 for (j = 0; j < initNr; j++) {
1797 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1798 skip = 1;
1799 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001800 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1801 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1802 xmlNsPtr ns1, ns2;
1803 ns1 = (xmlNsPtr) val1->nodeTab[j];
1804 ns2 = (xmlNsPtr) val2->nodeTab[i];
1805 if ((ns1->next == ns2->next) &&
1806 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1807 skip = 1;
1808 break;
1809 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001810 }
1811 }
1812 if (skip)
1813 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001814
1815 /*
1816 * grow the nodeTab if needed
1817 */
1818 if (val1->nodeMax == 0) {
1819 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1820 sizeof(xmlNodePtr));
1821 if (val1->nodeTab == NULL) {
1822 xmlGenericError(xmlGenericErrorContext,
1823 "xmlXPathNodeSetMerge: out of memory\n");
1824 return(NULL);
1825 }
1826 memset(val1->nodeTab, 0 ,
1827 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1828 val1->nodeMax = XML_NODESET_DEFAULT;
1829 } else if (val1->nodeNr == val1->nodeMax) {
1830 xmlNodePtr *temp;
1831
1832 val1->nodeMax *= 2;
1833 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1834 sizeof(xmlNodePtr));
1835 if (temp == NULL) {
1836 xmlGenericError(xmlGenericErrorContext,
1837 "xmlXPathNodeSetMerge: out of memory\n");
1838 return(NULL);
1839 }
1840 val1->nodeTab = temp;
1841 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001842 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1843 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1844
1845 val1->nodeTab[val1->nodeNr++] =
1846 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1847 } else
1848 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001849 }
1850
1851 return(val1);
1852}
1853
1854/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001855 * xmlXPathNodeSetMergeUnique:
1856 * @val1: the first NodeSet or NULL
1857 * @val2: the second NodeSet
1858 *
1859 * Merges two nodesets, all nodes from @val2 are added to @val1
1860 * if @val1 is NULL, a new set is created and copied from @val2
1861 *
1862 * Returns @val1 once extended or NULL in case of error.
1863 */
1864static xmlNodeSetPtr
1865xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1866 int i, initNr;
1867
1868 if (val2 == NULL) return(val1);
1869 if (val1 == NULL) {
1870 val1 = xmlXPathNodeSetCreate(NULL);
1871 }
1872
1873 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1874 initNr = val1->nodeNr;
1875
1876 for (i = 0;i < val2->nodeNr;i++) {
1877 /*
1878 * grow the nodeTab if needed
1879 */
1880 if (val1->nodeMax == 0) {
1881 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1882 sizeof(xmlNodePtr));
1883 if (val1->nodeTab == NULL) {
1884 xmlGenericError(xmlGenericErrorContext,
1885 "xmlXPathNodeSetMerge: out of memory\n");
1886 return(NULL);
1887 }
1888 memset(val1->nodeTab, 0 ,
1889 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1890 val1->nodeMax = XML_NODESET_DEFAULT;
1891 } else if (val1->nodeNr == val1->nodeMax) {
1892 xmlNodePtr *temp;
1893
1894 val1->nodeMax *= 2;
1895 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1896 sizeof(xmlNodePtr));
1897 if (temp == NULL) {
1898 xmlGenericError(xmlGenericErrorContext,
1899 "xmlXPathNodeSetMerge: out of memory\n");
1900 return(NULL);
1901 }
1902 val1->nodeTab = temp;
1903 }
1904 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1905 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1906
1907 val1->nodeTab[val1->nodeNr++] =
1908 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1909 } else
1910 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1911 }
1912
1913 return(val1);
1914}
1915
1916/**
Owen Taylor3473f882001-02-23 17:55:21 +00001917 * xmlXPathNodeSetDel:
1918 * @cur: the initial node set
1919 * @val: an xmlNodePtr
1920 *
1921 * Removes an xmlNodePtr from an existing NodeSet
1922 */
1923void
1924xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1925 int i;
1926
1927 if (cur == NULL) return;
1928 if (val == NULL) return;
1929
1930 /*
1931 * check against doublons
1932 */
1933 for (i = 0;i < cur->nodeNr;i++)
1934 if (cur->nodeTab[i] == val) break;
1935
1936 if (i >= cur->nodeNr) {
1937#ifdef DEBUG
1938 xmlGenericError(xmlGenericErrorContext,
1939 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1940 val->name);
1941#endif
1942 return;
1943 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001944 if ((cur->nodeTab[i] != NULL) &&
1945 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1946 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001947 cur->nodeNr--;
1948 for (;i < cur->nodeNr;i++)
1949 cur->nodeTab[i] = cur->nodeTab[i + 1];
1950 cur->nodeTab[cur->nodeNr] = NULL;
1951}
1952
1953/**
1954 * xmlXPathNodeSetRemove:
1955 * @cur: the initial node set
1956 * @val: the index to remove
1957 *
1958 * Removes an entry from an existing NodeSet list.
1959 */
1960void
1961xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1962 if (cur == NULL) return;
1963 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001964 if ((cur->nodeTab[val] != NULL) &&
1965 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1966 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001967 cur->nodeNr--;
1968 for (;val < cur->nodeNr;val++)
1969 cur->nodeTab[val] = cur->nodeTab[val + 1];
1970 cur->nodeTab[cur->nodeNr] = NULL;
1971}
1972
1973/**
1974 * xmlXPathFreeNodeSet:
1975 * @obj: the xmlNodeSetPtr to free
1976 *
1977 * Free the NodeSet compound (not the actual nodes !).
1978 */
1979void
1980xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1981 if (obj == NULL) return;
1982 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001983 int i;
1984
1985 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1986 for (i = 0;i < obj->nodeNr;i++)
1987 if ((obj->nodeTab[i] != NULL) &&
1988 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1989 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001990 xmlFree(obj->nodeTab);
1991 }
Owen Taylor3473f882001-02-23 17:55:21 +00001992 xmlFree(obj);
1993}
1994
1995/**
1996 * xmlXPathFreeValueTree:
1997 * @obj: the xmlNodeSetPtr to free
1998 *
1999 * Free the NodeSet compound and the actual tree, this is different
2000 * from xmlXPathFreeNodeSet()
2001 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002002static void
Owen Taylor3473f882001-02-23 17:55:21 +00002003xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2004 int i;
2005
2006 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002007
2008 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002009 for (i = 0;i < obj->nodeNr;i++) {
2010 if (obj->nodeTab[i] != NULL) {
2011 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2012 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2013 } else {
2014 xmlFreeNodeList(obj->nodeTab[i]);
2015 }
2016 }
2017 }
Owen Taylor3473f882001-02-23 17:55:21 +00002018 xmlFree(obj->nodeTab);
2019 }
Owen Taylor3473f882001-02-23 17:55:21 +00002020 xmlFree(obj);
2021}
2022
2023#if defined(DEBUG) || defined(DEBUG_STEP)
2024/**
2025 * xmlGenericErrorContextNodeSet:
2026 * @output: a FILE * for the output
2027 * @obj: the xmlNodeSetPtr to free
2028 *
2029 * Quick display of a NodeSet
2030 */
2031void
2032xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2033 int i;
2034
2035 if (output == NULL) output = xmlGenericErrorContext;
2036 if (obj == NULL) {
2037 fprintf(output, "NodeSet == NULL !\n");
2038 return;
2039 }
2040 if (obj->nodeNr == 0) {
2041 fprintf(output, "NodeSet is empty\n");
2042 return;
2043 }
2044 if (obj->nodeTab == NULL) {
2045 fprintf(output, " nodeTab == NULL !\n");
2046 return;
2047 }
2048 for (i = 0; i < obj->nodeNr; i++) {
2049 if (obj->nodeTab[i] == NULL) {
2050 fprintf(output, " NULL !\n");
2051 return;
2052 }
2053 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2054 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2055 fprintf(output, " /");
2056 else if (obj->nodeTab[i]->name == NULL)
2057 fprintf(output, " noname!");
2058 else fprintf(output, " %s", obj->nodeTab[i]->name);
2059 }
2060 fprintf(output, "\n");
2061}
2062#endif
2063
2064/**
2065 * xmlXPathNewNodeSet:
2066 * @val: the NodePtr value
2067 *
2068 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2069 * it with the single Node @val
2070 *
2071 * Returns the newly created object.
2072 */
2073xmlXPathObjectPtr
2074xmlXPathNewNodeSet(xmlNodePtr val) {
2075 xmlXPathObjectPtr ret;
2076
2077 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2078 if (ret == NULL) {
2079 xmlGenericError(xmlGenericErrorContext,
2080 "xmlXPathNewNodeSet: out of memory\n");
2081 return(NULL);
2082 }
2083 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2084 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002085 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002086 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002087 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002088 return(ret);
2089}
2090
2091/**
2092 * xmlXPathNewValueTree:
2093 * @val: the NodePtr value
2094 *
2095 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2096 * it with the tree root @val
2097 *
2098 * Returns the newly created object.
2099 */
2100xmlXPathObjectPtr
2101xmlXPathNewValueTree(xmlNodePtr val) {
2102 xmlXPathObjectPtr ret;
2103
2104 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2105 if (ret == NULL) {
2106 xmlGenericError(xmlGenericErrorContext,
2107 "xmlXPathNewNodeSet: out of memory\n");
2108 return(NULL);
2109 }
2110 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2111 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002112 ret->boolval = 1;
2113 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002114 ret->nodesetval = xmlXPathNodeSetCreate(val);
2115 return(ret);
2116}
2117
2118/**
2119 * xmlXPathNewNodeSetList:
2120 * @val: an existing NodeSet
2121 *
2122 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2123 * it with the Nodeset @val
2124 *
2125 * Returns the newly created object.
2126 */
2127xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002128xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2129{
Owen Taylor3473f882001-02-23 17:55:21 +00002130 xmlXPathObjectPtr ret;
2131 int i;
2132
2133 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002134 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002135 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002136 ret = xmlXPathNewNodeSet(NULL);
2137 else {
2138 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2139 for (i = 1; i < val->nodeNr; ++i)
2140 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2141 }
Owen Taylor3473f882001-02-23 17:55:21 +00002142
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002143 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002144}
2145
2146/**
2147 * xmlXPathWrapNodeSet:
2148 * @val: the NodePtr value
2149 *
2150 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2151 *
2152 * Returns the newly created object.
2153 */
2154xmlXPathObjectPtr
2155xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2156 xmlXPathObjectPtr ret;
2157
2158 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2159 if (ret == NULL) {
2160 xmlGenericError(xmlGenericErrorContext,
2161 "xmlXPathWrapNodeSet: out of memory\n");
2162 return(NULL);
2163 }
2164 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2165 ret->type = XPATH_NODESET;
2166 ret->nodesetval = val;
2167 return(ret);
2168}
2169
2170/**
2171 * xmlXPathFreeNodeSetList:
2172 * @obj: an existing NodeSetList object
2173 *
2174 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2175 * the list contrary to xmlXPathFreeObject().
2176 */
2177void
2178xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2179 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002180 xmlFree(obj);
2181}
2182
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002183/**
2184 * xmlXPathDifference:
2185 * @nodes1: a node-set
2186 * @nodes2: a node-set
2187 *
2188 * Implements the EXSLT - Sets difference() function:
2189 * node-set set:difference (node-set, node-set)
2190 *
2191 * Returns the difference between the two node sets, or nodes1 if
2192 * nodes2 is empty
2193 */
2194xmlNodeSetPtr
2195xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2196 xmlNodeSetPtr ret;
2197 int i, l1;
2198 xmlNodePtr cur;
2199
2200 if (xmlXPathNodeSetIsEmpty(nodes2))
2201 return(nodes1);
2202
2203 ret = xmlXPathNodeSetCreate(NULL);
2204 if (xmlXPathNodeSetIsEmpty(nodes1))
2205 return(ret);
2206
2207 l1 = xmlXPathNodeSetGetLength(nodes1);
2208
2209 for (i = 0; i < l1; i++) {
2210 cur = xmlXPathNodeSetItem(nodes1, i);
2211 if (!xmlXPathNodeSetContains(nodes2, cur))
2212 xmlXPathNodeSetAddUnique(ret, cur);
2213 }
2214 return(ret);
2215}
2216
2217/**
2218 * xmlXPathIntersection:
2219 * @nodes1: a node-set
2220 * @nodes2: a node-set
2221 *
2222 * Implements the EXSLT - Sets intersection() function:
2223 * node-set set:intersection (node-set, node-set)
2224 *
2225 * Returns a node set comprising the nodes that are within both the
2226 * node sets passed as arguments
2227 */
2228xmlNodeSetPtr
2229xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2230 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2231 int i, l1;
2232 xmlNodePtr cur;
2233
2234 if (xmlXPathNodeSetIsEmpty(nodes1))
2235 return(ret);
2236 if (xmlXPathNodeSetIsEmpty(nodes2))
2237 return(ret);
2238
2239 l1 = xmlXPathNodeSetGetLength(nodes1);
2240
2241 for (i = 0; i < l1; i++) {
2242 cur = xmlXPathNodeSetItem(nodes1, i);
2243 if (xmlXPathNodeSetContains(nodes2, cur))
2244 xmlXPathNodeSetAddUnique(ret, cur);
2245 }
2246 return(ret);
2247}
2248
2249/**
2250 * xmlXPathDistinctSorted:
2251 * @nodes: a node-set, sorted by document order
2252 *
2253 * Implements the EXSLT - Sets distinct() function:
2254 * node-set set:distinct (node-set)
2255 *
2256 * Returns a subset of the nodes contained in @nodes, or @nodes if
2257 * it is empty
2258 */
2259xmlNodeSetPtr
2260xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2261 xmlNodeSetPtr ret;
2262 xmlHashTablePtr hash;
2263 int i, l;
2264 xmlChar * strval;
2265 xmlNodePtr cur;
2266
2267 if (xmlXPathNodeSetIsEmpty(nodes))
2268 return(nodes);
2269
2270 ret = xmlXPathNodeSetCreate(NULL);
2271 l = xmlXPathNodeSetGetLength(nodes);
2272 hash = xmlHashCreate (l);
2273 for (i = 0; i < l; i++) {
2274 cur = xmlXPathNodeSetItem(nodes, i);
2275 strval = xmlXPathCastNodeToString(cur);
2276 if (xmlHashLookup(hash, strval) == NULL) {
2277 xmlHashAddEntry(hash, strval, strval);
2278 xmlXPathNodeSetAddUnique(ret, cur);
2279 } else {
2280 xmlFree(strval);
2281 }
2282 }
2283 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2284 return(ret);
2285}
2286
2287/**
2288 * xmlXPathDistinct:
2289 * @nodes: a node-set
2290 *
2291 * Implements the EXSLT - Sets distinct() function:
2292 * node-set set:distinct (node-set)
2293 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2294 * is called with the sorted node-set
2295 *
2296 * Returns a subset of the nodes contained in @nodes, or @nodes if
2297 * it is empty
2298 */
2299xmlNodeSetPtr
2300xmlXPathDistinct (xmlNodeSetPtr nodes) {
2301 if (xmlXPathNodeSetIsEmpty(nodes))
2302 return(nodes);
2303
2304 xmlXPathNodeSetSort(nodes);
2305 return(xmlXPathDistinctSorted(nodes));
2306}
2307
2308/**
2309 * xmlXPathHasSameNodes:
2310 * @nodes1: a node-set
2311 * @nodes2: a node-set
2312 *
2313 * Implements the EXSLT - Sets has-same-nodes function:
2314 * boolean set:has-same-node(node-set, node-set)
2315 *
2316 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2317 * otherwise
2318 */
2319int
2320xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2321 int i, l;
2322 xmlNodePtr cur;
2323
2324 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2325 xmlXPathNodeSetIsEmpty(nodes2))
2326 return(0);
2327
2328 l = xmlXPathNodeSetGetLength(nodes1);
2329 for (i = 0; i < l; i++) {
2330 cur = xmlXPathNodeSetItem(nodes1, i);
2331 if (xmlXPathNodeSetContains(nodes2, cur))
2332 return(1);
2333 }
2334 return(0);
2335}
2336
2337/**
2338 * xmlXPathNodeLeadingSorted:
2339 * @nodes: a node-set, sorted by document order
2340 * @node: a node
2341 *
2342 * Implements the EXSLT - Sets leading() function:
2343 * node-set set:leading (node-set, node-set)
2344 *
2345 * Returns the nodes in @nodes that precede @node in document order,
2346 * @nodes if @node is NULL or an empty node-set if @nodes
2347 * doesn't contain @node
2348 */
2349xmlNodeSetPtr
2350xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2351 int i, l;
2352 xmlNodePtr cur;
2353 xmlNodeSetPtr ret;
2354
2355 if (node == NULL)
2356 return(nodes);
2357
2358 ret = xmlXPathNodeSetCreate(NULL);
2359 if (xmlXPathNodeSetIsEmpty(nodes) ||
2360 (!xmlXPathNodeSetContains(nodes, node)))
2361 return(ret);
2362
2363 l = xmlXPathNodeSetGetLength(nodes);
2364 for (i = 0; i < l; i++) {
2365 cur = xmlXPathNodeSetItem(nodes, i);
2366 if (cur == node)
2367 break;
2368 xmlXPathNodeSetAddUnique(ret, cur);
2369 }
2370 return(ret);
2371}
2372
2373/**
2374 * xmlXPathNodeLeading:
2375 * @nodes: a node-set
2376 * @node: a node
2377 *
2378 * Implements the EXSLT - Sets leading() function:
2379 * node-set set:leading (node-set, node-set)
2380 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2381 * is called.
2382 *
2383 * Returns the nodes in @nodes that precede @node in document order,
2384 * @nodes if @node is NULL or an empty node-set if @nodes
2385 * doesn't contain @node
2386 */
2387xmlNodeSetPtr
2388xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2389 xmlXPathNodeSetSort(nodes);
2390 return(xmlXPathNodeLeadingSorted(nodes, node));
2391}
2392
2393/**
2394 * xmlXPathLeadingSorted:
2395 * @nodes1: a node-set, sorted by document order
2396 * @nodes2: a node-set, sorted by document order
2397 *
2398 * Implements the EXSLT - Sets leading() function:
2399 * node-set set:leading (node-set, node-set)
2400 *
2401 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2402 * in document order, @nodes1 if @nodes2 is NULL or empty or
2403 * an empty node-set if @nodes1 doesn't contain @nodes2
2404 */
2405xmlNodeSetPtr
2406xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2407 if (xmlXPathNodeSetIsEmpty(nodes2))
2408 return(nodes1);
2409 return(xmlXPathNodeLeadingSorted(nodes1,
2410 xmlXPathNodeSetItem(nodes2, 1)));
2411}
2412
2413/**
2414 * xmlXPathLeading:
2415 * @nodes1: a node-set
2416 * @nodes2: a node-set
2417 *
2418 * Implements the EXSLT - Sets leading() function:
2419 * node-set set:leading (node-set, node-set)
2420 * @nodes1 and @nodes2 are sorted by document order, then
2421 * #exslSetsLeadingSorted is called.
2422 *
2423 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2424 * in document order, @nodes1 if @nodes2 is NULL or empty or
2425 * an empty node-set if @nodes1 doesn't contain @nodes2
2426 */
2427xmlNodeSetPtr
2428xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2429 if (xmlXPathNodeSetIsEmpty(nodes2))
2430 return(nodes1);
2431 if (xmlXPathNodeSetIsEmpty(nodes1))
2432 return(xmlXPathNodeSetCreate(NULL));
2433 xmlXPathNodeSetSort(nodes1);
2434 xmlXPathNodeSetSort(nodes2);
2435 return(xmlXPathNodeLeadingSorted(nodes1,
2436 xmlXPathNodeSetItem(nodes2, 1)));
2437}
2438
2439/**
2440 * xmlXPathNodeTrailingSorted:
2441 * @nodes: a node-set, sorted by document order
2442 * @node: a node
2443 *
2444 * Implements the EXSLT - Sets trailing() function:
2445 * node-set set:trailing (node-set, node-set)
2446 *
2447 * Returns the nodes in @nodes that follow @node in document order,
2448 * @nodes if @node is NULL or an empty node-set if @nodes
2449 * doesn't contain @node
2450 */
2451xmlNodeSetPtr
2452xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2453 int i, l;
2454 xmlNodePtr cur;
2455 xmlNodeSetPtr ret;
2456
2457 if (node == NULL)
2458 return(nodes);
2459
2460 ret = xmlXPathNodeSetCreate(NULL);
2461 if (xmlXPathNodeSetIsEmpty(nodes) ||
2462 (!xmlXPathNodeSetContains(nodes, node)))
2463 return(ret);
2464
2465 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002466 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002467 cur = xmlXPathNodeSetItem(nodes, i);
2468 if (cur == node)
2469 break;
2470 xmlXPathNodeSetAddUnique(ret, cur);
2471 }
2472 return(ret);
2473}
2474
2475/**
2476 * xmlXPathNodeTrailing:
2477 * @nodes: a node-set
2478 * @node: a node
2479 *
2480 * Implements the EXSLT - Sets trailing() function:
2481 * node-set set:trailing (node-set, node-set)
2482 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2483 * is called.
2484 *
2485 * Returns the nodes in @nodes that follow @node in document order,
2486 * @nodes if @node is NULL or an empty node-set if @nodes
2487 * doesn't contain @node
2488 */
2489xmlNodeSetPtr
2490xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2491 xmlXPathNodeSetSort(nodes);
2492 return(xmlXPathNodeTrailingSorted(nodes, node));
2493}
2494
2495/**
2496 * xmlXPathTrailingSorted:
2497 * @nodes1: a node-set, sorted by document order
2498 * @nodes2: a node-set, sorted by document order
2499 *
2500 * Implements the EXSLT - Sets trailing() function:
2501 * node-set set:trailing (node-set, node-set)
2502 *
2503 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2504 * in document order, @nodes1 if @nodes2 is NULL or empty or
2505 * an empty node-set if @nodes1 doesn't contain @nodes2
2506 */
2507xmlNodeSetPtr
2508xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2509 if (xmlXPathNodeSetIsEmpty(nodes2))
2510 return(nodes1);
2511 return(xmlXPathNodeTrailingSorted(nodes1,
2512 xmlXPathNodeSetItem(nodes2, 0)));
2513}
2514
2515/**
2516 * xmlXPathTrailing:
2517 * @nodes1: a node-set
2518 * @nodes2: a node-set
2519 *
2520 * Implements the EXSLT - Sets trailing() function:
2521 * node-set set:trailing (node-set, node-set)
2522 * @nodes1 and @nodes2 are sorted by document order, then
2523 * #xmlXPathTrailingSorted is called.
2524 *
2525 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2526 * in document order, @nodes1 if @nodes2 is NULL or empty or
2527 * an empty node-set if @nodes1 doesn't contain @nodes2
2528 */
2529xmlNodeSetPtr
2530xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2531 if (xmlXPathNodeSetIsEmpty(nodes2))
2532 return(nodes1);
2533 if (xmlXPathNodeSetIsEmpty(nodes1))
2534 return(xmlXPathNodeSetCreate(NULL));
2535 xmlXPathNodeSetSort(nodes1);
2536 xmlXPathNodeSetSort(nodes2);
2537 return(xmlXPathNodeTrailingSorted(nodes1,
2538 xmlXPathNodeSetItem(nodes2, 0)));
2539}
2540
Owen Taylor3473f882001-02-23 17:55:21 +00002541/************************************************************************
2542 * *
2543 * Routines to handle extra functions *
2544 * *
2545 ************************************************************************/
2546
2547/**
2548 * xmlXPathRegisterFunc:
2549 * @ctxt: the XPath context
2550 * @name: the function name
2551 * @f: the function implementation or NULL
2552 *
2553 * Register a new function. If @f is NULL it unregisters the function
2554 *
2555 * Returns 0 in case of success, -1 in case of error
2556 */
2557int
2558xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2559 xmlXPathFunction f) {
2560 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2561}
2562
2563/**
2564 * xmlXPathRegisterFuncNS:
2565 * @ctxt: the XPath context
2566 * @name: the function name
2567 * @ns_uri: the function namespace URI
2568 * @f: the function implementation or NULL
2569 *
2570 * Register a new function. If @f is NULL it unregisters the function
2571 *
2572 * Returns 0 in case of success, -1 in case of error
2573 */
2574int
2575xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2576 const xmlChar *ns_uri, xmlXPathFunction f) {
2577 if (ctxt == NULL)
2578 return(-1);
2579 if (name == NULL)
2580 return(-1);
2581
2582 if (ctxt->funcHash == NULL)
2583 ctxt->funcHash = xmlHashCreate(0);
2584 if (ctxt->funcHash == NULL)
2585 return(-1);
2586 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2587}
2588
2589/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002590 * xmlXPathRegisterFuncLookup:
2591 * @ctxt: the XPath context
2592 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002593 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002594 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002595 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002596 */
2597void
2598xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2599 xmlXPathFuncLookupFunc f,
2600 void *funcCtxt) {
2601 if (ctxt == NULL)
2602 return;
2603 ctxt->funcLookupFunc = (void *) f;
2604 ctxt->funcLookupData = funcCtxt;
2605}
2606
2607/**
Owen Taylor3473f882001-02-23 17:55:21 +00002608 * xmlXPathFunctionLookup:
2609 * @ctxt: the XPath context
2610 * @name: the function name
2611 *
2612 * Search in the Function array of the context for the given
2613 * function.
2614 *
2615 * Returns the xmlXPathFunction or NULL if not found
2616 */
2617xmlXPathFunction
2618xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002619 if (ctxt == NULL)
2620 return (NULL);
2621
2622 if (ctxt->funcLookupFunc != NULL) {
2623 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002624 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002625
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002626 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002627 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002628 if (ret != NULL)
2629 return(ret);
2630 }
Owen Taylor3473f882001-02-23 17:55:21 +00002631 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2632}
2633
2634/**
2635 * xmlXPathFunctionLookupNS:
2636 * @ctxt: the XPath context
2637 * @name: the function name
2638 * @ns_uri: the function namespace URI
2639 *
2640 * Search in the Function array of the context for the given
2641 * function.
2642 *
2643 * Returns the xmlXPathFunction or NULL if not found
2644 */
2645xmlXPathFunction
2646xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2647 const xmlChar *ns_uri) {
2648 if (ctxt == NULL)
2649 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002650 if (name == NULL)
2651 return(NULL);
2652
Thomas Broyerba4ad322001-07-26 16:55:21 +00002653 if (ctxt->funcLookupFunc != NULL) {
2654 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002655 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002656
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002657 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002658 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002659 if (ret != NULL)
2660 return(ret);
2661 }
2662
2663 if (ctxt->funcHash == NULL)
2664 return(NULL);
2665
Owen Taylor3473f882001-02-23 17:55:21 +00002666 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2667}
2668
2669/**
2670 * xmlXPathRegisteredFuncsCleanup:
2671 * @ctxt: the XPath context
2672 *
2673 * Cleanup the XPath context data associated to registered functions
2674 */
2675void
2676xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2677 if (ctxt == NULL)
2678 return;
2679
2680 xmlHashFree(ctxt->funcHash, NULL);
2681 ctxt->funcHash = NULL;
2682}
2683
2684/************************************************************************
2685 * *
2686 * Routines to handle Variable *
2687 * *
2688 ************************************************************************/
2689
2690/**
2691 * xmlXPathRegisterVariable:
2692 * @ctxt: the XPath context
2693 * @name: the variable name
2694 * @value: the variable value or NULL
2695 *
2696 * Register a new variable value. If @value is NULL it unregisters
2697 * the variable
2698 *
2699 * Returns 0 in case of success, -1 in case of error
2700 */
2701int
2702xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2703 xmlXPathObjectPtr value) {
2704 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2705}
2706
2707/**
2708 * xmlXPathRegisterVariableNS:
2709 * @ctxt: the XPath context
2710 * @name: the variable name
2711 * @ns_uri: the variable namespace URI
2712 * @value: the variable value or NULL
2713 *
2714 * Register a new variable value. If @value is NULL it unregisters
2715 * the variable
2716 *
2717 * Returns 0 in case of success, -1 in case of error
2718 */
2719int
2720xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2721 const xmlChar *ns_uri,
2722 xmlXPathObjectPtr value) {
2723 if (ctxt == NULL)
2724 return(-1);
2725 if (name == NULL)
2726 return(-1);
2727
2728 if (ctxt->varHash == NULL)
2729 ctxt->varHash = xmlHashCreate(0);
2730 if (ctxt->varHash == NULL)
2731 return(-1);
2732 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2733 (void *) value,
2734 (xmlHashDeallocator)xmlXPathFreeObject));
2735}
2736
2737/**
2738 * xmlXPathRegisterVariableLookup:
2739 * @ctxt: the XPath context
2740 * @f: the lookup function
2741 * @data: the lookup data
2742 *
2743 * register an external mechanism to do variable lookup
2744 */
2745void
2746xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2747 xmlXPathVariableLookupFunc f, void *data) {
2748 if (ctxt == NULL)
2749 return;
2750 ctxt->varLookupFunc = (void *) f;
2751 ctxt->varLookupData = data;
2752}
2753
2754/**
2755 * xmlXPathVariableLookup:
2756 * @ctxt: the XPath context
2757 * @name: the variable name
2758 *
2759 * Search in the Variable array of the context for the given
2760 * variable value.
2761 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002762 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002763 */
2764xmlXPathObjectPtr
2765xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2766 if (ctxt == NULL)
2767 return(NULL);
2768
2769 if (ctxt->varLookupFunc != NULL) {
2770 xmlXPathObjectPtr ret;
2771
2772 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2773 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002774 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002775 }
2776 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2777}
2778
2779/**
2780 * xmlXPathVariableLookupNS:
2781 * @ctxt: the XPath context
2782 * @name: the variable name
2783 * @ns_uri: the variable namespace URI
2784 *
2785 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002786 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002787 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002788 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002789 */
2790xmlXPathObjectPtr
2791xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2792 const xmlChar *ns_uri) {
2793 if (ctxt == NULL)
2794 return(NULL);
2795
2796 if (ctxt->varLookupFunc != NULL) {
2797 xmlXPathObjectPtr ret;
2798
2799 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2800 (ctxt->varLookupData, name, ns_uri);
2801 if (ret != NULL) return(ret);
2802 }
2803
2804 if (ctxt->varHash == NULL)
2805 return(NULL);
2806 if (name == NULL)
2807 return(NULL);
2808
Daniel Veillard8c357d52001-07-03 23:43:33 +00002809 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2810 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002811}
2812
2813/**
2814 * xmlXPathRegisteredVariablesCleanup:
2815 * @ctxt: the XPath context
2816 *
2817 * Cleanup the XPath context data associated to registered variables
2818 */
2819void
2820xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2821 if (ctxt == NULL)
2822 return;
2823
Daniel Veillard76d66f42001-05-16 21:05:17 +00002824 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002825 ctxt->varHash = NULL;
2826}
2827
2828/**
2829 * xmlXPathRegisterNs:
2830 * @ctxt: the XPath context
2831 * @prefix: the namespace prefix
2832 * @ns_uri: the namespace name
2833 *
2834 * Register a new namespace. If @ns_uri is NULL it unregisters
2835 * the namespace
2836 *
2837 * Returns 0 in case of success, -1 in case of error
2838 */
2839int
2840xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2841 const xmlChar *ns_uri) {
2842 if (ctxt == NULL)
2843 return(-1);
2844 if (prefix == NULL)
2845 return(-1);
2846
2847 if (ctxt->nsHash == NULL)
2848 ctxt->nsHash = xmlHashCreate(10);
2849 if (ctxt->nsHash == NULL)
2850 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002851 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002852 (xmlHashDeallocator)xmlFree));
2853}
2854
2855/**
2856 * xmlXPathNsLookup:
2857 * @ctxt: the XPath context
2858 * @prefix: the namespace prefix value
2859 *
2860 * Search in the namespace declaration array of the context for the given
2861 * namespace name associated to the given prefix
2862 *
2863 * Returns the value or NULL if not found
2864 */
2865const xmlChar *
2866xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2867 if (ctxt == NULL)
2868 return(NULL);
2869 if (prefix == NULL)
2870 return(NULL);
2871
2872#ifdef XML_XML_NAMESPACE
2873 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2874 return(XML_XML_NAMESPACE);
2875#endif
2876
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002877 if (ctxt->namespaces != NULL) {
2878 int i;
2879
2880 for (i = 0;i < ctxt->nsNr;i++) {
2881 if ((ctxt->namespaces[i] != NULL) &&
2882 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2883 return(ctxt->namespaces[i]->href);
2884 }
2885 }
Owen Taylor3473f882001-02-23 17:55:21 +00002886
2887 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2888}
2889
2890/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002891 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002892 * @ctxt: the XPath context
2893 *
2894 * Cleanup the XPath context data associated to registered variables
2895 */
2896void
2897xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2898 if (ctxt == NULL)
2899 return;
2900
Daniel Veillard42766c02002-08-22 20:52:17 +00002901 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002902 ctxt->nsHash = NULL;
2903}
2904
2905/************************************************************************
2906 * *
2907 * Routines to handle Values *
2908 * *
2909 ************************************************************************/
2910
2911/* Allocations are terrible, one need to optimize all this !!! */
2912
2913/**
2914 * xmlXPathNewFloat:
2915 * @val: the double value
2916 *
2917 * Create a new xmlXPathObjectPtr of type double and of value @val
2918 *
2919 * Returns the newly created object.
2920 */
2921xmlXPathObjectPtr
2922xmlXPathNewFloat(double val) {
2923 xmlXPathObjectPtr ret;
2924
2925 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2926 if (ret == NULL) {
2927 xmlGenericError(xmlGenericErrorContext,
2928 "xmlXPathNewFloat: out of memory\n");
2929 return(NULL);
2930 }
2931 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2932 ret->type = XPATH_NUMBER;
2933 ret->floatval = val;
2934 return(ret);
2935}
2936
2937/**
2938 * xmlXPathNewBoolean:
2939 * @val: the boolean value
2940 *
2941 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2942 *
2943 * Returns the newly created object.
2944 */
2945xmlXPathObjectPtr
2946xmlXPathNewBoolean(int val) {
2947 xmlXPathObjectPtr ret;
2948
2949 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2950 if (ret == NULL) {
2951 xmlGenericError(xmlGenericErrorContext,
2952 "xmlXPathNewBoolean: out of memory\n");
2953 return(NULL);
2954 }
2955 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2956 ret->type = XPATH_BOOLEAN;
2957 ret->boolval = (val != 0);
2958 return(ret);
2959}
2960
2961/**
2962 * xmlXPathNewString:
2963 * @val: the xmlChar * value
2964 *
2965 * Create a new xmlXPathObjectPtr of type string and of value @val
2966 *
2967 * Returns the newly created object.
2968 */
2969xmlXPathObjectPtr
2970xmlXPathNewString(const xmlChar *val) {
2971 xmlXPathObjectPtr ret;
2972
2973 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2974 if (ret == NULL) {
2975 xmlGenericError(xmlGenericErrorContext,
2976 "xmlXPathNewString: out of memory\n");
2977 return(NULL);
2978 }
2979 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2980 ret->type = XPATH_STRING;
2981 if (val != NULL)
2982 ret->stringval = xmlStrdup(val);
2983 else
2984 ret->stringval = xmlStrdup((const xmlChar *)"");
2985 return(ret);
2986}
2987
2988/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002989 * xmlXPathWrapString:
2990 * @val: the xmlChar * value
2991 *
2992 * Wraps the @val string into an XPath object.
2993 *
2994 * Returns the newly created object.
2995 */
2996xmlXPathObjectPtr
2997xmlXPathWrapString (xmlChar *val) {
2998 xmlXPathObjectPtr ret;
2999
3000 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3001 if (ret == NULL) {
3002 xmlGenericError(xmlGenericErrorContext,
3003 "xmlXPathWrapString: out of memory\n");
3004 return(NULL);
3005 }
3006 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3007 ret->type = XPATH_STRING;
3008 ret->stringval = val;
3009 return(ret);
3010}
3011
3012/**
Owen Taylor3473f882001-02-23 17:55:21 +00003013 * xmlXPathNewCString:
3014 * @val: the char * value
3015 *
3016 * Create a new xmlXPathObjectPtr of type string and of value @val
3017 *
3018 * Returns the newly created object.
3019 */
3020xmlXPathObjectPtr
3021xmlXPathNewCString(const char *val) {
3022 xmlXPathObjectPtr ret;
3023
3024 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3025 if (ret == NULL) {
3026 xmlGenericError(xmlGenericErrorContext,
3027 "xmlXPathNewCString: out of memory\n");
3028 return(NULL);
3029 }
3030 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3031 ret->type = XPATH_STRING;
3032 ret->stringval = xmlStrdup(BAD_CAST val);
3033 return(ret);
3034}
3035
3036/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003037 * xmlXPathWrapCString:
3038 * @val: the char * value
3039 *
3040 * Wraps a string into an XPath object.
3041 *
3042 * Returns the newly created object.
3043 */
3044xmlXPathObjectPtr
3045xmlXPathWrapCString (char * val) {
3046 return(xmlXPathWrapString((xmlChar *)(val)));
3047}
3048
3049/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003050 * xmlXPathWrapExternal:
3051 * @val: the user data
3052 *
3053 * Wraps the @val data into an XPath object.
3054 *
3055 * Returns the newly created object.
3056 */
3057xmlXPathObjectPtr
3058xmlXPathWrapExternal (void *val) {
3059 xmlXPathObjectPtr ret;
3060
3061 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3062 if (ret == NULL) {
3063 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003064 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003065 return(NULL);
3066 }
3067 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3068 ret->type = XPATH_USERS;
3069 ret->user = val;
3070 return(ret);
3071}
3072
3073/**
Owen Taylor3473f882001-02-23 17:55:21 +00003074 * xmlXPathObjectCopy:
3075 * @val: the original object
3076 *
3077 * allocate a new copy of a given object
3078 *
3079 * Returns the newly created object.
3080 */
3081xmlXPathObjectPtr
3082xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3083 xmlXPathObjectPtr ret;
3084
3085 if (val == NULL)
3086 return(NULL);
3087
3088 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3089 if (ret == NULL) {
3090 xmlGenericError(xmlGenericErrorContext,
3091 "xmlXPathObjectCopy: out of memory\n");
3092 return(NULL);
3093 }
3094 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3095 switch (val->type) {
3096 case XPATH_BOOLEAN:
3097 case XPATH_NUMBER:
3098 case XPATH_POINT:
3099 case XPATH_RANGE:
3100 break;
3101 case XPATH_STRING:
3102 ret->stringval = xmlStrdup(val->stringval);
3103 break;
3104 case XPATH_XSLT_TREE:
3105 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003106 (val->nodesetval->nodeTab != NULL)) {
3107 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003108 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3109 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003110 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003111 (xmlNodePtr) ret->user);
3112 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003113 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003114 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003115 break;
3116 case XPATH_NODESET:
3117 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003118 /* Do not deallocate the copied tree value */
3119 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003120 break;
3121 case XPATH_LOCATIONSET:
3122#ifdef LIBXML_XPTR_ENABLED
3123 {
3124 xmlLocationSetPtr loc = val->user;
3125 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3126 break;
3127 }
3128#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003129 case XPATH_USERS:
3130 ret->user = val->user;
3131 break;
3132 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003133 xmlGenericError(xmlGenericErrorContext,
3134 "xmlXPathObjectCopy: unsupported type %d\n",
3135 val->type);
3136 break;
3137 }
3138 return(ret);
3139}
3140
3141/**
3142 * xmlXPathFreeObject:
3143 * @obj: the object to free
3144 *
3145 * Free up an xmlXPathObjectPtr object.
3146 */
3147void
3148xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3149 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003150 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003151 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003152 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003153 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003154 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003155 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003156 xmlXPathFreeValueTree(obj->nodesetval);
3157 } else {
3158 if (obj->nodesetval != NULL)
3159 xmlXPathFreeNodeSet(obj->nodesetval);
3160 }
Owen Taylor3473f882001-02-23 17:55:21 +00003161#ifdef LIBXML_XPTR_ENABLED
3162 } else if (obj->type == XPATH_LOCATIONSET) {
3163 if (obj->user != NULL)
3164 xmlXPtrFreeLocationSet(obj->user);
3165#endif
3166 } else if (obj->type == XPATH_STRING) {
3167 if (obj->stringval != NULL)
3168 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003169 }
3170
Owen Taylor3473f882001-02-23 17:55:21 +00003171 xmlFree(obj);
3172}
3173
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003174
3175/************************************************************************
3176 * *
3177 * Type Casting Routines *
3178 * *
3179 ************************************************************************/
3180
3181/**
3182 * xmlXPathCastBooleanToString:
3183 * @val: a boolean
3184 *
3185 * Converts a boolean to its string value.
3186 *
3187 * Returns a newly allocated string.
3188 */
3189xmlChar *
3190xmlXPathCastBooleanToString (int val) {
3191 xmlChar *ret;
3192 if (val)
3193 ret = xmlStrdup((const xmlChar *) "true");
3194 else
3195 ret = xmlStrdup((const xmlChar *) "false");
3196 return(ret);
3197}
3198
3199/**
3200 * xmlXPathCastNumberToString:
3201 * @val: a number
3202 *
3203 * Converts a number to its string value.
3204 *
3205 * Returns a newly allocated string.
3206 */
3207xmlChar *
3208xmlXPathCastNumberToString (double val) {
3209 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003210 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003211 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003212 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003213 break;
3214 case -1:
3215 ret = xmlStrdup((const xmlChar *) "-Infinity");
3216 break;
3217 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003218 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003219 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003220 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3221 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003222 } else {
3223 /* could be improved */
3224 char buf[100];
3225 xmlXPathFormatNumber(val, buf, 100);
3226 ret = xmlStrdup((const xmlChar *) buf);
3227 }
3228 }
3229 return(ret);
3230}
3231
3232/**
3233 * xmlXPathCastNodeToString:
3234 * @node: a node
3235 *
3236 * Converts a node to its string value.
3237 *
3238 * Returns a newly allocated string.
3239 */
3240xmlChar *
3241xmlXPathCastNodeToString (xmlNodePtr node) {
Daniel Veillard23b1f372002-04-18 15:50:05 +00003242 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE))
3243 node = xmlDocGetRootElement((xmlDocPtr) node);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003244 return(xmlNodeGetContent(node));
3245}
3246
3247/**
3248 * xmlXPathCastNodeSetToString:
3249 * @ns: a node-set
3250 *
3251 * Converts a node-set to its string value.
3252 *
3253 * Returns a newly allocated string.
3254 */
3255xmlChar *
3256xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3257 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3258 return(xmlStrdup((const xmlChar *) ""));
3259
3260 xmlXPathNodeSetSort(ns);
3261 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3262}
3263
3264/**
3265 * xmlXPathCastToString:
3266 * @val: an XPath object
3267 *
3268 * Converts an existing object to its string() equivalent
3269 *
3270 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003271 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003272 * string object).
3273 */
3274xmlChar *
3275xmlXPathCastToString(xmlXPathObjectPtr val) {
3276 xmlChar *ret = NULL;
3277
3278 if (val == NULL)
3279 return(xmlStrdup((const xmlChar *) ""));
3280 switch (val->type) {
3281 case XPATH_UNDEFINED:
3282#ifdef DEBUG_EXPR
3283 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3284#endif
3285 ret = xmlStrdup((const xmlChar *) "");
3286 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003287 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003288 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003289 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3290 break;
3291 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003292 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003293 case XPATH_BOOLEAN:
3294 ret = xmlXPathCastBooleanToString(val->boolval);
3295 break;
3296 case XPATH_NUMBER: {
3297 ret = xmlXPathCastNumberToString(val->floatval);
3298 break;
3299 }
3300 case XPATH_USERS:
3301 case XPATH_POINT:
3302 case XPATH_RANGE:
3303 case XPATH_LOCATIONSET:
3304 TODO
3305 ret = xmlStrdup((const xmlChar *) "");
3306 break;
3307 }
3308 return(ret);
3309}
3310
3311/**
3312 * xmlXPathConvertString:
3313 * @val: an XPath object
3314 *
3315 * Converts an existing object to its string() equivalent
3316 *
3317 * Returns the new object, the old one is freed (or the operation
3318 * is done directly on @val)
3319 */
3320xmlXPathObjectPtr
3321xmlXPathConvertString(xmlXPathObjectPtr val) {
3322 xmlChar *res = NULL;
3323
3324 if (val == NULL)
3325 return(xmlXPathNewCString(""));
3326
3327 switch (val->type) {
3328 case XPATH_UNDEFINED:
3329#ifdef DEBUG_EXPR
3330 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3331#endif
3332 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003333 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003334 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003335 res = xmlXPathCastNodeSetToString(val->nodesetval);
3336 break;
3337 case XPATH_STRING:
3338 return(val);
3339 case XPATH_BOOLEAN:
3340 res = xmlXPathCastBooleanToString(val->boolval);
3341 break;
3342 case XPATH_NUMBER:
3343 res = xmlXPathCastNumberToString(val->floatval);
3344 break;
3345 case XPATH_USERS:
3346 case XPATH_POINT:
3347 case XPATH_RANGE:
3348 case XPATH_LOCATIONSET:
3349 TODO;
3350 break;
3351 }
3352 xmlXPathFreeObject(val);
3353 if (res == NULL)
3354 return(xmlXPathNewCString(""));
3355 return(xmlXPathWrapString(res));
3356}
3357
3358/**
3359 * xmlXPathCastBooleanToNumber:
3360 * @val: a boolean
3361 *
3362 * Converts a boolean to its number value
3363 *
3364 * Returns the number value
3365 */
3366double
3367xmlXPathCastBooleanToNumber(int val) {
3368 if (val)
3369 return(1.0);
3370 return(0.0);
3371}
3372
3373/**
3374 * xmlXPathCastStringToNumber:
3375 * @val: a string
3376 *
3377 * Converts a string to its number value
3378 *
3379 * Returns the number value
3380 */
3381double
3382xmlXPathCastStringToNumber(const xmlChar * val) {
3383 return(xmlXPathStringEvalNumber(val));
3384}
3385
3386/**
3387 * xmlXPathCastNodeToNumber:
3388 * @node: a node
3389 *
3390 * Converts a node to its number value
3391 *
3392 * Returns the number value
3393 */
3394double
3395xmlXPathCastNodeToNumber (xmlNodePtr node) {
3396 xmlChar *strval;
3397 double ret;
3398
3399 if (node == NULL)
3400 return(xmlXPathNAN);
3401 strval = xmlXPathCastNodeToString(node);
3402 if (strval == NULL)
3403 return(xmlXPathNAN);
3404 ret = xmlXPathCastStringToNumber(strval);
3405 xmlFree(strval);
3406
3407 return(ret);
3408}
3409
3410/**
3411 * xmlXPathCastNodeSetToNumber:
3412 * @ns: a node-set
3413 *
3414 * Converts a node-set to its number value
3415 *
3416 * Returns the number value
3417 */
3418double
3419xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3420 xmlChar *str;
3421 double ret;
3422
3423 if (ns == NULL)
3424 return(xmlXPathNAN);
3425 str = xmlXPathCastNodeSetToString(ns);
3426 ret = xmlXPathCastStringToNumber(str);
3427 xmlFree(str);
3428 return(ret);
3429}
3430
3431/**
3432 * xmlXPathCastToNumber:
3433 * @val: an XPath object
3434 *
3435 * Converts an XPath object to its number value
3436 *
3437 * Returns the number value
3438 */
3439double
3440xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3441 double ret = 0.0;
3442
3443 if (val == NULL)
3444 return(xmlXPathNAN);
3445 switch (val->type) {
3446 case XPATH_UNDEFINED:
3447#ifdef DEGUB_EXPR
3448 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3449#endif
3450 ret = xmlXPathNAN;
3451 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003452 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003453 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003454 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3455 break;
3456 case XPATH_STRING:
3457 ret = xmlXPathCastStringToNumber(val->stringval);
3458 break;
3459 case XPATH_NUMBER:
3460 ret = val->floatval;
3461 break;
3462 case XPATH_BOOLEAN:
3463 ret = xmlXPathCastBooleanToNumber(val->boolval);
3464 break;
3465 case XPATH_USERS:
3466 case XPATH_POINT:
3467 case XPATH_RANGE:
3468 case XPATH_LOCATIONSET:
3469 TODO;
3470 ret = xmlXPathNAN;
3471 break;
3472 }
3473 return(ret);
3474}
3475
3476/**
3477 * xmlXPathConvertNumber:
3478 * @val: an XPath object
3479 *
3480 * Converts an existing object to its number() equivalent
3481 *
3482 * Returns the new object, the old one is freed (or the operation
3483 * is done directly on @val)
3484 */
3485xmlXPathObjectPtr
3486xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3487 xmlXPathObjectPtr ret;
3488
3489 if (val == NULL)
3490 return(xmlXPathNewFloat(0.0));
3491 if (val->type == XPATH_NUMBER)
3492 return(val);
3493 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3494 xmlXPathFreeObject(val);
3495 return(ret);
3496}
3497
3498/**
3499 * xmlXPathCastNumberToBoolean:
3500 * @val: a number
3501 *
3502 * Converts a number to its boolean value
3503 *
3504 * Returns the boolean value
3505 */
3506int
3507xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003508 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003509 return(0);
3510 return(1);
3511}
3512
3513/**
3514 * xmlXPathCastStringToBoolean:
3515 * @val: a string
3516 *
3517 * Converts a string to its boolean value
3518 *
3519 * Returns the boolean value
3520 */
3521int
3522xmlXPathCastStringToBoolean (const xmlChar *val) {
3523 if ((val == NULL) || (xmlStrlen(val) == 0))
3524 return(0);
3525 return(1);
3526}
3527
3528/**
3529 * xmlXPathCastNodeSetToBoolean:
3530 * @ns: a node-set
3531 *
3532 * Converts a node-set to its boolean value
3533 *
3534 * Returns the boolean value
3535 */
3536int
3537xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3538 if ((ns == NULL) || (ns->nodeNr == 0))
3539 return(0);
3540 return(1);
3541}
3542
3543/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003544 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003545 * @val: an XPath object
3546 *
3547 * Converts an XPath object to its boolean value
3548 *
3549 * Returns the boolean value
3550 */
3551int
3552xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3553 int ret = 0;
3554
3555 if (val == NULL)
3556 return(0);
3557 switch (val->type) {
3558 case XPATH_UNDEFINED:
3559#ifdef DEBUG_EXPR
3560 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3561#endif
3562 ret = 0;
3563 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003564 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003565 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003566 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3567 break;
3568 case XPATH_STRING:
3569 ret = xmlXPathCastStringToBoolean(val->stringval);
3570 break;
3571 case XPATH_NUMBER:
3572 ret = xmlXPathCastNumberToBoolean(val->floatval);
3573 break;
3574 case XPATH_BOOLEAN:
3575 ret = val->boolval;
3576 break;
3577 case XPATH_USERS:
3578 case XPATH_POINT:
3579 case XPATH_RANGE:
3580 case XPATH_LOCATIONSET:
3581 TODO;
3582 ret = 0;
3583 break;
3584 }
3585 return(ret);
3586}
3587
3588
3589/**
3590 * xmlXPathConvertBoolean:
3591 * @val: an XPath object
3592 *
3593 * Converts an existing object to its boolean() equivalent
3594 *
3595 * Returns the new object, the old one is freed (or the operation
3596 * is done directly on @val)
3597 */
3598xmlXPathObjectPtr
3599xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3600 xmlXPathObjectPtr ret;
3601
3602 if (val == NULL)
3603 return(xmlXPathNewBoolean(0));
3604 if (val->type == XPATH_BOOLEAN)
3605 return(val);
3606 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3607 xmlXPathFreeObject(val);
3608 return(ret);
3609}
3610
Owen Taylor3473f882001-02-23 17:55:21 +00003611/************************************************************************
3612 * *
3613 * Routines to handle XPath contexts *
3614 * *
3615 ************************************************************************/
3616
3617/**
3618 * xmlXPathNewContext:
3619 * @doc: the XML document
3620 *
3621 * Create a new xmlXPathContext
3622 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003623 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003624 */
3625xmlXPathContextPtr
3626xmlXPathNewContext(xmlDocPtr doc) {
3627 xmlXPathContextPtr ret;
3628
3629 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3630 if (ret == NULL) {
3631 xmlGenericError(xmlGenericErrorContext,
3632 "xmlXPathNewContext: out of memory\n");
3633 return(NULL);
3634 }
3635 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3636 ret->doc = doc;
3637 ret->node = NULL;
3638
3639 ret->varHash = NULL;
3640
3641 ret->nb_types = 0;
3642 ret->max_types = 0;
3643 ret->types = NULL;
3644
3645 ret->funcHash = xmlHashCreate(0);
3646
3647 ret->nb_axis = 0;
3648 ret->max_axis = 0;
3649 ret->axis = NULL;
3650
3651 ret->nsHash = NULL;
3652 ret->user = NULL;
3653
3654 ret->contextSize = -1;
3655 ret->proximityPosition = -1;
3656
3657 xmlXPathRegisterAllFunctions(ret);
3658
3659 return(ret);
3660}
3661
3662/**
3663 * xmlXPathFreeContext:
3664 * @ctxt: the context to free
3665 *
3666 * Free up an xmlXPathContext
3667 */
3668void
3669xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3670 xmlXPathRegisteredNsCleanup(ctxt);
3671 xmlXPathRegisteredFuncsCleanup(ctxt);
3672 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003673 xmlFree(ctxt);
3674}
3675
3676/************************************************************************
3677 * *
3678 * Routines to handle XPath parser contexts *
3679 * *
3680 ************************************************************************/
3681
3682#define CHECK_CTXT(ctxt) \
3683 if (ctxt == NULL) { \
3684 xmlGenericError(xmlGenericErrorContext, \
3685 "%s:%d Internal error: ctxt == NULL\n", \
3686 __FILE__, __LINE__); \
3687 } \
3688
3689
3690#define CHECK_CONTEXT(ctxt) \
3691 if (ctxt == NULL) { \
3692 xmlGenericError(xmlGenericErrorContext, \
3693 "%s:%d Internal error: no context\n", \
3694 __FILE__, __LINE__); \
3695 } \
3696 else if (ctxt->doc == NULL) { \
3697 xmlGenericError(xmlGenericErrorContext, \
3698 "%s:%d Internal error: no document\n", \
3699 __FILE__, __LINE__); \
3700 } \
3701 else if (ctxt->doc->children == NULL) { \
3702 xmlGenericError(xmlGenericErrorContext, \
3703 "%s:%d Internal error: document without root\n", \
3704 __FILE__, __LINE__); \
3705 } \
3706
3707
3708/**
3709 * xmlXPathNewParserContext:
3710 * @str: the XPath expression
3711 * @ctxt: the XPath context
3712 *
3713 * Create a new xmlXPathParserContext
3714 *
3715 * Returns the xmlXPathParserContext just allocated.
3716 */
3717xmlXPathParserContextPtr
3718xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3719 xmlXPathParserContextPtr ret;
3720
3721 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3722 if (ret == NULL) {
3723 xmlGenericError(xmlGenericErrorContext,
3724 "xmlXPathNewParserContext: out of memory\n");
3725 return(NULL);
3726 }
3727 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3728 ret->cur = ret->base = str;
3729 ret->context = ctxt;
3730
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003731 ret->comp = xmlXPathNewCompExpr();
3732 if (ret->comp == NULL) {
3733 xmlFree(ret->valueTab);
3734 xmlFree(ret);
3735 return(NULL);
3736 }
3737
3738 return(ret);
3739}
3740
3741/**
3742 * xmlXPathCompParserContext:
3743 * @comp: the XPath compiled expression
3744 * @ctxt: the XPath context
3745 *
3746 * Create a new xmlXPathParserContext when processing a compiled expression
3747 *
3748 * Returns the xmlXPathParserContext just allocated.
3749 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003750static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003751xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3752 xmlXPathParserContextPtr ret;
3753
3754 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3755 if (ret == NULL) {
3756 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003757 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003758 return(NULL);
3759 }
3760 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3761
Owen Taylor3473f882001-02-23 17:55:21 +00003762 /* Allocate the value stack */
3763 ret->valueTab = (xmlXPathObjectPtr *)
3764 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003765 if (ret->valueTab == NULL) {
3766 xmlFree(ret);
3767 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003768 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003769 return(NULL);
3770 }
Owen Taylor3473f882001-02-23 17:55:21 +00003771 ret->valueNr = 0;
3772 ret->valueMax = 10;
3773 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003774
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003775 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003776 ret->comp = comp;
3777
Owen Taylor3473f882001-02-23 17:55:21 +00003778 return(ret);
3779}
3780
3781/**
3782 * xmlXPathFreeParserContext:
3783 * @ctxt: the context to free
3784 *
3785 * Free up an xmlXPathParserContext
3786 */
3787void
3788xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3789 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003790 xmlFree(ctxt->valueTab);
3791 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003792 if (ctxt->comp)
3793 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003794 xmlFree(ctxt);
3795}
3796
3797/************************************************************************
3798 * *
3799 * The implicit core function library *
3800 * *
3801 ************************************************************************/
3802
Owen Taylor3473f882001-02-23 17:55:21 +00003803/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003804 * xmlXPathNodeStringHash:
3805 * @node: a node pointer
3806 *
3807 * Function computing the beginning of the string value of the node,
3808 * used to speed up comparisons
3809 *
3810 * Returns an int usable as a hash
3811 */
3812static unsigned int
3813xmlXPathNodeValHash(xmlNodePtr node) {
3814 int len = 2;
3815 const xmlChar * string = NULL;
3816 xmlNodePtr tmp = NULL;
3817 unsigned int ret = 0;
3818
3819 if (node == NULL)
3820 return(0);
3821
3822
3823 switch (node->type) {
3824 case XML_COMMENT_NODE:
3825 case XML_PI_NODE:
3826 case XML_CDATA_SECTION_NODE:
3827 case XML_TEXT_NODE:
3828 string = node->content;
3829 if (string == NULL)
3830 return(0);
3831 if (string[0] == 0)
3832 return(0);
3833 return(((unsigned int) string[0]) +
3834 (((unsigned int) string[1]) << 8));
3835 case XML_NAMESPACE_DECL:
3836 string = ((xmlNsPtr)node)->href;
3837 if (string == NULL)
3838 return(0);
3839 if (string[0] == 0)
3840 return(0);
3841 return(((unsigned int) string[0]) +
3842 (((unsigned int) string[1]) << 8));
3843 case XML_ATTRIBUTE_NODE:
3844 tmp = ((xmlAttrPtr) node)->children;
3845 break;
3846 case XML_ELEMENT_NODE:
3847 tmp = node->children;
3848 break;
3849 default:
3850 return(0);
3851 }
3852 while (tmp != NULL) {
3853 switch (tmp->type) {
3854 case XML_COMMENT_NODE:
3855 case XML_PI_NODE:
3856 case XML_CDATA_SECTION_NODE:
3857 case XML_TEXT_NODE:
3858 string = tmp->content;
3859 break;
3860 case XML_NAMESPACE_DECL:
3861 string = ((xmlNsPtr)tmp)->href;
3862 break;
3863 default:
3864 break;
3865 }
3866 if ((string != NULL) && (string[0] != 0)) {
3867 if (string[0] == 0)
3868 return(0);
3869 if (len == 1) {
3870 return(ret + (((unsigned int) string[0]) << 8));
3871 }
3872 if (string[1] == 0) {
3873 len = 1;
3874 ret = (unsigned int) string[0];
3875 } else {
3876 return(((unsigned int) string[0]) +
3877 (((unsigned int) string[1]) << 8));
3878 }
3879 }
3880 /*
3881 * Skip to next node
3882 */
3883 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3884 if (tmp->children->type != XML_ENTITY_DECL) {
3885 tmp = tmp->children;
3886 continue;
3887 }
3888 }
3889 if (tmp == node)
3890 break;
3891
3892 if (tmp->next != NULL) {
3893 tmp = tmp->next;
3894 continue;
3895 }
3896
3897 do {
3898 tmp = tmp->parent;
3899 if (tmp == NULL)
3900 break;
3901 if (tmp == node) {
3902 tmp = NULL;
3903 break;
3904 }
3905 if (tmp->next != NULL) {
3906 tmp = tmp->next;
3907 break;
3908 }
3909 } while (tmp != NULL);
3910 }
3911 return(ret);
3912}
3913
3914/**
3915 * xmlXPathStringHash:
3916 * @string: a string
3917 *
3918 * Function computing the beginning of the string value of the node,
3919 * used to speed up comparisons
3920 *
3921 * Returns an int usable as a hash
3922 */
3923static unsigned int
3924xmlXPathStringHash(const xmlChar * string) {
3925 if (string == NULL)
3926 return((unsigned int) 0);
3927 if (string[0] == 0)
3928 return(0);
3929 return(((unsigned int) string[0]) +
3930 (((unsigned int) string[1]) << 8));
3931}
3932
3933/**
Owen Taylor3473f882001-02-23 17:55:21 +00003934 * xmlXPathCompareNodeSetFloat:
3935 * @ctxt: the XPath Parser context
3936 * @inf: less than (1) or greater than (0)
3937 * @strict: is the comparison strict
3938 * @arg: the node set
3939 * @f: the value
3940 *
3941 * Implement the compare operation between a nodeset and a number
3942 * @ns < @val (1, 1, ...
3943 * @ns <= @val (1, 0, ...
3944 * @ns > @val (0, 1, ...
3945 * @ns >= @val (0, 0, ...
3946 *
3947 * If one object to be compared is a node-set and the other is a number,
3948 * then the comparison will be true if and only if there is a node in the
3949 * node-set such that the result of performing the comparison on the number
3950 * to be compared and on the result of converting the string-value of that
3951 * node to a number using the number function is true.
3952 *
3953 * Returns 0 or 1 depending on the results of the test.
3954 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003955static int
Owen Taylor3473f882001-02-23 17:55:21 +00003956xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3957 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3958 int i, ret = 0;
3959 xmlNodeSetPtr ns;
3960 xmlChar *str2;
3961
3962 if ((f == NULL) || (arg == NULL) ||
3963 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3964 xmlXPathFreeObject(arg);
3965 xmlXPathFreeObject(f);
3966 return(0);
3967 }
3968 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003969 if (ns != NULL) {
3970 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003971 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003972 if (str2 != NULL) {
3973 valuePush(ctxt,
3974 xmlXPathNewString(str2));
3975 xmlFree(str2);
3976 xmlXPathNumberFunction(ctxt, 1);
3977 valuePush(ctxt, xmlXPathObjectCopy(f));
3978 ret = xmlXPathCompareValues(ctxt, inf, strict);
3979 if (ret)
3980 break;
3981 }
3982 }
Owen Taylor3473f882001-02-23 17:55:21 +00003983 }
3984 xmlXPathFreeObject(arg);
3985 xmlXPathFreeObject(f);
3986 return(ret);
3987}
3988
3989/**
3990 * xmlXPathCompareNodeSetString:
3991 * @ctxt: the XPath Parser context
3992 * @inf: less than (1) or greater than (0)
3993 * @strict: is the comparison strict
3994 * @arg: the node set
3995 * @s: the value
3996 *
3997 * Implement the compare operation between a nodeset and a string
3998 * @ns < @val (1, 1, ...
3999 * @ns <= @val (1, 0, ...
4000 * @ns > @val (0, 1, ...
4001 * @ns >= @val (0, 0, ...
4002 *
4003 * If one object to be compared is a node-set and the other is a string,
4004 * then the comparison will be true if and only if there is a node in
4005 * the node-set such that the result of performing the comparison on the
4006 * string-value of the node and the other string is true.
4007 *
4008 * Returns 0 or 1 depending on the results of the test.
4009 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004010static int
Owen Taylor3473f882001-02-23 17:55:21 +00004011xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4012 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4013 int i, ret = 0;
4014 xmlNodeSetPtr ns;
4015 xmlChar *str2;
4016
4017 if ((s == NULL) || (arg == NULL) ||
4018 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4019 xmlXPathFreeObject(arg);
4020 xmlXPathFreeObject(s);
4021 return(0);
4022 }
4023 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004024 if (ns != NULL) {
4025 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004026 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004027 if (str2 != NULL) {
4028 valuePush(ctxt,
4029 xmlXPathNewString(str2));
4030 xmlFree(str2);
4031 valuePush(ctxt, xmlXPathObjectCopy(s));
4032 ret = xmlXPathCompareValues(ctxt, inf, strict);
4033 if (ret)
4034 break;
4035 }
4036 }
Owen Taylor3473f882001-02-23 17:55:21 +00004037 }
4038 xmlXPathFreeObject(arg);
4039 xmlXPathFreeObject(s);
4040 return(ret);
4041}
4042
4043/**
4044 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004045 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004046 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004047 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004048 * @arg2: the second node set object
4049 *
4050 * Implement the compare operation on nodesets:
4051 *
4052 * If both objects to be compared are node-sets, then the comparison
4053 * will be true if and only if there is a node in the first node-set
4054 * and a node in the second node-set such that the result of performing
4055 * the comparison on the string-values of the two nodes is true.
4056 * ....
4057 * When neither object to be compared is a node-set and the operator
4058 * is <=, <, >= or >, then the objects are compared by converting both
4059 * objects to numbers and comparing the numbers according to IEEE 754.
4060 * ....
4061 * The number function converts its argument to a number as follows:
4062 * - a string that consists of optional whitespace followed by an
4063 * optional minus sign followed by a Number followed by whitespace
4064 * is converted to the IEEE 754 number that is nearest (according
4065 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4066 * represented by the string; any other string is converted to NaN
4067 *
4068 * Conclusion all nodes need to be converted first to their string value
4069 * and then the comparison must be done when possible
4070 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004071static int
4072xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004073 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4074 int i, j, init = 0;
4075 double val1;
4076 double *values2;
4077 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004078 xmlNodeSetPtr ns1;
4079 xmlNodeSetPtr ns2;
4080
4081 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004082 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4083 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004084 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004085 }
Owen Taylor3473f882001-02-23 17:55:21 +00004086 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004087 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4088 xmlXPathFreeObject(arg1);
4089 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004090 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004091 }
Owen Taylor3473f882001-02-23 17:55:21 +00004092
4093 ns1 = arg1->nodesetval;
4094 ns2 = arg2->nodesetval;
4095
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004096 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004097 xmlXPathFreeObject(arg1);
4098 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004099 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004100 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004101 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004102 xmlXPathFreeObject(arg1);
4103 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004104 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004105 }
Owen Taylor3473f882001-02-23 17:55:21 +00004106
4107 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4108 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004109 xmlXPathFreeObject(arg1);
4110 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004111 return(0);
4112 }
4113 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004114 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004115 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004116 continue;
4117 for (j = 0;j < ns2->nodeNr;j++) {
4118 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004119 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004120 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004121 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004122 continue;
4123 if (inf && strict)
4124 ret = (val1 < values2[j]);
4125 else if (inf && !strict)
4126 ret = (val1 <= values2[j]);
4127 else if (!inf && strict)
4128 ret = (val1 > values2[j]);
4129 else if (!inf && !strict)
4130 ret = (val1 >= values2[j]);
4131 if (ret)
4132 break;
4133 }
4134 if (ret)
4135 break;
4136 init = 1;
4137 }
4138 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004139 xmlXPathFreeObject(arg1);
4140 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004141 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004142}
4143
4144/**
4145 * xmlXPathCompareNodeSetValue:
4146 * @ctxt: the XPath Parser context
4147 * @inf: less than (1) or greater than (0)
4148 * @strict: is the comparison strict
4149 * @arg: the node set
4150 * @val: the value
4151 *
4152 * Implement the compare operation between a nodeset and a value
4153 * @ns < @val (1, 1, ...
4154 * @ns <= @val (1, 0, ...
4155 * @ns > @val (0, 1, ...
4156 * @ns >= @val (0, 0, ...
4157 *
4158 * If one object to be compared is a node-set and the other is a boolean,
4159 * then the comparison will be true if and only if the result of performing
4160 * the comparison on the boolean and on the result of converting
4161 * the node-set to a boolean using the boolean function is true.
4162 *
4163 * Returns 0 or 1 depending on the results of the test.
4164 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004165static int
Owen Taylor3473f882001-02-23 17:55:21 +00004166xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4167 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4168 if ((val == NULL) || (arg == NULL) ||
4169 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4170 return(0);
4171
4172 switch(val->type) {
4173 case XPATH_NUMBER:
4174 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4175 case XPATH_NODESET:
4176 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004177 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004178 case XPATH_STRING:
4179 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4180 case XPATH_BOOLEAN:
4181 valuePush(ctxt, arg);
4182 xmlXPathBooleanFunction(ctxt, 1);
4183 valuePush(ctxt, val);
4184 return(xmlXPathCompareValues(ctxt, inf, strict));
4185 default:
4186 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004187 }
4188 return(0);
4189}
4190
4191/**
4192 * xmlXPathEqualNodeSetString
4193 * @arg: the nodeset object argument
4194 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004195 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004196 *
4197 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4198 * If one object to be compared is a node-set and the other is a string,
4199 * then the comparison will be true if and only if there is a node in
4200 * the node-set such that the result of performing the comparison on the
4201 * string-value of the node and the other string is true.
4202 *
4203 * Returns 0 or 1 depending on the results of the test.
4204 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004205static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004206xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004207{
Owen Taylor3473f882001-02-23 17:55:21 +00004208 int i;
4209 xmlNodeSetPtr ns;
4210 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004211 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004212
4213 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004214 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4215 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004216 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004217 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004218 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004219 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004220 if (ns->nodeNr <= 0) {
4221 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004222 return(neq ^ 1);
4223 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004224 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004225 for (i = 0; i < ns->nodeNr; i++) {
4226 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4227 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4228 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4229 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004230 if (neq)
4231 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004232 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004233 } else if (neq) {
4234 if (str2 != NULL)
4235 xmlFree(str2);
4236 return (1);
4237 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004238 if (str2 != NULL)
4239 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004240 } else if (neq)
4241 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004242 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004243 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004244}
4245
4246/**
4247 * xmlXPathEqualNodeSetFloat
4248 * @arg: the nodeset object argument
4249 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004250 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004251 *
4252 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4253 * If one object to be compared is a node-set and the other is a number,
4254 * then the comparison will be true if and only if there is a node in
4255 * the node-set such that the result of performing the comparison on the
4256 * number to be compared and on the result of converting the string-value
4257 * of that node to a number using the number function is true.
4258 *
4259 * Returns 0 or 1 depending on the results of the test.
4260 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004261static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004262xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4263 xmlXPathObjectPtr arg, double f, int neq) {
4264 int i, ret=0;
4265 xmlNodeSetPtr ns;
4266 xmlChar *str2;
4267 xmlXPathObjectPtr val;
4268 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004269
4270 if ((arg == NULL) ||
4271 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4272 return(0);
4273
William M. Brack0c022ad2002-07-12 00:56:01 +00004274 ns = arg->nodesetval;
4275 if (ns != NULL) {
4276 for (i=0;i<ns->nodeNr;i++) {
4277 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4278 if (str2 != NULL) {
4279 valuePush(ctxt, xmlXPathNewString(str2));
4280 xmlFree(str2);
4281 xmlXPathNumberFunction(ctxt, 1);
4282 val = valuePop(ctxt);
4283 v = val->floatval;
4284 xmlXPathFreeObject(val);
4285 if (!xmlXPathIsNaN(v)) {
4286 if ((!neq) && (v==f)) {
4287 ret = 1;
4288 break;
4289 } else if ((neq) && (v!=f)) {
4290 ret = 1;
4291 break;
4292 }
4293 }
4294 }
4295 }
4296 }
4297
4298 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004299}
4300
4301
4302/**
4303 * xmlXPathEqualNodeSets
4304 * @arg1: first nodeset object argument
4305 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004306 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004307 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004308 * Implement the equal / not equal operation on XPath nodesets:
4309 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004310 * If both objects to be compared are node-sets, then the comparison
4311 * will be true if and only if there is a node in the first node-set and
4312 * a node in the second node-set such that the result of performing the
4313 * comparison on the string-values of the two nodes is true.
4314 *
4315 * (needless to say, this is a costly operation)
4316 *
4317 * Returns 0 or 1 depending on the results of the test.
4318 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004319static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004320xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004321 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004322 unsigned int *hashs1;
4323 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004324 xmlChar **values1;
4325 xmlChar **values2;
4326 int ret = 0;
4327 xmlNodeSetPtr ns1;
4328 xmlNodeSetPtr ns2;
4329
4330 if ((arg1 == NULL) ||
4331 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4332 return(0);
4333 if ((arg2 == NULL) ||
4334 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4335 return(0);
4336
4337 ns1 = arg1->nodesetval;
4338 ns2 = arg2->nodesetval;
4339
Daniel Veillard911f49a2001-04-07 15:39:35 +00004340 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004341 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004342 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004343 return(0);
4344
4345 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004346 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004347 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004348 if (neq == 0)
4349 for (i = 0;i < ns1->nodeNr;i++)
4350 for (j = 0;j < ns2->nodeNr;j++)
4351 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4352 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004353
4354 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4355 if (values1 == NULL)
4356 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004357 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4358 if (hashs1 == NULL) {
4359 xmlFree(values1);
4360 return(0);
4361 }
Owen Taylor3473f882001-02-23 17:55:21 +00004362 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4363 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4364 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004365 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004366 xmlFree(values1);
4367 return(0);
4368 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004369 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4370 if (hashs2 == NULL) {
4371 xmlFree(hashs1);
4372 xmlFree(values1);
4373 xmlFree(values2);
4374 return(0);
4375 }
Owen Taylor3473f882001-02-23 17:55:21 +00004376 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4377 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004378 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004379 for (j = 0;j < ns2->nodeNr;j++) {
4380 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004381 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004382 if (hashs1[i] != hashs2[j]) {
4383 if (neq) {
4384 ret = 1;
4385 break;
4386 }
4387 }
4388 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004389 if (values1[i] == NULL)
4390 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4391 if (values2[j] == NULL)
4392 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004393 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004394 if (ret)
4395 break;
4396 }
Owen Taylor3473f882001-02-23 17:55:21 +00004397 }
4398 if (ret)
4399 break;
4400 }
4401 for (i = 0;i < ns1->nodeNr;i++)
4402 if (values1[i] != NULL)
4403 xmlFree(values1[i]);
4404 for (j = 0;j < ns2->nodeNr;j++)
4405 if (values2[j] != NULL)
4406 xmlFree(values2[j]);
4407 xmlFree(values1);
4408 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004409 xmlFree(hashs1);
4410 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004411 return(ret);
4412}
4413
William M. Brack0c022ad2002-07-12 00:56:01 +00004414static int
4415xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4416 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004417 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004418 /*
4419 *At this point we are assured neither arg1 nor arg2
4420 *is a nodeset, so we can just pick the appropriate routine.
4421 */
Owen Taylor3473f882001-02-23 17:55:21 +00004422 switch (arg1->type) {
4423 case XPATH_UNDEFINED:
4424#ifdef DEBUG_EXPR
4425 xmlGenericError(xmlGenericErrorContext,
4426 "Equal: undefined\n");
4427#endif
4428 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004429 case XPATH_BOOLEAN:
4430 switch (arg2->type) {
4431 case XPATH_UNDEFINED:
4432#ifdef DEBUG_EXPR
4433 xmlGenericError(xmlGenericErrorContext,
4434 "Equal: undefined\n");
4435#endif
4436 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004437 case XPATH_BOOLEAN:
4438#ifdef DEBUG_EXPR
4439 xmlGenericError(xmlGenericErrorContext,
4440 "Equal: %d boolean %d \n",
4441 arg1->boolval, arg2->boolval);
4442#endif
4443 ret = (arg1->boolval == arg2->boolval);
4444 break;
4445 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004446 ret = (arg1->boolval ==
4447 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004448 break;
4449 case XPATH_STRING:
4450 if ((arg2->stringval == NULL) ||
4451 (arg2->stringval[0] == 0)) ret = 0;
4452 else
4453 ret = 1;
4454 ret = (arg1->boolval == ret);
4455 break;
4456 case XPATH_USERS:
4457 case XPATH_POINT:
4458 case XPATH_RANGE:
4459 case XPATH_LOCATIONSET:
4460 TODO
4461 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004462 case XPATH_NODESET:
4463 case XPATH_XSLT_TREE:
4464 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004465 }
4466 break;
4467 case XPATH_NUMBER:
4468 switch (arg2->type) {
4469 case XPATH_UNDEFINED:
4470#ifdef DEBUG_EXPR
4471 xmlGenericError(xmlGenericErrorContext,
4472 "Equal: undefined\n");
4473#endif
4474 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004475 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004476 ret = (arg2->boolval==
4477 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004478 break;
4479 case XPATH_STRING:
4480 valuePush(ctxt, arg2);
4481 xmlXPathNumberFunction(ctxt, 1);
4482 arg2 = valuePop(ctxt);
4483 /* no break on purpose */
4484 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004485 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004486 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4487 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004488 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4489 if (xmlXPathIsInf(arg2->floatval) == 1)
4490 ret = 1;
4491 else
4492 ret = 0;
4493 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4494 if (xmlXPathIsInf(arg2->floatval) == -1)
4495 ret = 1;
4496 else
4497 ret = 0;
4498 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4499 if (xmlXPathIsInf(arg1->floatval) == 1)
4500 ret = 1;
4501 else
4502 ret = 0;
4503 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4504 if (xmlXPathIsInf(arg1->floatval) == -1)
4505 ret = 1;
4506 else
4507 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004508 } else {
4509 ret = (arg1->floatval == arg2->floatval);
4510 }
Owen Taylor3473f882001-02-23 17:55:21 +00004511 break;
4512 case XPATH_USERS:
4513 case XPATH_POINT:
4514 case XPATH_RANGE:
4515 case XPATH_LOCATIONSET:
4516 TODO
4517 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004518 case XPATH_NODESET:
4519 case XPATH_XSLT_TREE:
4520 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004521 }
4522 break;
4523 case XPATH_STRING:
4524 switch (arg2->type) {
4525 case XPATH_UNDEFINED:
4526#ifdef DEBUG_EXPR
4527 xmlGenericError(xmlGenericErrorContext,
4528 "Equal: undefined\n");
4529#endif
4530 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004531 case XPATH_BOOLEAN:
4532 if ((arg1->stringval == NULL) ||
4533 (arg1->stringval[0] == 0)) ret = 0;
4534 else
4535 ret = 1;
4536 ret = (arg2->boolval == ret);
4537 break;
4538 case XPATH_STRING:
4539 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4540 break;
4541 case XPATH_NUMBER:
4542 valuePush(ctxt, arg1);
4543 xmlXPathNumberFunction(ctxt, 1);
4544 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004545 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004546 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4547 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004548 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4549 if (xmlXPathIsInf(arg2->floatval) == 1)
4550 ret = 1;
4551 else
4552 ret = 0;
4553 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4554 if (xmlXPathIsInf(arg2->floatval) == -1)
4555 ret = 1;
4556 else
4557 ret = 0;
4558 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4559 if (xmlXPathIsInf(arg1->floatval) == 1)
4560 ret = 1;
4561 else
4562 ret = 0;
4563 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4564 if (xmlXPathIsInf(arg1->floatval) == -1)
4565 ret = 1;
4566 else
4567 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004568 } else {
4569 ret = (arg1->floatval == arg2->floatval);
4570 }
Owen Taylor3473f882001-02-23 17:55:21 +00004571 break;
4572 case XPATH_USERS:
4573 case XPATH_POINT:
4574 case XPATH_RANGE:
4575 case XPATH_LOCATIONSET:
4576 TODO
4577 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004578 case XPATH_NODESET:
4579 case XPATH_XSLT_TREE:
4580 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004581 }
4582 break;
4583 case XPATH_USERS:
4584 case XPATH_POINT:
4585 case XPATH_RANGE:
4586 case XPATH_LOCATIONSET:
4587 TODO
4588 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004589 case XPATH_NODESET:
4590 case XPATH_XSLT_TREE:
4591 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004592 }
4593 xmlXPathFreeObject(arg1);
4594 xmlXPathFreeObject(arg2);
4595 return(ret);
4596}
4597
William M. Brack0c022ad2002-07-12 00:56:01 +00004598/**
4599 * xmlXPathEqualValues:
4600 * @ctxt: the XPath Parser context
4601 *
4602 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4603 *
4604 * Returns 0 or 1 depending on the results of the test.
4605 */
4606int
4607xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4608 xmlXPathObjectPtr arg1, arg2, argtmp;
4609 int ret = 0;
4610
4611 arg2 = valuePop(ctxt);
4612 arg1 = valuePop(ctxt);
4613 if ((arg1 == NULL) || (arg2 == NULL)) {
4614 if (arg1 != NULL)
4615 xmlXPathFreeObject(arg1);
4616 else
4617 xmlXPathFreeObject(arg2);
4618 XP_ERROR0(XPATH_INVALID_OPERAND);
4619 }
4620
4621 if (arg1 == arg2) {
4622#ifdef DEBUG_EXPR
4623 xmlGenericError(xmlGenericErrorContext,
4624 "Equal: by pointer\n");
4625#endif
4626 return(1);
4627 }
4628
4629 /*
4630 *If either argument is a nodeset, it's a 'special case'
4631 */
4632 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4633 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4634 /*
4635 *Hack it to assure arg1 is the nodeset
4636 */
4637 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4638 argtmp = arg2;
4639 arg2 = arg1;
4640 arg1 = argtmp;
4641 }
4642 switch (arg2->type) {
4643 case XPATH_UNDEFINED:
4644#ifdef DEBUG_EXPR
4645 xmlGenericError(xmlGenericErrorContext,
4646 "Equal: undefined\n");
4647#endif
4648 break;
4649 case XPATH_NODESET:
4650 case XPATH_XSLT_TREE:
4651 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4652 break;
4653 case XPATH_BOOLEAN:
4654 if ((arg1->nodesetval == NULL) ||
4655 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4656 else
4657 ret = 1;
4658 ret = (ret == arg2->boolval);
4659 break;
4660 case XPATH_NUMBER:
4661 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4662 break;
4663 case XPATH_STRING:
4664 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4665 break;
4666 case XPATH_USERS:
4667 case XPATH_POINT:
4668 case XPATH_RANGE:
4669 case XPATH_LOCATIONSET:
4670 TODO
4671 break;
4672 }
4673 xmlXPathFreeObject(arg1);
4674 xmlXPathFreeObject(arg2);
4675 return(ret);
4676 }
4677
4678 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4679}
4680
4681/**
4682 * xmlXPathNotEqualValues:
4683 * @ctxt: the XPath Parser context
4684 *
4685 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4686 *
4687 * Returns 0 or 1 depending on the results of the test.
4688 */
4689int
4690xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4691 xmlXPathObjectPtr arg1, arg2, argtmp;
4692 int ret = 0;
4693
4694 arg2 = valuePop(ctxt);
4695 arg1 = valuePop(ctxt);
4696 if ((arg1 == NULL) || (arg2 == NULL)) {
4697 if (arg1 != NULL)
4698 xmlXPathFreeObject(arg1);
4699 else
4700 xmlXPathFreeObject(arg2);
4701 XP_ERROR0(XPATH_INVALID_OPERAND);
4702 }
4703
4704 if (arg1 == arg2) {
4705#ifdef DEBUG_EXPR
4706 xmlGenericError(xmlGenericErrorContext,
4707 "NotEqual: by pointer\n");
4708#endif
4709 return(0);
4710 }
4711
4712 /*
4713 *If either argument is a nodeset, it's a 'special case'
4714 */
4715 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4716 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4717 /*
4718 *Hack it to assure arg1 is the nodeset
4719 */
4720 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4721 argtmp = arg2;
4722 arg2 = arg1;
4723 arg1 = argtmp;
4724 }
4725 switch (arg2->type) {
4726 case XPATH_UNDEFINED:
4727#ifdef DEBUG_EXPR
4728 xmlGenericError(xmlGenericErrorContext,
4729 "NotEqual: undefined\n");
4730#endif
4731 break;
4732 case XPATH_NODESET:
4733 case XPATH_XSLT_TREE:
4734 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4735 break;
4736 case XPATH_BOOLEAN:
4737 if ((arg1->nodesetval == NULL) ||
4738 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4739 else
4740 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004741 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004742 break;
4743 case XPATH_NUMBER:
4744 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4745 break;
4746 case XPATH_STRING:
4747 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4748 break;
4749 case XPATH_USERS:
4750 case XPATH_POINT:
4751 case XPATH_RANGE:
4752 case XPATH_LOCATIONSET:
4753 TODO
4754 break;
4755 }
4756 xmlXPathFreeObject(arg1);
4757 xmlXPathFreeObject(arg2);
4758 return(ret);
4759 }
4760
4761 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4762}
Owen Taylor3473f882001-02-23 17:55:21 +00004763
4764/**
4765 * xmlXPathCompareValues:
4766 * @ctxt: the XPath Parser context
4767 * @inf: less than (1) or greater than (0)
4768 * @strict: is the comparison strict
4769 *
4770 * Implement the compare operation on XPath objects:
4771 * @arg1 < @arg2 (1, 1, ...
4772 * @arg1 <= @arg2 (1, 0, ...
4773 * @arg1 > @arg2 (0, 1, ...
4774 * @arg1 >= @arg2 (0, 0, ...
4775 *
4776 * When neither object to be compared is a node-set and the operator is
4777 * <=, <, >=, >, then the objects are compared by converted both objects
4778 * to numbers and comparing the numbers according to IEEE 754. The <
4779 * comparison will be true if and only if the first number is less than the
4780 * second number. The <= comparison will be true if and only if the first
4781 * number is less than or equal to the second number. The > comparison
4782 * will be true if and only if the first number is greater than the second
4783 * number. The >= comparison will be true if and only if the first number
4784 * is greater than or equal to the second number.
4785 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004786 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004787 */
4788int
4789xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004790 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004791 xmlXPathObjectPtr arg1, arg2;
4792
William M. Brack0c022ad2002-07-12 00:56:01 +00004793 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004794 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004795 if ((arg1 == NULL) || (arg2 == NULL)) {
4796 if (arg1 != NULL)
4797 xmlXPathFreeObject(arg1);
4798 else
4799 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004800 XP_ERROR0(XPATH_INVALID_OPERAND);
4801 }
4802
William M. Brack0c022ad2002-07-12 00:56:01 +00004803 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4804 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4805 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4806 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004807 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004808 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004809 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004810 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4811 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004812 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004813 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4814 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004815 }
4816 }
4817 return(ret);
4818 }
4819
4820 if (arg1->type != XPATH_NUMBER) {
4821 valuePush(ctxt, arg1);
4822 xmlXPathNumberFunction(ctxt, 1);
4823 arg1 = valuePop(ctxt);
4824 }
4825 if (arg1->type != XPATH_NUMBER) {
4826 xmlXPathFreeObject(arg1);
4827 xmlXPathFreeObject(arg2);
4828 XP_ERROR0(XPATH_INVALID_OPERAND);
4829 }
4830 if (arg2->type != XPATH_NUMBER) {
4831 valuePush(ctxt, arg2);
4832 xmlXPathNumberFunction(ctxt, 1);
4833 arg2 = valuePop(ctxt);
4834 }
4835 if (arg2->type != XPATH_NUMBER) {
4836 xmlXPathFreeObject(arg1);
4837 xmlXPathFreeObject(arg2);
4838 XP_ERROR0(XPATH_INVALID_OPERAND);
4839 }
4840 /*
4841 * Add tests for infinity and nan
4842 * => feedback on 3.4 for Inf and NaN
4843 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004844 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004845 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004846 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004847 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004848 arg1i=xmlXPathIsInf(arg1->floatval);
4849 arg2i=xmlXPathIsInf(arg2->floatval);
4850 if (inf && strict) {
4851 if ((arg1i == -1 && arg2i != -1) ||
4852 (arg2i == 1 && arg1i != 1)) {
4853 ret = 1;
4854 } else if (arg1i == 0 && arg2i == 0) {
4855 ret = (arg1->floatval < arg2->floatval);
4856 } else {
4857 ret = 0;
4858 }
4859 }
4860 else if (inf && !strict) {
4861 if (arg1i == -1 || arg2i == 1) {
4862 ret = 1;
4863 } else if (arg1i == 0 && arg2i == 0) {
4864 ret = (arg1->floatval <= arg2->floatval);
4865 } else {
4866 ret = 0;
4867 }
4868 }
4869 else if (!inf && strict) {
4870 if ((arg1i == 1 && arg2i != 1) ||
4871 (arg2i == -1 && arg1i != -1)) {
4872 ret = 1;
4873 } else if (arg1i == 0 && arg2i == 0) {
4874 ret = (arg1->floatval > arg2->floatval);
4875 } else {
4876 ret = 0;
4877 }
4878 }
4879 else if (!inf && !strict) {
4880 if (arg1i == 1 || arg2i == -1) {
4881 ret = 1;
4882 } else if (arg1i == 0 && arg2i == 0) {
4883 ret = (arg1->floatval >= arg2->floatval);
4884 } else {
4885 ret = 0;
4886 }
4887 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004888 }
Owen Taylor3473f882001-02-23 17:55:21 +00004889 xmlXPathFreeObject(arg1);
4890 xmlXPathFreeObject(arg2);
4891 return(ret);
4892}
4893
4894/**
4895 * xmlXPathValueFlipSign:
4896 * @ctxt: the XPath Parser context
4897 *
4898 * Implement the unary - operation on an XPath object
4899 * The numeric operators convert their operands to numbers as if
4900 * by calling the number function.
4901 */
4902void
4903xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004904 CAST_TO_NUMBER;
4905 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004906 if (xmlXPathIsNaN(ctxt->value->floatval))
4907 ctxt->value->floatval=xmlXPathNAN;
4908 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4909 ctxt->value->floatval=xmlXPathNINF;
4910 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4911 ctxt->value->floatval=xmlXPathPINF;
4912 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004913 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4914 ctxt->value->floatval = xmlXPathNZERO;
4915 else
4916 ctxt->value->floatval = 0;
4917 }
4918 else
4919 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004920}
4921
4922/**
4923 * xmlXPathAddValues:
4924 * @ctxt: the XPath Parser context
4925 *
4926 * Implement the add operation on XPath objects:
4927 * The numeric operators convert their operands to numbers as if
4928 * by calling the number function.
4929 */
4930void
4931xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4932 xmlXPathObjectPtr arg;
4933 double val;
4934
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004935 arg = valuePop(ctxt);
4936 if (arg == NULL)
4937 XP_ERROR(XPATH_INVALID_OPERAND);
4938 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004939 xmlXPathFreeObject(arg);
4940
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004941 CAST_TO_NUMBER;
4942 CHECK_TYPE(XPATH_NUMBER);
4943 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004944}
4945
4946/**
4947 * xmlXPathSubValues:
4948 * @ctxt: the XPath Parser context
4949 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004950 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004951 * The numeric operators convert their operands to numbers as if
4952 * by calling the number function.
4953 */
4954void
4955xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4956 xmlXPathObjectPtr arg;
4957 double val;
4958
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004959 arg = valuePop(ctxt);
4960 if (arg == NULL)
4961 XP_ERROR(XPATH_INVALID_OPERAND);
4962 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004963 xmlXPathFreeObject(arg);
4964
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004965 CAST_TO_NUMBER;
4966 CHECK_TYPE(XPATH_NUMBER);
4967 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004968}
4969
4970/**
4971 * xmlXPathMultValues:
4972 * @ctxt: the XPath Parser context
4973 *
4974 * Implement the multiply operation on XPath objects:
4975 * The numeric operators convert their operands to numbers as if
4976 * by calling the number function.
4977 */
4978void
4979xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4980 xmlXPathObjectPtr arg;
4981 double val;
4982
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004983 arg = valuePop(ctxt);
4984 if (arg == NULL)
4985 XP_ERROR(XPATH_INVALID_OPERAND);
4986 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004987 xmlXPathFreeObject(arg);
4988
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004989 CAST_TO_NUMBER;
4990 CHECK_TYPE(XPATH_NUMBER);
4991 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004992}
4993
4994/**
4995 * xmlXPathDivValues:
4996 * @ctxt: the XPath Parser context
4997 *
4998 * Implement the div operation on XPath objects @arg1 / @arg2:
4999 * The numeric operators convert their operands to numbers as if
5000 * by calling the number function.
5001 */
5002void
5003xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5004 xmlXPathObjectPtr arg;
5005 double val;
5006
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005007 arg = valuePop(ctxt);
5008 if (arg == NULL)
5009 XP_ERROR(XPATH_INVALID_OPERAND);
5010 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005011 xmlXPathFreeObject(arg);
5012
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005013 CAST_TO_NUMBER;
5014 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005015 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5016 ctxt->value->floatval = xmlXPathNAN;
5017 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005018 if (ctxt->value->floatval == 0)
5019 ctxt->value->floatval = xmlXPathNAN;
5020 else if (ctxt->value->floatval > 0)
5021 ctxt->value->floatval = xmlXPathNINF;
5022 else if (ctxt->value->floatval < 0)
5023 ctxt->value->floatval = xmlXPathPINF;
5024 }
5025 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005026 if (ctxt->value->floatval == 0)
5027 ctxt->value->floatval = xmlXPathNAN;
5028 else if (ctxt->value->floatval > 0)
5029 ctxt->value->floatval = xmlXPathPINF;
5030 else if (ctxt->value->floatval < 0)
5031 ctxt->value->floatval = xmlXPathNINF;
5032 } else
5033 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005034}
5035
5036/**
5037 * xmlXPathModValues:
5038 * @ctxt: the XPath Parser context
5039 *
5040 * Implement the mod operation on XPath objects: @arg1 / @arg2
5041 * The numeric operators convert their operands to numbers as if
5042 * by calling the number function.
5043 */
5044void
5045xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5046 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005047 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005048
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005049 arg = valuePop(ctxt);
5050 if (arg == NULL)
5051 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005052 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005053 xmlXPathFreeObject(arg);
5054
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005055 CAST_TO_NUMBER;
5056 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005057 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005058 if (arg2 == 0)
5059 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005060 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005061 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005062 }
Owen Taylor3473f882001-02-23 17:55:21 +00005063}
5064
5065/************************************************************************
5066 * *
5067 * The traversal functions *
5068 * *
5069 ************************************************************************/
5070
Owen Taylor3473f882001-02-23 17:55:21 +00005071/*
5072 * A traversal function enumerates nodes along an axis.
5073 * Initially it must be called with NULL, and it indicates
5074 * termination on the axis by returning NULL.
5075 */
5076typedef xmlNodePtr (*xmlXPathTraversalFunction)
5077 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5078
5079/**
5080 * xmlXPathNextSelf:
5081 * @ctxt: the XPath Parser context
5082 * @cur: the current node in the traversal
5083 *
5084 * Traversal function for the "self" direction
5085 * The self axis contains just the context node itself
5086 *
5087 * Returns the next element following that axis
5088 */
5089xmlNodePtr
5090xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5091 if (cur == NULL)
5092 return(ctxt->context->node);
5093 return(NULL);
5094}
5095
5096/**
5097 * xmlXPathNextChild:
5098 * @ctxt: the XPath Parser context
5099 * @cur: the current node in the traversal
5100 *
5101 * Traversal function for the "child" direction
5102 * The child axis contains the children of the context node in document order.
5103 *
5104 * Returns the next element following that axis
5105 */
5106xmlNodePtr
5107xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5108 if (cur == NULL) {
5109 if (ctxt->context->node == NULL) return(NULL);
5110 switch (ctxt->context->node->type) {
5111 case XML_ELEMENT_NODE:
5112 case XML_TEXT_NODE:
5113 case XML_CDATA_SECTION_NODE:
5114 case XML_ENTITY_REF_NODE:
5115 case XML_ENTITY_NODE:
5116 case XML_PI_NODE:
5117 case XML_COMMENT_NODE:
5118 case XML_NOTATION_NODE:
5119 case XML_DTD_NODE:
5120 return(ctxt->context->node->children);
5121 case XML_DOCUMENT_NODE:
5122 case XML_DOCUMENT_TYPE_NODE:
5123 case XML_DOCUMENT_FRAG_NODE:
5124 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005125#ifdef LIBXML_DOCB_ENABLED
5126 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005127#endif
5128 return(((xmlDocPtr) ctxt->context->node)->children);
5129 case XML_ELEMENT_DECL:
5130 case XML_ATTRIBUTE_DECL:
5131 case XML_ENTITY_DECL:
5132 case XML_ATTRIBUTE_NODE:
5133 case XML_NAMESPACE_DECL:
5134 case XML_XINCLUDE_START:
5135 case XML_XINCLUDE_END:
5136 return(NULL);
5137 }
5138 return(NULL);
5139 }
5140 if ((cur->type == XML_DOCUMENT_NODE) ||
5141 (cur->type == XML_HTML_DOCUMENT_NODE))
5142 return(NULL);
5143 return(cur->next);
5144}
5145
5146/**
5147 * xmlXPathNextDescendant:
5148 * @ctxt: the XPath Parser context
5149 * @cur: the current node in the traversal
5150 *
5151 * Traversal function for the "descendant" direction
5152 * the descendant axis contains the descendants of the context node in document
5153 * order; a descendant is a child or a child of a child and so on.
5154 *
5155 * Returns the next element following that axis
5156 */
5157xmlNodePtr
5158xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5159 if (cur == NULL) {
5160 if (ctxt->context->node == NULL)
5161 return(NULL);
5162 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5163 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5164 return(NULL);
5165
5166 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5167 return(ctxt->context->doc->children);
5168 return(ctxt->context->node->children);
5169 }
5170
Daniel Veillard567e1b42001-08-01 15:53:47 +00005171 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005172 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00005173 return(cur->children);
5174 }
5175
5176 if (cur == ctxt->context->node) return(NULL);
5177
Owen Taylor3473f882001-02-23 17:55:21 +00005178 if (cur->next != NULL) return(cur->next);
5179
5180 do {
5181 cur = cur->parent;
5182 if (cur == NULL) return(NULL);
5183 if (cur == ctxt->context->node) return(NULL);
5184 if (cur->next != NULL) {
5185 cur = cur->next;
5186 return(cur);
5187 }
5188 } while (cur != NULL);
5189 return(cur);
5190}
5191
5192/**
5193 * xmlXPathNextDescendantOrSelf:
5194 * @ctxt: the XPath Parser context
5195 * @cur: the current node in the traversal
5196 *
5197 * Traversal function for the "descendant-or-self" direction
5198 * the descendant-or-self axis contains the context node and the descendants
5199 * of the context node in document order; thus the context node is the first
5200 * node on the axis, and the first child of the context node is the second node
5201 * on the axis
5202 *
5203 * Returns the next element following that axis
5204 */
5205xmlNodePtr
5206xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5207 if (cur == NULL) {
5208 if (ctxt->context->node == NULL)
5209 return(NULL);
5210 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5211 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5212 return(NULL);
5213 return(ctxt->context->node);
5214 }
5215
5216 return(xmlXPathNextDescendant(ctxt, cur));
5217}
5218
5219/**
5220 * xmlXPathNextParent:
5221 * @ctxt: the XPath Parser context
5222 * @cur: the current node in the traversal
5223 *
5224 * Traversal function for the "parent" direction
5225 * The parent axis contains the parent of the context node, if there is one.
5226 *
5227 * Returns the next element following that axis
5228 */
5229xmlNodePtr
5230xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5231 /*
5232 * the parent of an attribute or namespace node is the element
5233 * to which the attribute or namespace node is attached
5234 * Namespace handling !!!
5235 */
5236 if (cur == NULL) {
5237 if (ctxt->context->node == NULL) return(NULL);
5238 switch (ctxt->context->node->type) {
5239 case XML_ELEMENT_NODE:
5240 case XML_TEXT_NODE:
5241 case XML_CDATA_SECTION_NODE:
5242 case XML_ENTITY_REF_NODE:
5243 case XML_ENTITY_NODE:
5244 case XML_PI_NODE:
5245 case XML_COMMENT_NODE:
5246 case XML_NOTATION_NODE:
5247 case XML_DTD_NODE:
5248 case XML_ELEMENT_DECL:
5249 case XML_ATTRIBUTE_DECL:
5250 case XML_XINCLUDE_START:
5251 case XML_XINCLUDE_END:
5252 case XML_ENTITY_DECL:
5253 if (ctxt->context->node->parent == NULL)
5254 return((xmlNodePtr) ctxt->context->doc);
5255 return(ctxt->context->node->parent);
5256 case XML_ATTRIBUTE_NODE: {
5257 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5258
5259 return(att->parent);
5260 }
5261 case XML_DOCUMENT_NODE:
5262 case XML_DOCUMENT_TYPE_NODE:
5263 case XML_DOCUMENT_FRAG_NODE:
5264 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005265#ifdef LIBXML_DOCB_ENABLED
5266 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005267#endif
5268 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005269 case XML_NAMESPACE_DECL: {
5270 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5271
5272 if ((ns->next != NULL) &&
5273 (ns->next->type != XML_NAMESPACE_DECL))
5274 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005275 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005276 }
Owen Taylor3473f882001-02-23 17:55:21 +00005277 }
5278 }
5279 return(NULL);
5280}
5281
5282/**
5283 * xmlXPathNextAncestor:
5284 * @ctxt: the XPath Parser context
5285 * @cur: the current node in the traversal
5286 *
5287 * Traversal function for the "ancestor" direction
5288 * the ancestor axis contains the ancestors of the context node; the ancestors
5289 * of the context node consist of the parent of context node and the parent's
5290 * parent and so on; the nodes are ordered in reverse document order; thus the
5291 * parent is the first node on the axis, and the parent's parent is the second
5292 * node on the axis
5293 *
5294 * Returns the next element following that axis
5295 */
5296xmlNodePtr
5297xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5298 /*
5299 * the parent of an attribute or namespace node is the element
5300 * to which the attribute or namespace node is attached
5301 * !!!!!!!!!!!!!
5302 */
5303 if (cur == NULL) {
5304 if (ctxt->context->node == NULL) return(NULL);
5305 switch (ctxt->context->node->type) {
5306 case XML_ELEMENT_NODE:
5307 case XML_TEXT_NODE:
5308 case XML_CDATA_SECTION_NODE:
5309 case XML_ENTITY_REF_NODE:
5310 case XML_ENTITY_NODE:
5311 case XML_PI_NODE:
5312 case XML_COMMENT_NODE:
5313 case XML_DTD_NODE:
5314 case XML_ELEMENT_DECL:
5315 case XML_ATTRIBUTE_DECL:
5316 case XML_ENTITY_DECL:
5317 case XML_NOTATION_NODE:
5318 case XML_XINCLUDE_START:
5319 case XML_XINCLUDE_END:
5320 if (ctxt->context->node->parent == NULL)
5321 return((xmlNodePtr) ctxt->context->doc);
5322 return(ctxt->context->node->parent);
5323 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005324 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005325
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005326 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005327 }
5328 case XML_DOCUMENT_NODE:
5329 case XML_DOCUMENT_TYPE_NODE:
5330 case XML_DOCUMENT_FRAG_NODE:
5331 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005332#ifdef LIBXML_DOCB_ENABLED
5333 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005334#endif
5335 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005336 case XML_NAMESPACE_DECL: {
5337 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5338
5339 if ((ns->next != NULL) &&
5340 (ns->next->type != XML_NAMESPACE_DECL))
5341 return((xmlNodePtr) ns->next);
5342 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005343 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005344 }
Owen Taylor3473f882001-02-23 17:55:21 +00005345 }
5346 return(NULL);
5347 }
5348 if (cur == ctxt->context->doc->children)
5349 return((xmlNodePtr) ctxt->context->doc);
5350 if (cur == (xmlNodePtr) ctxt->context->doc)
5351 return(NULL);
5352 switch (cur->type) {
5353 case XML_ELEMENT_NODE:
5354 case XML_TEXT_NODE:
5355 case XML_CDATA_SECTION_NODE:
5356 case XML_ENTITY_REF_NODE:
5357 case XML_ENTITY_NODE:
5358 case XML_PI_NODE:
5359 case XML_COMMENT_NODE:
5360 case XML_NOTATION_NODE:
5361 case XML_DTD_NODE:
5362 case XML_ELEMENT_DECL:
5363 case XML_ATTRIBUTE_DECL:
5364 case XML_ENTITY_DECL:
5365 case XML_XINCLUDE_START:
5366 case XML_XINCLUDE_END:
5367 return(cur->parent);
5368 case XML_ATTRIBUTE_NODE: {
5369 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5370
5371 return(att->parent);
5372 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005373 case XML_NAMESPACE_DECL: {
5374 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5375
5376 if ((ns->next != NULL) &&
5377 (ns->next->type != XML_NAMESPACE_DECL))
5378 return((xmlNodePtr) ns->next);
5379 /* Bad, how did that namespace ended-up there ? */
5380 return(NULL);
5381 }
Owen Taylor3473f882001-02-23 17:55:21 +00005382 case XML_DOCUMENT_NODE:
5383 case XML_DOCUMENT_TYPE_NODE:
5384 case XML_DOCUMENT_FRAG_NODE:
5385 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005386#ifdef LIBXML_DOCB_ENABLED
5387 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005388#endif
5389 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005390 }
5391 return(NULL);
5392}
5393
5394/**
5395 * xmlXPathNextAncestorOrSelf:
5396 * @ctxt: the XPath Parser context
5397 * @cur: the current node in the traversal
5398 *
5399 * Traversal function for the "ancestor-or-self" direction
5400 * he ancestor-or-self axis contains the context node and ancestors of
5401 * the context node in reverse document order; thus the context node is
5402 * the first node on the axis, and the context node's parent the second;
5403 * parent here is defined the same as with the parent axis.
5404 *
5405 * Returns the next element following that axis
5406 */
5407xmlNodePtr
5408xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5409 if (cur == NULL)
5410 return(ctxt->context->node);
5411 return(xmlXPathNextAncestor(ctxt, cur));
5412}
5413
5414/**
5415 * xmlXPathNextFollowingSibling:
5416 * @ctxt: the XPath Parser context
5417 * @cur: the current node in the traversal
5418 *
5419 * Traversal function for the "following-sibling" direction
5420 * The following-sibling axis contains the following siblings of the context
5421 * node in document order.
5422 *
5423 * Returns the next element following that axis
5424 */
5425xmlNodePtr
5426xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5427 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5428 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5429 return(NULL);
5430 if (cur == (xmlNodePtr) ctxt->context->doc)
5431 return(NULL);
5432 if (cur == NULL)
5433 return(ctxt->context->node->next);
5434 return(cur->next);
5435}
5436
5437/**
5438 * xmlXPathNextPrecedingSibling:
5439 * @ctxt: the XPath Parser context
5440 * @cur: the current node in the traversal
5441 *
5442 * Traversal function for the "preceding-sibling" direction
5443 * The preceding-sibling axis contains the preceding siblings of the context
5444 * node in reverse document order; the first preceding sibling is first on the
5445 * axis; the sibling preceding that node is the second on the axis and so on.
5446 *
5447 * Returns the next element following that axis
5448 */
5449xmlNodePtr
5450xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5451 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5452 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5453 return(NULL);
5454 if (cur == (xmlNodePtr) ctxt->context->doc)
5455 return(NULL);
5456 if (cur == NULL)
5457 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005458 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5459 cur = cur->prev;
5460 if (cur == NULL)
5461 return(ctxt->context->node->prev);
5462 }
Owen Taylor3473f882001-02-23 17:55:21 +00005463 return(cur->prev);
5464}
5465
5466/**
5467 * xmlXPathNextFollowing:
5468 * @ctxt: the XPath Parser context
5469 * @cur: the current node in the traversal
5470 *
5471 * Traversal function for the "following" direction
5472 * The following axis contains all nodes in the same document as the context
5473 * node that are after the context node in document order, excluding any
5474 * descendants and excluding attribute nodes and namespace nodes; the nodes
5475 * are ordered in document order
5476 *
5477 * Returns the next element following that axis
5478 */
5479xmlNodePtr
5480xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5481 if (cur != NULL && cur->children != NULL)
5482 return cur->children ;
5483 if (cur == NULL) cur = ctxt->context->node;
5484 if (cur == NULL) return(NULL) ; /* ERROR */
5485 if (cur->next != NULL) return(cur->next) ;
5486 do {
5487 cur = cur->parent;
5488 if (cur == NULL) return(NULL);
5489 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5490 if (cur->next != NULL) return(cur->next);
5491 } while (cur != NULL);
5492 return(cur);
5493}
5494
5495/*
5496 * xmlXPathIsAncestor:
5497 * @ancestor: the ancestor node
5498 * @node: the current node
5499 *
5500 * Check that @ancestor is a @node's ancestor
5501 *
5502 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5503 */
5504static int
5505xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5506 if ((ancestor == NULL) || (node == NULL)) return(0);
5507 /* nodes need to be in the same document */
5508 if (ancestor->doc != node->doc) return(0);
5509 /* avoid searching if ancestor or node is the root node */
5510 if (ancestor == (xmlNodePtr) node->doc) return(1);
5511 if (node == (xmlNodePtr) ancestor->doc) return(0);
5512 while (node->parent != NULL) {
5513 if (node->parent == ancestor)
5514 return(1);
5515 node = node->parent;
5516 }
5517 return(0);
5518}
5519
5520/**
5521 * xmlXPathNextPreceding:
5522 * @ctxt: the XPath Parser context
5523 * @cur: the current node in the traversal
5524 *
5525 * Traversal function for the "preceding" direction
5526 * the preceding axis contains all nodes in the same document as the context
5527 * node that are before the context node in document order, excluding any
5528 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5529 * ordered in reverse document order
5530 *
5531 * Returns the next element following that axis
5532 */
5533xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005534xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5535{
Owen Taylor3473f882001-02-23 17:55:21 +00005536 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005537 cur = ctxt->context->node;
5538 if (cur == NULL)
5539 return (NULL);
5540 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5541 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005542 do {
5543 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005544 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5545 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005546 }
5547
5548 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005549 if (cur == NULL)
5550 return (NULL);
5551 if (cur == ctxt->context->doc->children)
5552 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005553 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005554 return (cur);
5555}
5556
5557/**
5558 * xmlXPathNextPrecedingInternal:
5559 * @ctxt: the XPath Parser context
5560 * @cur: the current node in the traversal
5561 *
5562 * Traversal function for the "preceding" direction
5563 * the preceding axis contains all nodes in the same document as the context
5564 * node that are before the context node in document order, excluding any
5565 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5566 * ordered in reverse document order
5567 * This is a faster implementation but internal only since it requires a
5568 * state kept in the parser context: ctxt->ancestor.
5569 *
5570 * Returns the next element following that axis
5571 */
5572static xmlNodePtr
5573xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5574 xmlNodePtr cur)
5575{
5576 if (cur == NULL) {
5577 cur = ctxt->context->node;
5578 if (cur == NULL)
5579 return (NULL);
5580 ctxt->ancestor = cur->parent;
5581 }
5582 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5583 cur = cur->prev;
5584 while (cur->prev == NULL) {
5585 cur = cur->parent;
5586 if (cur == NULL)
5587 return (NULL);
5588 if (cur == ctxt->context->doc->children)
5589 return (NULL);
5590 if (cur != ctxt->ancestor)
5591 return (cur);
5592 ctxt->ancestor = cur->parent;
5593 }
5594 cur = cur->prev;
5595 while (cur->last != NULL)
5596 cur = cur->last;
5597 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005598}
5599
5600/**
5601 * xmlXPathNextNamespace:
5602 * @ctxt: the XPath Parser context
5603 * @cur: the current attribute in the traversal
5604 *
5605 * Traversal function for the "namespace" direction
5606 * the namespace axis contains the namespace nodes of the context node;
5607 * the order of nodes on this axis is implementation-defined; the axis will
5608 * be empty unless the context node is an element
5609 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005610 * We keep the XML namespace node at the end of the list.
5611 *
Owen Taylor3473f882001-02-23 17:55:21 +00005612 * Returns the next element following that axis
5613 */
5614xmlNodePtr
5615xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5616 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005617 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005618 if (ctxt->context->tmpNsList != NULL)
5619 xmlFree(ctxt->context->tmpNsList);
5620 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005621 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005622 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005623 if (ctxt->context->tmpNsList != NULL) {
5624 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5625 ctxt->context->tmpNsNr++;
5626 }
5627 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005628 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005629 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005630 if (ctxt->context->tmpNsNr > 0) {
5631 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5632 } else {
5633 if (ctxt->context->tmpNsList != NULL)
5634 xmlFree(ctxt->context->tmpNsList);
5635 ctxt->context->tmpNsList = NULL;
5636 return(NULL);
5637 }
Owen Taylor3473f882001-02-23 17:55:21 +00005638}
5639
5640/**
5641 * xmlXPathNextAttribute:
5642 * @ctxt: the XPath Parser context
5643 * @cur: the current attribute in the traversal
5644 *
5645 * Traversal function for the "attribute" direction
5646 * TODO: support DTD inherited default attributes
5647 *
5648 * Returns the next element following that axis
5649 */
5650xmlNodePtr
5651xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005652 if (ctxt->context->node == NULL)
5653 return(NULL);
5654 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5655 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005656 if (cur == NULL) {
5657 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5658 return(NULL);
5659 return((xmlNodePtr)ctxt->context->node->properties);
5660 }
5661 return((xmlNodePtr)cur->next);
5662}
5663
5664/************************************************************************
5665 * *
5666 * NodeTest Functions *
5667 * *
5668 ************************************************************************/
5669
Owen Taylor3473f882001-02-23 17:55:21 +00005670#define IS_FUNCTION 200
5671
Owen Taylor3473f882001-02-23 17:55:21 +00005672
5673/************************************************************************
5674 * *
5675 * Implicit tree core function library *
5676 * *
5677 ************************************************************************/
5678
5679/**
5680 * xmlXPathRoot:
5681 * @ctxt: the XPath Parser context
5682 *
5683 * Initialize the context to the root of the document
5684 */
5685void
5686xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5687 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5688 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5689}
5690
5691/************************************************************************
5692 * *
5693 * The explicit core function library *
5694 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5695 * *
5696 ************************************************************************/
5697
5698
5699/**
5700 * xmlXPathLastFunction:
5701 * @ctxt: the XPath Parser context
5702 * @nargs: the number of arguments
5703 *
5704 * Implement the last() XPath function
5705 * number last()
5706 * The last function returns the number of nodes in the context node list.
5707 */
5708void
5709xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5710 CHECK_ARITY(0);
5711 if (ctxt->context->contextSize >= 0) {
5712 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5713#ifdef DEBUG_EXPR
5714 xmlGenericError(xmlGenericErrorContext,
5715 "last() : %d\n", ctxt->context->contextSize);
5716#endif
5717 } else {
5718 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5719 }
5720}
5721
5722/**
5723 * xmlXPathPositionFunction:
5724 * @ctxt: the XPath Parser context
5725 * @nargs: the number of arguments
5726 *
5727 * Implement the position() XPath function
5728 * number position()
5729 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005730 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005731 * will be equal to last().
5732 */
5733void
5734xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5735 CHECK_ARITY(0);
5736 if (ctxt->context->proximityPosition >= 0) {
5737 valuePush(ctxt,
5738 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5739#ifdef DEBUG_EXPR
5740 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5741 ctxt->context->proximityPosition);
5742#endif
5743 } else {
5744 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5745 }
5746}
5747
5748/**
5749 * xmlXPathCountFunction:
5750 * @ctxt: the XPath Parser context
5751 * @nargs: the number of arguments
5752 *
5753 * Implement the count() XPath function
5754 * number count(node-set)
5755 */
5756void
5757xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5758 xmlXPathObjectPtr cur;
5759
5760 CHECK_ARITY(1);
5761 if ((ctxt->value == NULL) ||
5762 ((ctxt->value->type != XPATH_NODESET) &&
5763 (ctxt->value->type != XPATH_XSLT_TREE)))
5764 XP_ERROR(XPATH_INVALID_TYPE);
5765 cur = valuePop(ctxt);
5766
Daniel Veillard911f49a2001-04-07 15:39:35 +00005767 if ((cur == NULL) || (cur->nodesetval == NULL))
5768 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005769 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005770 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005771 } else {
5772 if ((cur->nodesetval->nodeNr != 1) ||
5773 (cur->nodesetval->nodeTab == NULL)) {
5774 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5775 } else {
5776 xmlNodePtr tmp;
5777 int i = 0;
5778
5779 tmp = cur->nodesetval->nodeTab[0];
5780 if (tmp != NULL) {
5781 tmp = tmp->children;
5782 while (tmp != NULL) {
5783 tmp = tmp->next;
5784 i++;
5785 }
5786 }
5787 valuePush(ctxt, xmlXPathNewFloat((double) i));
5788 }
5789 }
Owen Taylor3473f882001-02-23 17:55:21 +00005790 xmlXPathFreeObject(cur);
5791}
5792
5793/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005794 * xmlXPathGetElementsByIds:
5795 * @doc: the document
5796 * @ids: a whitespace separated list of IDs
5797 *
5798 * Selects elements by their unique ID.
5799 *
5800 * Returns a node-set of selected elements.
5801 */
5802static xmlNodeSetPtr
5803xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5804 xmlNodeSetPtr ret;
5805 const xmlChar *cur = ids;
5806 xmlChar *ID;
5807 xmlAttrPtr attr;
5808 xmlNodePtr elem = NULL;
5809
5810 ret = xmlXPathNodeSetCreate(NULL);
5811
5812 while (IS_BLANK(*cur)) cur++;
5813 while (*cur != 0) {
5814 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5815 (*cur == '.') || (*cur == '-') ||
5816 (*cur == '_') || (*cur == ':') ||
5817 (IS_COMBINING(*cur)) ||
5818 (IS_EXTENDER(*cur)))
5819 cur++;
5820
5821 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5822
5823 ID = xmlStrndup(ids, cur - ids);
5824 attr = xmlGetID(doc, ID);
5825 if (attr != NULL) {
5826 elem = attr->parent;
5827 xmlXPathNodeSetAdd(ret, elem);
5828 }
5829 if (ID != NULL)
5830 xmlFree(ID);
5831
5832 while (IS_BLANK(*cur)) cur++;
5833 ids = cur;
5834 }
5835 return(ret);
5836}
5837
5838/**
Owen Taylor3473f882001-02-23 17:55:21 +00005839 * xmlXPathIdFunction:
5840 * @ctxt: the XPath Parser context
5841 * @nargs: the number of arguments
5842 *
5843 * Implement the id() XPath function
5844 * node-set id(object)
5845 * The id function selects elements by their unique ID
5846 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5847 * then the result is the union of the result of applying id to the
5848 * string value of each of the nodes in the argument node-set. When the
5849 * argument to id is of any other type, the argument is converted to a
5850 * string as if by a call to the string function; the string is split
5851 * into a whitespace-separated list of tokens (whitespace is any sequence
5852 * of characters matching the production S); the result is a node-set
5853 * containing the elements in the same document as the context node that
5854 * have a unique ID equal to any of the tokens in the list.
5855 */
5856void
5857xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005858 xmlChar *tokens;
5859 xmlNodeSetPtr ret;
5860 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005861
5862 CHECK_ARITY(1);
5863 obj = valuePop(ctxt);
5864 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005865 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005866 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005867 int i;
5868
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005869 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005870
Daniel Veillard911f49a2001-04-07 15:39:35 +00005871 if (obj->nodesetval != NULL) {
5872 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005873 tokens =
5874 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5875 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5876 ret = xmlXPathNodeSetMerge(ret, ns);
5877 xmlXPathFreeNodeSet(ns);
5878 if (tokens != NULL)
5879 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005880 }
Owen Taylor3473f882001-02-23 17:55:21 +00005881 }
5882
5883 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005884 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005885 return;
5886 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005887 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005888
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005889 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5890 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005891
Owen Taylor3473f882001-02-23 17:55:21 +00005892 xmlXPathFreeObject(obj);
5893 return;
5894}
5895
5896/**
5897 * xmlXPathLocalNameFunction:
5898 * @ctxt: the XPath Parser context
5899 * @nargs: the number of arguments
5900 *
5901 * Implement the local-name() XPath function
5902 * string local-name(node-set?)
5903 * The local-name function returns a string containing the local part
5904 * of the name of the node in the argument node-set that is first in
5905 * document order. If the node-set is empty or the first node has no
5906 * name, an empty string is returned. If the argument is omitted it
5907 * defaults to the context node.
5908 */
5909void
5910xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5911 xmlXPathObjectPtr cur;
5912
5913 if (nargs == 0) {
5914 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5915 nargs = 1;
5916 }
5917
5918 CHECK_ARITY(1);
5919 if ((ctxt->value == NULL) ||
5920 ((ctxt->value->type != XPATH_NODESET) &&
5921 (ctxt->value->type != XPATH_XSLT_TREE)))
5922 XP_ERROR(XPATH_INVALID_TYPE);
5923 cur = valuePop(ctxt);
5924
Daniel Veillard911f49a2001-04-07 15:39:35 +00005925 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005926 valuePush(ctxt, xmlXPathNewCString(""));
5927 } else {
5928 int i = 0; /* Should be first in document order !!!!! */
5929 switch (cur->nodesetval->nodeTab[i]->type) {
5930 case XML_ELEMENT_NODE:
5931 case XML_ATTRIBUTE_NODE:
5932 case XML_PI_NODE:
5933 valuePush(ctxt,
5934 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5935 break;
5936 case XML_NAMESPACE_DECL:
5937 valuePush(ctxt, xmlXPathNewString(
5938 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5939 break;
5940 default:
5941 valuePush(ctxt, xmlXPathNewCString(""));
5942 }
5943 }
5944 xmlXPathFreeObject(cur);
5945}
5946
5947/**
5948 * xmlXPathNamespaceURIFunction:
5949 * @ctxt: the XPath Parser context
5950 * @nargs: the number of arguments
5951 *
5952 * Implement the namespace-uri() XPath function
5953 * string namespace-uri(node-set?)
5954 * The namespace-uri function returns a string containing the
5955 * namespace URI of the expanded name of the node in the argument
5956 * node-set that is first in document order. If the node-set is empty,
5957 * the first node has no name, or the expanded name has no namespace
5958 * URI, an empty string is returned. If the argument is omitted it
5959 * defaults to the context node.
5960 */
5961void
5962xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5963 xmlXPathObjectPtr cur;
5964
5965 if (nargs == 0) {
5966 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5967 nargs = 1;
5968 }
5969 CHECK_ARITY(1);
5970 if ((ctxt->value == NULL) ||
5971 ((ctxt->value->type != XPATH_NODESET) &&
5972 (ctxt->value->type != XPATH_XSLT_TREE)))
5973 XP_ERROR(XPATH_INVALID_TYPE);
5974 cur = valuePop(ctxt);
5975
Daniel Veillard911f49a2001-04-07 15:39:35 +00005976 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005977 valuePush(ctxt, xmlXPathNewCString(""));
5978 } else {
5979 int i = 0; /* Should be first in document order !!!!! */
5980 switch (cur->nodesetval->nodeTab[i]->type) {
5981 case XML_ELEMENT_NODE:
5982 case XML_ATTRIBUTE_NODE:
5983 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5984 valuePush(ctxt, xmlXPathNewCString(""));
5985 else
5986 valuePush(ctxt, xmlXPathNewString(
5987 cur->nodesetval->nodeTab[i]->ns->href));
5988 break;
5989 default:
5990 valuePush(ctxt, xmlXPathNewCString(""));
5991 }
5992 }
5993 xmlXPathFreeObject(cur);
5994}
5995
5996/**
5997 * xmlXPathNameFunction:
5998 * @ctxt: the XPath Parser context
5999 * @nargs: the number of arguments
6000 *
6001 * Implement the name() XPath function
6002 * string name(node-set?)
6003 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006004 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006005 * order. The QName must represent the name with respect to the namespace
6006 * declarations in effect on the node whose name is being represented.
6007 * Typically, this will be the form in which the name occurred in the XML
6008 * source. This need not be the case if there are namespace declarations
6009 * in effect on the node that associate multiple prefixes with the same
6010 * namespace. However, an implementation may include information about
6011 * the original prefix in its representation of nodes; in this case, an
6012 * implementation can ensure that the returned string is always the same
6013 * as the QName used in the XML source. If the argument it omitted it
6014 * defaults to the context node.
6015 * Libxml keep the original prefix so the "real qualified name" used is
6016 * returned.
6017 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006018static void
Daniel Veillard04383752001-07-08 14:27:15 +00006019xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6020{
Owen Taylor3473f882001-02-23 17:55:21 +00006021 xmlXPathObjectPtr cur;
6022
6023 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006024 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6025 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006026 }
6027
6028 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006029 if ((ctxt->value == NULL) ||
6030 ((ctxt->value->type != XPATH_NODESET) &&
6031 (ctxt->value->type != XPATH_XSLT_TREE)))
6032 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006033 cur = valuePop(ctxt);
6034
Daniel Veillard911f49a2001-04-07 15:39:35 +00006035 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006036 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006037 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006038 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006039
Daniel Veillard04383752001-07-08 14:27:15 +00006040 switch (cur->nodesetval->nodeTab[i]->type) {
6041 case XML_ELEMENT_NODE:
6042 case XML_ATTRIBUTE_NODE:
6043 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6044 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
6045 valuePush(ctxt,
6046 xmlXPathNewString(cur->nodesetval->
6047 nodeTab[i]->name));
6048
6049 else {
6050 char name[2000];
6051
6052 snprintf(name, sizeof(name), "%s:%s",
6053 (char *) cur->nodesetval->nodeTab[i]->ns->
6054 prefix,
6055 (char *) cur->nodesetval->nodeTab[i]->name);
6056 name[sizeof(name) - 1] = 0;
6057 valuePush(ctxt, xmlXPathNewCString(name));
6058 }
6059 break;
6060 default:
6061 valuePush(ctxt,
6062 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6063 xmlXPathLocalNameFunction(ctxt, 1);
6064 }
Owen Taylor3473f882001-02-23 17:55:21 +00006065 }
6066 xmlXPathFreeObject(cur);
6067}
6068
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006069
6070/**
Owen Taylor3473f882001-02-23 17:55:21 +00006071 * xmlXPathStringFunction:
6072 * @ctxt: the XPath Parser context
6073 * @nargs: the number of arguments
6074 *
6075 * Implement the string() XPath function
6076 * string string(object?)
6077 * he string function converts an object to a string as follows:
6078 * - A node-set is converted to a string by returning the value of
6079 * the node in the node-set that is first in document order.
6080 * If the node-set is empty, an empty string is returned.
6081 * - A number is converted to a string as follows
6082 * + NaN is converted to the string NaN
6083 * + positive zero is converted to the string 0
6084 * + negative zero is converted to the string 0
6085 * + positive infinity is converted to the string Infinity
6086 * + negative infinity is converted to the string -Infinity
6087 * + if the number is an integer, the number is represented in
6088 * decimal form as a Number with no decimal point and no leading
6089 * zeros, preceded by a minus sign (-) if the number is negative
6090 * + otherwise, the number is represented in decimal form as a
6091 * Number including a decimal point with at least one digit
6092 * before the decimal point and at least one digit after the
6093 * decimal point, preceded by a minus sign (-) if the number
6094 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006095 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006096 * before the decimal point; beyond the one required digit
6097 * after the decimal point there must be as many, but only as
6098 * many, more digits as are needed to uniquely distinguish the
6099 * number from all other IEEE 754 numeric values.
6100 * - The boolean false value is converted to the string false.
6101 * The boolean true value is converted to the string true.
6102 *
6103 * If the argument is omitted, it defaults to a node-set with the
6104 * context node as its only member.
6105 */
6106void
6107xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6108 xmlXPathObjectPtr cur;
6109
6110 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006111 valuePush(ctxt,
6112 xmlXPathWrapString(
6113 xmlXPathCastNodeToString(ctxt->context->node)));
6114 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006115 }
6116
6117 CHECK_ARITY(1);
6118 cur = valuePop(ctxt);
6119 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006120 cur = xmlXPathConvertString(cur);
6121 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006122}
6123
6124/**
6125 * xmlXPathStringLengthFunction:
6126 * @ctxt: the XPath Parser context
6127 * @nargs: the number of arguments
6128 *
6129 * Implement the string-length() XPath function
6130 * number string-length(string?)
6131 * The string-length returns the number of characters in the string
6132 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6133 * the context node converted to a string, in other words the value
6134 * of the context node.
6135 */
6136void
6137xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6138 xmlXPathObjectPtr cur;
6139
6140 if (nargs == 0) {
6141 if (ctxt->context->node == NULL) {
6142 valuePush(ctxt, xmlXPathNewFloat(0));
6143 } else {
6144 xmlChar *content;
6145
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006146 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006147 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006148 xmlFree(content);
6149 }
6150 return;
6151 }
6152 CHECK_ARITY(1);
6153 CAST_TO_STRING;
6154 CHECK_TYPE(XPATH_STRING);
6155 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006156 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006157 xmlXPathFreeObject(cur);
6158}
6159
6160/**
6161 * xmlXPathConcatFunction:
6162 * @ctxt: the XPath Parser context
6163 * @nargs: the number of arguments
6164 *
6165 * Implement the concat() XPath function
6166 * string concat(string, string, string*)
6167 * The concat function returns the concatenation of its arguments.
6168 */
6169void
6170xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6171 xmlXPathObjectPtr cur, newobj;
6172 xmlChar *tmp;
6173
6174 if (nargs < 2) {
6175 CHECK_ARITY(2);
6176 }
6177
6178 CAST_TO_STRING;
6179 cur = valuePop(ctxt);
6180 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6181 xmlXPathFreeObject(cur);
6182 return;
6183 }
6184 nargs--;
6185
6186 while (nargs > 0) {
6187 CAST_TO_STRING;
6188 newobj = valuePop(ctxt);
6189 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6190 xmlXPathFreeObject(newobj);
6191 xmlXPathFreeObject(cur);
6192 XP_ERROR(XPATH_INVALID_TYPE);
6193 }
6194 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6195 newobj->stringval = cur->stringval;
6196 cur->stringval = tmp;
6197
6198 xmlXPathFreeObject(newobj);
6199 nargs--;
6200 }
6201 valuePush(ctxt, cur);
6202}
6203
6204/**
6205 * xmlXPathContainsFunction:
6206 * @ctxt: the XPath Parser context
6207 * @nargs: the number of arguments
6208 *
6209 * Implement the contains() XPath function
6210 * boolean contains(string, string)
6211 * The contains function returns true if the first argument string
6212 * contains the second argument string, and otherwise returns false.
6213 */
6214void
6215xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6216 xmlXPathObjectPtr hay, needle;
6217
6218 CHECK_ARITY(2);
6219 CAST_TO_STRING;
6220 CHECK_TYPE(XPATH_STRING);
6221 needle = valuePop(ctxt);
6222 CAST_TO_STRING;
6223 hay = valuePop(ctxt);
6224 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6225 xmlXPathFreeObject(hay);
6226 xmlXPathFreeObject(needle);
6227 XP_ERROR(XPATH_INVALID_TYPE);
6228 }
6229 if (xmlStrstr(hay->stringval, needle->stringval))
6230 valuePush(ctxt, xmlXPathNewBoolean(1));
6231 else
6232 valuePush(ctxt, xmlXPathNewBoolean(0));
6233 xmlXPathFreeObject(hay);
6234 xmlXPathFreeObject(needle);
6235}
6236
6237/**
6238 * xmlXPathStartsWithFunction:
6239 * @ctxt: the XPath Parser context
6240 * @nargs: the number of arguments
6241 *
6242 * Implement the starts-with() XPath function
6243 * boolean starts-with(string, string)
6244 * The starts-with function returns true if the first argument string
6245 * starts with the second argument string, and otherwise returns false.
6246 */
6247void
6248xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6249 xmlXPathObjectPtr hay, needle;
6250 int n;
6251
6252 CHECK_ARITY(2);
6253 CAST_TO_STRING;
6254 CHECK_TYPE(XPATH_STRING);
6255 needle = valuePop(ctxt);
6256 CAST_TO_STRING;
6257 hay = valuePop(ctxt);
6258 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6259 xmlXPathFreeObject(hay);
6260 xmlXPathFreeObject(needle);
6261 XP_ERROR(XPATH_INVALID_TYPE);
6262 }
6263 n = xmlStrlen(needle->stringval);
6264 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6265 valuePush(ctxt, xmlXPathNewBoolean(0));
6266 else
6267 valuePush(ctxt, xmlXPathNewBoolean(1));
6268 xmlXPathFreeObject(hay);
6269 xmlXPathFreeObject(needle);
6270}
6271
6272/**
6273 * xmlXPathSubstringFunction:
6274 * @ctxt: the XPath Parser context
6275 * @nargs: the number of arguments
6276 *
6277 * Implement the substring() XPath function
6278 * string substring(string, number, number?)
6279 * The substring function returns the substring of the first argument
6280 * starting at the position specified in the second argument with
6281 * length specified in the third argument. For example,
6282 * substring("12345",2,3) returns "234". If the third argument is not
6283 * specified, it returns the substring starting at the position specified
6284 * in the second argument and continuing to the end of the string. For
6285 * example, substring("12345",2) returns "2345". More precisely, each
6286 * character in the string (see [3.6 Strings]) is considered to have a
6287 * numeric position: the position of the first character is 1, the position
6288 * of the second character is 2 and so on. The returned substring contains
6289 * those characters for which the position of the character is greater than
6290 * or equal to the second argument and, if the third argument is specified,
6291 * less than the sum of the second and third arguments; the comparisons
6292 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6293 * - substring("12345", 1.5, 2.6) returns "234"
6294 * - substring("12345", 0, 3) returns "12"
6295 * - substring("12345", 0 div 0, 3) returns ""
6296 * - substring("12345", 1, 0 div 0) returns ""
6297 * - substring("12345", -42, 1 div 0) returns "12345"
6298 * - substring("12345", -1 div 0, 1 div 0) returns ""
6299 */
6300void
6301xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6302 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006303 double le=0, in;
6304 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006305 xmlChar *ret;
6306
Owen Taylor3473f882001-02-23 17:55:21 +00006307 if (nargs < 2) {
6308 CHECK_ARITY(2);
6309 }
6310 if (nargs > 3) {
6311 CHECK_ARITY(3);
6312 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006313 /*
6314 * take care of possible last (position) argument
6315 */
Owen Taylor3473f882001-02-23 17:55:21 +00006316 if (nargs == 3) {
6317 CAST_TO_NUMBER;
6318 CHECK_TYPE(XPATH_NUMBER);
6319 len = valuePop(ctxt);
6320 le = len->floatval;
6321 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006322 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006323
Owen Taylor3473f882001-02-23 17:55:21 +00006324 CAST_TO_NUMBER;
6325 CHECK_TYPE(XPATH_NUMBER);
6326 start = valuePop(ctxt);
6327 in = start->floatval;
6328 xmlXPathFreeObject(start);
6329 CAST_TO_STRING;
6330 CHECK_TYPE(XPATH_STRING);
6331 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006332 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006333
Daniel Veillard97ac1312001-05-30 19:14:17 +00006334 /*
6335 * If last pos not present, calculate last position
6336 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006337 if (nargs != 3) {
6338 le = (double)m;
6339 if (in < 1.0)
6340 in = 1.0;
6341 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006342
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006343 /* Need to check for the special cases where either
6344 * the index is NaN, the length is NaN, or both
6345 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006346 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006347 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006348 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006349 * To meet the requirements of the spec, the arguments
6350 * must be converted to integer format before
6351 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006352 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006353 * First we go to integer form, rounding up
6354 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006355 */
6356 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006357 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006358
Daniel Veillard9e412302002-06-10 15:59:44 +00006359 if (xmlXPathIsInf(le) == 1) {
6360 l = m;
6361 if (i < 1)
6362 i = 1;
6363 }
6364 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6365 l = 0;
6366 else {
6367 l = (int) le;
6368 if (((double)l)+0.5 <= le) l++;
6369 }
6370
6371 /* Now we normalize inidices */
6372 i -= 1;
6373 l += i;
6374 if (i < 0)
6375 i = 0;
6376 if (l > m)
6377 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006378
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006379 /* number of chars to copy */
6380 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006381
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006382 ret = xmlUTF8Strsub(str->stringval, i, l);
6383 }
6384 else {
6385 ret = NULL;
6386 }
6387
Owen Taylor3473f882001-02-23 17:55:21 +00006388 if (ret == NULL)
6389 valuePush(ctxt, xmlXPathNewCString(""));
6390 else {
6391 valuePush(ctxt, xmlXPathNewString(ret));
6392 xmlFree(ret);
6393 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006394
Owen Taylor3473f882001-02-23 17:55:21 +00006395 xmlXPathFreeObject(str);
6396}
6397
6398/**
6399 * xmlXPathSubstringBeforeFunction:
6400 * @ctxt: the XPath Parser context
6401 * @nargs: the number of arguments
6402 *
6403 * Implement the substring-before() XPath function
6404 * string substring-before(string, string)
6405 * The substring-before function returns the substring of the first
6406 * argument string that precedes the first occurrence of the second
6407 * argument string in the first argument string, or the empty string
6408 * if the first argument string does not contain the second argument
6409 * string. For example, substring-before("1999/04/01","/") returns 1999.
6410 */
6411void
6412xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6413 xmlXPathObjectPtr str;
6414 xmlXPathObjectPtr find;
6415 xmlBufferPtr target;
6416 const xmlChar *point;
6417 int offset;
6418
6419 CHECK_ARITY(2);
6420 CAST_TO_STRING;
6421 find = valuePop(ctxt);
6422 CAST_TO_STRING;
6423 str = valuePop(ctxt);
6424
6425 target = xmlBufferCreate();
6426 if (target) {
6427 point = xmlStrstr(str->stringval, find->stringval);
6428 if (point) {
6429 offset = (int)(point - str->stringval);
6430 xmlBufferAdd(target, str->stringval, offset);
6431 }
6432 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6433 xmlBufferFree(target);
6434 }
6435
6436 xmlXPathFreeObject(str);
6437 xmlXPathFreeObject(find);
6438}
6439
6440/**
6441 * xmlXPathSubstringAfterFunction:
6442 * @ctxt: the XPath Parser context
6443 * @nargs: the number of arguments
6444 *
6445 * Implement the substring-after() XPath function
6446 * string substring-after(string, string)
6447 * The substring-after function returns the substring of the first
6448 * argument string that follows the first occurrence of the second
6449 * argument string in the first argument string, or the empty stringi
6450 * if the first argument string does not contain the second argument
6451 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6452 * and substring-after("1999/04/01","19") returns 99/04/01.
6453 */
6454void
6455xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6456 xmlXPathObjectPtr str;
6457 xmlXPathObjectPtr find;
6458 xmlBufferPtr target;
6459 const xmlChar *point;
6460 int offset;
6461
6462 CHECK_ARITY(2);
6463 CAST_TO_STRING;
6464 find = valuePop(ctxt);
6465 CAST_TO_STRING;
6466 str = valuePop(ctxt);
6467
6468 target = xmlBufferCreate();
6469 if (target) {
6470 point = xmlStrstr(str->stringval, find->stringval);
6471 if (point) {
6472 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6473 xmlBufferAdd(target, &str->stringval[offset],
6474 xmlStrlen(str->stringval) - offset);
6475 }
6476 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6477 xmlBufferFree(target);
6478 }
6479
6480 xmlXPathFreeObject(str);
6481 xmlXPathFreeObject(find);
6482}
6483
6484/**
6485 * xmlXPathNormalizeFunction:
6486 * @ctxt: the XPath Parser context
6487 * @nargs: the number of arguments
6488 *
6489 * Implement the normalize-space() XPath function
6490 * string normalize-space(string?)
6491 * The normalize-space function returns the argument string with white
6492 * space normalized by stripping leading and trailing whitespace
6493 * and replacing sequences of whitespace characters by a single
6494 * space. Whitespace characters are the same allowed by the S production
6495 * in XML. If the argument is omitted, it defaults to the context
6496 * node converted to a string, in other words the value of the context node.
6497 */
6498void
6499xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6500 xmlXPathObjectPtr obj = NULL;
6501 xmlChar *source = NULL;
6502 xmlBufferPtr target;
6503 xmlChar blank;
6504
6505 if (nargs == 0) {
6506 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006507 valuePush(ctxt,
6508 xmlXPathWrapString(
6509 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006510 nargs = 1;
6511 }
6512
6513 CHECK_ARITY(1);
6514 CAST_TO_STRING;
6515 CHECK_TYPE(XPATH_STRING);
6516 obj = valuePop(ctxt);
6517 source = obj->stringval;
6518
6519 target = xmlBufferCreate();
6520 if (target && source) {
6521
6522 /* Skip leading whitespaces */
6523 while (IS_BLANK(*source))
6524 source++;
6525
6526 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6527 blank = 0;
6528 while (*source) {
6529 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006530 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006531 } else {
6532 if (blank) {
6533 xmlBufferAdd(target, &blank, 1);
6534 blank = 0;
6535 }
6536 xmlBufferAdd(target, source, 1);
6537 }
6538 source++;
6539 }
6540
6541 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6542 xmlBufferFree(target);
6543 }
6544 xmlXPathFreeObject(obj);
6545}
6546
6547/**
6548 * xmlXPathTranslateFunction:
6549 * @ctxt: the XPath Parser context
6550 * @nargs: the number of arguments
6551 *
6552 * Implement the translate() XPath function
6553 * string translate(string, string, string)
6554 * The translate function returns the first argument string with
6555 * occurrences of characters in the second argument string replaced
6556 * by the character at the corresponding position in the third argument
6557 * string. For example, translate("bar","abc","ABC") returns the string
6558 * BAr. If there is a character in the second argument string with no
6559 * character at a corresponding position in the third argument string
6560 * (because the second argument string is longer than the third argument
6561 * string), then occurrences of that character in the first argument
6562 * string are removed. For example, translate("--aaa--","abc-","ABC")
6563 * returns "AAA". If a character occurs more than once in second
6564 * argument string, then the first occurrence determines the replacement
6565 * character. If the third argument string is longer than the second
6566 * argument string, then excess characters are ignored.
6567 */
6568void
6569xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006570 xmlXPathObjectPtr str;
6571 xmlXPathObjectPtr from;
6572 xmlXPathObjectPtr to;
6573 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006574 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006575 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006576 xmlChar *point;
6577 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006578
Daniel Veillarde043ee12001-04-16 14:08:07 +00006579 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006580
Daniel Veillarde043ee12001-04-16 14:08:07 +00006581 CAST_TO_STRING;
6582 to = valuePop(ctxt);
6583 CAST_TO_STRING;
6584 from = valuePop(ctxt);
6585 CAST_TO_STRING;
6586 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006587
Daniel Veillarde043ee12001-04-16 14:08:07 +00006588 target = xmlBufferCreate();
6589 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006590 max = xmlUTF8Strlen(to->stringval);
6591 for (cptr = str->stringval; (ch=*cptr); ) {
6592 offset = xmlUTF8Strloc(from->stringval, cptr);
6593 if (offset >= 0) {
6594 if (offset < max) {
6595 point = xmlUTF8Strpos(to->stringval, offset);
6596 if (point)
6597 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6598 }
6599 } else
6600 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6601
6602 /* Step to next character in input */
6603 cptr++;
6604 if ( ch & 0x80 ) {
6605 /* if not simple ascii, verify proper format */
6606 if ( (ch & 0xc0) != 0xc0 ) {
6607 xmlGenericError(xmlGenericErrorContext,
6608 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6609 break;
6610 }
6611 /* then skip over remaining bytes for this char */
6612 while ( (ch <<= 1) & 0x80 )
6613 if ( (*cptr++ & 0xc0) != 0x80 ) {
6614 xmlGenericError(xmlGenericErrorContext,
6615 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6616 break;
6617 }
6618 if (ch & 0x80) /* must have had error encountered */
6619 break;
6620 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006621 }
Owen Taylor3473f882001-02-23 17:55:21 +00006622 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006623 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6624 xmlBufferFree(target);
6625 xmlXPathFreeObject(str);
6626 xmlXPathFreeObject(from);
6627 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006628}
6629
6630/**
6631 * xmlXPathBooleanFunction:
6632 * @ctxt: the XPath Parser context
6633 * @nargs: the number of arguments
6634 *
6635 * Implement the boolean() XPath function
6636 * boolean boolean(object)
6637 * he boolean function converts its argument to a boolean as follows:
6638 * - a number is true if and only if it is neither positive or
6639 * negative zero nor NaN
6640 * - a node-set is true if and only if it is non-empty
6641 * - a string is true if and only if its length is non-zero
6642 */
6643void
6644xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6645 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006646
6647 CHECK_ARITY(1);
6648 cur = valuePop(ctxt);
6649 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006650 cur = xmlXPathConvertBoolean(cur);
6651 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006652}
6653
6654/**
6655 * xmlXPathNotFunction:
6656 * @ctxt: the XPath Parser context
6657 * @nargs: the number of arguments
6658 *
6659 * Implement the not() XPath function
6660 * boolean not(boolean)
6661 * The not function returns true if its argument is false,
6662 * and false otherwise.
6663 */
6664void
6665xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6666 CHECK_ARITY(1);
6667 CAST_TO_BOOLEAN;
6668 CHECK_TYPE(XPATH_BOOLEAN);
6669 ctxt->value->boolval = ! ctxt->value->boolval;
6670}
6671
6672/**
6673 * xmlXPathTrueFunction:
6674 * @ctxt: the XPath Parser context
6675 * @nargs: the number of arguments
6676 *
6677 * Implement the true() XPath function
6678 * boolean true()
6679 */
6680void
6681xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6682 CHECK_ARITY(0);
6683 valuePush(ctxt, xmlXPathNewBoolean(1));
6684}
6685
6686/**
6687 * xmlXPathFalseFunction:
6688 * @ctxt: the XPath Parser context
6689 * @nargs: the number of arguments
6690 *
6691 * Implement the false() XPath function
6692 * boolean false()
6693 */
6694void
6695xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6696 CHECK_ARITY(0);
6697 valuePush(ctxt, xmlXPathNewBoolean(0));
6698}
6699
6700/**
6701 * xmlXPathLangFunction:
6702 * @ctxt: the XPath Parser context
6703 * @nargs: the number of arguments
6704 *
6705 * Implement the lang() XPath function
6706 * boolean lang(string)
6707 * The lang function returns true or false depending on whether the
6708 * language of the context node as specified by xml:lang attributes
6709 * is the same as or is a sublanguage of the language specified by
6710 * the argument string. The language of the context node is determined
6711 * by the value of the xml:lang attribute on the context node, or, if
6712 * the context node has no xml:lang attribute, by the value of the
6713 * xml:lang attribute on the nearest ancestor of the context node that
6714 * has an xml:lang attribute. If there is no such attribute, then lang
6715 * returns false. If there is such an attribute, then lang returns
6716 * true if the attribute value is equal to the argument ignoring case,
6717 * or if there is some suffix starting with - such that the attribute
6718 * value is equal to the argument ignoring that suffix of the attribute
6719 * value and ignoring case.
6720 */
6721void
6722xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6723 xmlXPathObjectPtr val;
6724 const xmlChar *theLang;
6725 const xmlChar *lang;
6726 int ret = 0;
6727 int i;
6728
6729 CHECK_ARITY(1);
6730 CAST_TO_STRING;
6731 CHECK_TYPE(XPATH_STRING);
6732 val = valuePop(ctxt);
6733 lang = val->stringval;
6734 theLang = xmlNodeGetLang(ctxt->context->node);
6735 if ((theLang != NULL) && (lang != NULL)) {
6736 for (i = 0;lang[i] != 0;i++)
6737 if (toupper(lang[i]) != toupper(theLang[i]))
6738 goto not_equal;
6739 ret = 1;
6740 }
6741not_equal:
6742 xmlXPathFreeObject(val);
6743 valuePush(ctxt, xmlXPathNewBoolean(ret));
6744}
6745
6746/**
6747 * xmlXPathNumberFunction:
6748 * @ctxt: the XPath Parser context
6749 * @nargs: the number of arguments
6750 *
6751 * Implement the number() XPath function
6752 * number number(object?)
6753 */
6754void
6755xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6756 xmlXPathObjectPtr cur;
6757 double res;
6758
6759 if (nargs == 0) {
6760 if (ctxt->context->node == NULL) {
6761 valuePush(ctxt, xmlXPathNewFloat(0.0));
6762 } else {
6763 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6764
6765 res = xmlXPathStringEvalNumber(content);
6766 valuePush(ctxt, xmlXPathNewFloat(res));
6767 xmlFree(content);
6768 }
6769 return;
6770 }
6771
6772 CHECK_ARITY(1);
6773 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006774 cur = xmlXPathConvertNumber(cur);
6775 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006776}
6777
6778/**
6779 * xmlXPathSumFunction:
6780 * @ctxt: the XPath Parser context
6781 * @nargs: the number of arguments
6782 *
6783 * Implement the sum() XPath function
6784 * number sum(node-set)
6785 * The sum function returns the sum of the values of the nodes in
6786 * the argument node-set.
6787 */
6788void
6789xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6790 xmlXPathObjectPtr cur;
6791 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006792 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006793
6794 CHECK_ARITY(1);
6795 if ((ctxt->value == NULL) ||
6796 ((ctxt->value->type != XPATH_NODESET) &&
6797 (ctxt->value->type != XPATH_XSLT_TREE)))
6798 XP_ERROR(XPATH_INVALID_TYPE);
6799 cur = valuePop(ctxt);
6800
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006801 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006802 valuePush(ctxt, xmlXPathNewFloat(0.0));
6803 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006804 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6805 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006806 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006807 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006808 }
6809 xmlXPathFreeObject(cur);
6810}
6811
6812/**
6813 * xmlXPathFloorFunction:
6814 * @ctxt: the XPath Parser context
6815 * @nargs: the number of arguments
6816 *
6817 * Implement the floor() XPath function
6818 * number floor(number)
6819 * The floor function returns the largest (closest to positive infinity)
6820 * number that is not greater than the argument and that is an integer.
6821 */
6822void
6823xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006824 double f;
6825
Owen Taylor3473f882001-02-23 17:55:21 +00006826 CHECK_ARITY(1);
6827 CAST_TO_NUMBER;
6828 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006829
6830 f = (double)((int) ctxt->value->floatval);
6831 if (f != ctxt->value->floatval) {
6832 if (ctxt->value->floatval > 0)
6833 ctxt->value->floatval = f;
6834 else
6835 ctxt->value->floatval = f - 1;
6836 }
Owen Taylor3473f882001-02-23 17:55:21 +00006837}
6838
6839/**
6840 * xmlXPathCeilingFunction:
6841 * @ctxt: the XPath Parser context
6842 * @nargs: the number of arguments
6843 *
6844 * Implement the ceiling() XPath function
6845 * number ceiling(number)
6846 * The ceiling function returns the smallest (closest to negative infinity)
6847 * number that is not less than the argument and that is an integer.
6848 */
6849void
6850xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6851 double f;
6852
6853 CHECK_ARITY(1);
6854 CAST_TO_NUMBER;
6855 CHECK_TYPE(XPATH_NUMBER);
6856
6857#if 0
6858 ctxt->value->floatval = ceil(ctxt->value->floatval);
6859#else
6860 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006861 if (f != ctxt->value->floatval) {
6862 if (ctxt->value->floatval > 0)
6863 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006864 else {
6865 if (ctxt->value->floatval < 0 && f == 0)
6866 ctxt->value->floatval = xmlXPathNZERO;
6867 else
6868 ctxt->value->floatval = f;
6869 }
6870
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006871 }
Owen Taylor3473f882001-02-23 17:55:21 +00006872#endif
6873}
6874
6875/**
6876 * xmlXPathRoundFunction:
6877 * @ctxt: the XPath Parser context
6878 * @nargs: the number of arguments
6879 *
6880 * Implement the round() XPath function
6881 * number round(number)
6882 * The round function returns the number that is closest to the
6883 * argument and that is an integer. If there are two such numbers,
6884 * then the one that is even is returned.
6885 */
6886void
6887xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6888 double f;
6889
6890 CHECK_ARITY(1);
6891 CAST_TO_NUMBER;
6892 CHECK_TYPE(XPATH_NUMBER);
6893
Daniel Veillardcda96922001-08-21 10:56:31 +00006894 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6895 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6896 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006897 (ctxt->value->floatval == 0.0))
6898 return;
6899
Owen Taylor3473f882001-02-23 17:55:21 +00006900 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006901 if (ctxt->value->floatval < 0) {
6902 if (ctxt->value->floatval < f - 0.5)
6903 ctxt->value->floatval = f - 1;
6904 else
6905 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006906 if (ctxt->value->floatval == 0)
6907 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006908 } else {
6909 if (ctxt->value->floatval < f + 0.5)
6910 ctxt->value->floatval = f;
6911 else
6912 ctxt->value->floatval = f + 1;
6913 }
Owen Taylor3473f882001-02-23 17:55:21 +00006914}
6915
6916/************************************************************************
6917 * *
6918 * The Parser *
6919 * *
6920 ************************************************************************/
6921
6922/*
6923 * a couple of forward declarations since we use a recursive call based
6924 * implementation.
6925 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006926static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006927static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006928static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006929static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00006930static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6931 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006932
6933/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006934 * xmlXPathCurrentChar:
6935 * @ctxt: the XPath parser context
6936 * @cur: pointer to the beginning of the char
6937 * @len: pointer to the length of the char read
6938 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006939 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006940 * bytes in the input buffer.
6941 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006942 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006943 */
6944
6945static int
6946xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6947 unsigned char c;
6948 unsigned int val;
6949 const xmlChar *cur;
6950
6951 if (ctxt == NULL)
6952 return(0);
6953 cur = ctxt->cur;
6954
6955 /*
6956 * We are supposed to handle UTF8, check it's valid
6957 * From rfc2044: encoding of the Unicode values on UTF-8:
6958 *
6959 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6960 * 0000 0000-0000 007F 0xxxxxxx
6961 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6962 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6963 *
6964 * Check for the 0x110000 limit too
6965 */
6966 c = *cur;
6967 if (c & 0x80) {
6968 if ((cur[1] & 0xc0) != 0x80)
6969 goto encoding_error;
6970 if ((c & 0xe0) == 0xe0) {
6971
6972 if ((cur[2] & 0xc0) != 0x80)
6973 goto encoding_error;
6974 if ((c & 0xf0) == 0xf0) {
6975 if (((c & 0xf8) != 0xf0) ||
6976 ((cur[3] & 0xc0) != 0x80))
6977 goto encoding_error;
6978 /* 4-byte code */
6979 *len = 4;
6980 val = (cur[0] & 0x7) << 18;
6981 val |= (cur[1] & 0x3f) << 12;
6982 val |= (cur[2] & 0x3f) << 6;
6983 val |= cur[3] & 0x3f;
6984 } else {
6985 /* 3-byte code */
6986 *len = 3;
6987 val = (cur[0] & 0xf) << 12;
6988 val |= (cur[1] & 0x3f) << 6;
6989 val |= cur[2] & 0x3f;
6990 }
6991 } else {
6992 /* 2-byte code */
6993 *len = 2;
6994 val = (cur[0] & 0x1f) << 6;
6995 val |= cur[1] & 0x3f;
6996 }
6997 if (!IS_CHAR(val)) {
6998 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6999 }
7000 return(val);
7001 } else {
7002 /* 1-byte code */
7003 *len = 1;
7004 return((int) *cur);
7005 }
7006encoding_error:
7007 /*
7008 * If we detect an UTF8 error that probably mean that the
7009 * input encoding didn't get properly advertized in the
7010 * declaration header. Report the error and switch the encoding
7011 * to ISO-Latin-1 (if you don't like this policy, just declare the
7012 * encoding !)
7013 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007014 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007015 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007016}
7017
7018/**
Owen Taylor3473f882001-02-23 17:55:21 +00007019 * xmlXPathParseNCName:
7020 * @ctxt: the XPath Parser context
7021 *
7022 * parse an XML namespace non qualified name.
7023 *
7024 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7025 *
7026 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7027 * CombiningChar | Extender
7028 *
7029 * Returns the namespace name or NULL
7030 */
7031
7032xmlChar *
7033xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007034 const xmlChar *in;
7035 xmlChar *ret;
7036 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007037
Daniel Veillard2156a562001-04-28 12:24:34 +00007038 /*
7039 * Accelerator for simple ASCII names
7040 */
7041 in = ctxt->cur;
7042 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7043 ((*in >= 0x41) && (*in <= 0x5A)) ||
7044 (*in == '_')) {
7045 in++;
7046 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7047 ((*in >= 0x41) && (*in <= 0x5A)) ||
7048 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007049 (*in == '_') || (*in == '.') ||
7050 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007051 in++;
7052 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7053 (*in == '[') || (*in == ']') || (*in == ':') ||
7054 (*in == '@') || (*in == '*')) {
7055 count = in - ctxt->cur;
7056 if (count == 0)
7057 return(NULL);
7058 ret = xmlStrndup(ctxt->cur, count);
7059 ctxt->cur = in;
7060 return(ret);
7061 }
7062 }
7063 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007064}
7065
Daniel Veillard2156a562001-04-28 12:24:34 +00007066
Owen Taylor3473f882001-02-23 17:55:21 +00007067/**
7068 * xmlXPathParseQName:
7069 * @ctxt: the XPath Parser context
7070 * @prefix: a xmlChar **
7071 *
7072 * parse an XML qualified name
7073 *
7074 * [NS 5] QName ::= (Prefix ':')? LocalPart
7075 *
7076 * [NS 6] Prefix ::= NCName
7077 *
7078 * [NS 7] LocalPart ::= NCName
7079 *
7080 * Returns the function returns the local part, and prefix is updated
7081 * to get the Prefix if any.
7082 */
7083
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007084static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007085xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7086 xmlChar *ret = NULL;
7087
7088 *prefix = NULL;
7089 ret = xmlXPathParseNCName(ctxt);
7090 if (CUR == ':') {
7091 *prefix = ret;
7092 NEXT;
7093 ret = xmlXPathParseNCName(ctxt);
7094 }
7095 return(ret);
7096}
7097
7098/**
7099 * xmlXPathParseName:
7100 * @ctxt: the XPath Parser context
7101 *
7102 * parse an XML name
7103 *
7104 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7105 * CombiningChar | Extender
7106 *
7107 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7108 *
7109 * Returns the namespace name or NULL
7110 */
7111
7112xmlChar *
7113xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007114 const xmlChar *in;
7115 xmlChar *ret;
7116 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007117
Daniel Veillard61d80a22001-04-27 17:13:01 +00007118 /*
7119 * Accelerator for simple ASCII names
7120 */
7121 in = ctxt->cur;
7122 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7123 ((*in >= 0x41) && (*in <= 0x5A)) ||
7124 (*in == '_') || (*in == ':')) {
7125 in++;
7126 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7127 ((*in >= 0x41) && (*in <= 0x5A)) ||
7128 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007129 (*in == '_') || (*in == '-') ||
7130 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007131 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007132 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007133 count = in - ctxt->cur;
7134 ret = xmlStrndup(ctxt->cur, count);
7135 ctxt->cur = in;
7136 return(ret);
7137 }
7138 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007139 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007140}
7141
Daniel Veillard61d80a22001-04-27 17:13:01 +00007142static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007143xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007144 xmlChar buf[XML_MAX_NAMELEN + 5];
7145 int len = 0, l;
7146 int c;
7147
7148 /*
7149 * Handler for more complex cases
7150 */
7151 c = CUR_CHAR(l);
7152 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007153 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7154 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007155 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007156 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007157 return(NULL);
7158 }
7159
7160 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7161 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7162 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007163 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007164 (IS_COMBINING(c)) ||
7165 (IS_EXTENDER(c)))) {
7166 COPY_BUF(l,buf,len,c);
7167 NEXTL(l);
7168 c = CUR_CHAR(l);
7169 if (len >= XML_MAX_NAMELEN) {
7170 /*
7171 * Okay someone managed to make a huge name, so he's ready to pay
7172 * for the processing speed.
7173 */
7174 xmlChar *buffer;
7175 int max = len * 2;
7176
7177 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7178 if (buffer == NULL) {
7179 XP_ERROR0(XPATH_MEMORY_ERROR);
7180 }
7181 memcpy(buffer, buf, len);
7182 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7183 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007184 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007185 (IS_COMBINING(c)) ||
7186 (IS_EXTENDER(c))) {
7187 if (len + 10 > max) {
7188 max *= 2;
7189 buffer = (xmlChar *) xmlRealloc(buffer,
7190 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007191 if (buffer == NULL) {
7192 XP_ERROR0(XPATH_MEMORY_ERROR);
7193 }
7194 }
7195 COPY_BUF(l,buffer,len,c);
7196 NEXTL(l);
7197 c = CUR_CHAR(l);
7198 }
7199 buffer[len] = 0;
7200 return(buffer);
7201 }
7202 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007203 if (len == 0)
7204 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007205 return(xmlStrndup(buf, len));
7206}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007207
7208#define MAX_FRAC 20
7209
7210static double my_pow10[MAX_FRAC] = {
7211 1.0, 10.0, 100.0, 1000.0, 10000.0,
7212 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7213 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7214 100000000000000.0,
7215 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7216 1000000000000000000.0, 10000000000000000000.0
7217};
7218
Owen Taylor3473f882001-02-23 17:55:21 +00007219/**
7220 * xmlXPathStringEvalNumber:
7221 * @str: A string to scan
7222 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007223 * [30a] Float ::= Number ('e' Digits?)?
7224 *
Owen Taylor3473f882001-02-23 17:55:21 +00007225 * [30] Number ::= Digits ('.' Digits?)?
7226 * | '.' Digits
7227 * [31] Digits ::= [0-9]+
7228 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007229 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007230 * In complement of the Number expression, this function also handles
7231 * negative values : '-' Number.
7232 *
7233 * Returns the double value.
7234 */
7235double
7236xmlXPathStringEvalNumber(const xmlChar *str) {
7237 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007238 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007239 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007240 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007241 int exponent = 0;
7242 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007243#ifdef __GNUC__
7244 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007245 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007246#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007247 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007248 while (IS_BLANK(*cur)) cur++;
7249 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7250 return(xmlXPathNAN);
7251 }
7252 if (*cur == '-') {
7253 isneg = 1;
7254 cur++;
7255 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007256
7257#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007258 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007259 * tmp/temp is a workaround against a gcc compiler bug
7260 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007261 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007262 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007263 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007264 ret = ret * 10;
7265 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007266 ok = 1;
7267 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007268 temp = (double) tmp;
7269 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007270 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007271#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007272 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007273 while ((*cur >= '0') && (*cur <= '9')) {
7274 ret = ret * 10 + (*cur - '0');
7275 ok = 1;
7276 cur++;
7277 }
7278#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007279
Owen Taylor3473f882001-02-23 17:55:21 +00007280 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007281 int v, frac = 0;
7282 double fraction = 0;
7283
Owen Taylor3473f882001-02-23 17:55:21 +00007284 cur++;
7285 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7286 return(xmlXPathNAN);
7287 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007288 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7289 v = (*cur - '0');
7290 fraction = fraction * 10 + v;
7291 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007292 cur++;
7293 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007294 fraction /= my_pow10[frac];
7295 ret = ret + fraction;
7296 while ((*cur >= '0') && (*cur <= '9'))
7297 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007298 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007299 if ((*cur == 'e') || (*cur == 'E')) {
7300 cur++;
7301 if (*cur == '-') {
7302 is_exponent_negative = 1;
7303 cur++;
7304 }
7305 while ((*cur >= '0') && (*cur <= '9')) {
7306 exponent = exponent * 10 + (*cur - '0');
7307 cur++;
7308 }
7309 }
Owen Taylor3473f882001-02-23 17:55:21 +00007310 while (IS_BLANK(*cur)) cur++;
7311 if (*cur != 0) return(xmlXPathNAN);
7312 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007313 if (is_exponent_negative) exponent = -exponent;
7314 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007315 return(ret);
7316}
7317
7318/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007319 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007320 * @ctxt: the XPath Parser context
7321 *
7322 * [30] Number ::= Digits ('.' Digits?)?
7323 * | '.' Digits
7324 * [31] Digits ::= [0-9]+
7325 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007326 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007327 *
7328 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007329static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007330xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7331{
Owen Taylor3473f882001-02-23 17:55:21 +00007332 double ret = 0.0;
7333 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007334 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007335 int exponent = 0;
7336 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007337#ifdef __GNUC__
7338 unsigned long tmp = 0;
7339 double temp;
7340#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007341
7342 CHECK_ERROR;
7343 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7344 XP_ERROR(XPATH_NUMBER_ERROR);
7345 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007346#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007347 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007348 * tmp/temp is a workaround against a gcc compiler bug
7349 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007350 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007351 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007352 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007353 ret = ret * 10;
7354 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007355 ok = 1;
7356 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007357 temp = (double) tmp;
7358 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007359 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007360#else
7361 ret = 0;
7362 while ((CUR >= '0') && (CUR <= '9')) {
7363 ret = ret * 10 + (CUR - '0');
7364 ok = 1;
7365 NEXT;
7366 }
7367#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007368 if (CUR == '.') {
7369 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007370 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7371 XP_ERROR(XPATH_NUMBER_ERROR);
7372 }
7373 while ((CUR >= '0') && (CUR <= '9')) {
7374 mult /= 10;
7375 ret = ret + (CUR - '0') * mult;
7376 NEXT;
7377 }
Owen Taylor3473f882001-02-23 17:55:21 +00007378 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007379 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007380 NEXT;
7381 if (CUR == '-') {
7382 is_exponent_negative = 1;
7383 NEXT;
7384 }
7385 while ((CUR >= '0') && (CUR <= '9')) {
7386 exponent = exponent * 10 + (CUR - '0');
7387 NEXT;
7388 }
7389 if (is_exponent_negative)
7390 exponent = -exponent;
7391 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007392 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007393 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007394 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007395}
7396
7397/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007398 * xmlXPathParseLiteral:
7399 * @ctxt: the XPath Parser context
7400 *
7401 * Parse a Literal
7402 *
7403 * [29] Literal ::= '"' [^"]* '"'
7404 * | "'" [^']* "'"
7405 *
7406 * Returns the value found or NULL in case of error
7407 */
7408static xmlChar *
7409xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7410 const xmlChar *q;
7411 xmlChar *ret = NULL;
7412
7413 if (CUR == '"') {
7414 NEXT;
7415 q = CUR_PTR;
7416 while ((IS_CHAR(CUR)) && (CUR != '"'))
7417 NEXT;
7418 if (!IS_CHAR(CUR)) {
7419 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7420 } else {
7421 ret = xmlStrndup(q, CUR_PTR - q);
7422 NEXT;
7423 }
7424 } else if (CUR == '\'') {
7425 NEXT;
7426 q = CUR_PTR;
7427 while ((IS_CHAR(CUR)) && (CUR != '\''))
7428 NEXT;
7429 if (!IS_CHAR(CUR)) {
7430 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7431 } else {
7432 ret = xmlStrndup(q, CUR_PTR - q);
7433 NEXT;
7434 }
7435 } else {
7436 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7437 }
7438 return(ret);
7439}
7440
7441/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007442 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007443 * @ctxt: the XPath Parser context
7444 *
7445 * Parse a Literal and push it on the stack.
7446 *
7447 * [29] Literal ::= '"' [^"]* '"'
7448 * | "'" [^']* "'"
7449 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007450 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007451 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007452static void
7453xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007454 const xmlChar *q;
7455 xmlChar *ret = NULL;
7456
7457 if (CUR == '"') {
7458 NEXT;
7459 q = CUR_PTR;
7460 while ((IS_CHAR(CUR)) && (CUR != '"'))
7461 NEXT;
7462 if (!IS_CHAR(CUR)) {
7463 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7464 } else {
7465 ret = xmlStrndup(q, CUR_PTR - q);
7466 NEXT;
7467 }
7468 } else if (CUR == '\'') {
7469 NEXT;
7470 q = CUR_PTR;
7471 while ((IS_CHAR(CUR)) && (CUR != '\''))
7472 NEXT;
7473 if (!IS_CHAR(CUR)) {
7474 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7475 } else {
7476 ret = xmlStrndup(q, CUR_PTR - q);
7477 NEXT;
7478 }
7479 } else {
7480 XP_ERROR(XPATH_START_LITERAL_ERROR);
7481 }
7482 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007483 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7484 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007485 xmlFree(ret);
7486}
7487
7488/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007489 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007490 * @ctxt: the XPath Parser context
7491 *
7492 * Parse a VariableReference, evaluate it and push it on the stack.
7493 *
7494 * The variable bindings consist of a mapping from variable names
7495 * to variable values. The value of a variable is an object, which
7496 * of any of the types that are possible for the value of an expression,
7497 * and may also be of additional types not specified here.
7498 *
7499 * Early evaluation is possible since:
7500 * The variable bindings [...] used to evaluate a subexpression are
7501 * always the same as those used to evaluate the containing expression.
7502 *
7503 * [36] VariableReference ::= '$' QName
7504 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007505static void
7506xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007507 xmlChar *name;
7508 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007509
7510 SKIP_BLANKS;
7511 if (CUR != '$') {
7512 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7513 }
7514 NEXT;
7515 name = xmlXPathParseQName(ctxt, &prefix);
7516 if (name == NULL) {
7517 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7518 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007519 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007520 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7521 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007522 SKIP_BLANKS;
7523}
7524
7525/**
7526 * xmlXPathIsNodeType:
7527 * @ctxt: the XPath Parser context
7528 * @name: a name string
7529 *
7530 * Is the name given a NodeType one.
7531 *
7532 * [38] NodeType ::= 'comment'
7533 * | 'text'
7534 * | 'processing-instruction'
7535 * | 'node'
7536 *
7537 * Returns 1 if true 0 otherwise
7538 */
7539int
7540xmlXPathIsNodeType(const xmlChar *name) {
7541 if (name == NULL)
7542 return(0);
7543
Daniel Veillard1971ee22002-01-31 20:29:19 +00007544 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007545 return(1);
7546 if (xmlStrEqual(name, BAD_CAST "text"))
7547 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007548 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007549 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007550 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007551 return(1);
7552 return(0);
7553}
7554
7555/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007556 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007557 * @ctxt: the XPath Parser context
7558 *
7559 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7560 * [17] Argument ::= Expr
7561 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007562 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007563 * pushed on the stack
7564 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007565static void
7566xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007567 xmlChar *name;
7568 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007569 int nbargs = 0;
7570
7571 name = xmlXPathParseQName(ctxt, &prefix);
7572 if (name == NULL) {
7573 XP_ERROR(XPATH_EXPR_ERROR);
7574 }
7575 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007576#ifdef DEBUG_EXPR
7577 if (prefix == NULL)
7578 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7579 name);
7580 else
7581 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7582 prefix, name);
7583#endif
7584
Owen Taylor3473f882001-02-23 17:55:21 +00007585 if (CUR != '(') {
7586 XP_ERROR(XPATH_EXPR_ERROR);
7587 }
7588 NEXT;
7589 SKIP_BLANKS;
7590
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007591 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007592 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007593 int op1 = ctxt->comp->last;
7594 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007595 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007596 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007597 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007598 nbargs++;
7599 if (CUR == ')') break;
7600 if (CUR != ',') {
7601 XP_ERROR(XPATH_EXPR_ERROR);
7602 }
7603 NEXT;
7604 SKIP_BLANKS;
7605 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007606 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7607 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007608 NEXT;
7609 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007610}
7611
7612/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007613 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007614 * @ctxt: the XPath Parser context
7615 *
7616 * [15] PrimaryExpr ::= VariableReference
7617 * | '(' Expr ')'
7618 * | Literal
7619 * | Number
7620 * | FunctionCall
7621 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007622 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007623 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007624static void
7625xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007626 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007627 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007628 else if (CUR == '(') {
7629 NEXT;
7630 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007631 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007632 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007633 if (CUR != ')') {
7634 XP_ERROR(XPATH_EXPR_ERROR);
7635 }
7636 NEXT;
7637 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007638 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007639 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007640 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007641 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007642 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007643 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007644 }
7645 SKIP_BLANKS;
7646}
7647
7648/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007649 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007650 * @ctxt: the XPath Parser context
7651 *
7652 * [20] FilterExpr ::= PrimaryExpr
7653 * | FilterExpr Predicate
7654 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007655 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007656 * Square brackets are used to filter expressions in the same way that
7657 * they are used in location paths. It is an error if the expression to
7658 * be filtered does not evaluate to a node-set. The context node list
7659 * used for evaluating the expression in square brackets is the node-set
7660 * to be filtered listed in document order.
7661 */
7662
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007663static void
7664xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7665 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007666 CHECK_ERROR;
7667 SKIP_BLANKS;
7668
7669 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007670 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007671 SKIP_BLANKS;
7672 }
7673
7674
7675}
7676
7677/**
7678 * xmlXPathScanName:
7679 * @ctxt: the XPath Parser context
7680 *
7681 * Trickery: parse an XML name but without consuming the input flow
7682 * Needed to avoid insanity in the parser state.
7683 *
7684 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7685 * CombiningChar | Extender
7686 *
7687 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7688 *
7689 * [6] Names ::= Name (S Name)*
7690 *
7691 * Returns the Name parsed or NULL
7692 */
7693
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007694static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007695xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7696 xmlChar buf[XML_MAX_NAMELEN];
7697 int len = 0;
7698
7699 SKIP_BLANKS;
7700 if (!IS_LETTER(CUR) && (CUR != '_') &&
7701 (CUR != ':')) {
7702 return(NULL);
7703 }
7704
7705 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7706 (NXT(len) == '.') || (NXT(len) == '-') ||
7707 (NXT(len) == '_') || (NXT(len) == ':') ||
7708 (IS_COMBINING(NXT(len))) ||
7709 (IS_EXTENDER(NXT(len)))) {
7710 buf[len] = NXT(len);
7711 len++;
7712 if (len >= XML_MAX_NAMELEN) {
7713 xmlGenericError(xmlGenericErrorContext,
7714 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7715 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7716 (NXT(len) == '.') || (NXT(len) == '-') ||
7717 (NXT(len) == '_') || (NXT(len) == ':') ||
7718 (IS_COMBINING(NXT(len))) ||
7719 (IS_EXTENDER(NXT(len))))
7720 len++;
7721 break;
7722 }
7723 }
7724 return(xmlStrndup(buf, len));
7725}
7726
7727/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007728 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007729 * @ctxt: the XPath Parser context
7730 *
7731 * [19] PathExpr ::= LocationPath
7732 * | FilterExpr
7733 * | FilterExpr '/' RelativeLocationPath
7734 * | FilterExpr '//' RelativeLocationPath
7735 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007736 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007737 * The / operator and // operators combine an arbitrary expression
7738 * and a relative location path. It is an error if the expression
7739 * does not evaluate to a node-set.
7740 * The / operator does composition in the same way as when / is
7741 * used in a location path. As in location paths, // is short for
7742 * /descendant-or-self::node()/.
7743 */
7744
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007745static void
7746xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007747 int lc = 1; /* Should we branch to LocationPath ? */
7748 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7749
7750 SKIP_BLANKS;
7751 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007752 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007753 lc = 0;
7754 } else if (CUR == '*') {
7755 /* relative or absolute location path */
7756 lc = 1;
7757 } else if (CUR == '/') {
7758 /* relative or absolute location path */
7759 lc = 1;
7760 } else if (CUR == '@') {
7761 /* relative abbreviated attribute location path */
7762 lc = 1;
7763 } else if (CUR == '.') {
7764 /* relative abbreviated attribute location path */
7765 lc = 1;
7766 } else {
7767 /*
7768 * Problem is finding if we have a name here whether it's:
7769 * - a nodetype
7770 * - a function call in which case it's followed by '('
7771 * - an axis in which case it's followed by ':'
7772 * - a element name
7773 * We do an a priori analysis here rather than having to
7774 * maintain parsed token content through the recursive function
7775 * calls. This looks uglier but makes the code quite easier to
7776 * read/write/debug.
7777 */
7778 SKIP_BLANKS;
7779 name = xmlXPathScanName(ctxt);
7780 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7781#ifdef DEBUG_STEP
7782 xmlGenericError(xmlGenericErrorContext,
7783 "PathExpr: Axis\n");
7784#endif
7785 lc = 1;
7786 xmlFree(name);
7787 } else if (name != NULL) {
7788 int len =xmlStrlen(name);
7789 int blank = 0;
7790
7791
7792 while (NXT(len) != 0) {
7793 if (NXT(len) == '/') {
7794 /* element name */
7795#ifdef DEBUG_STEP
7796 xmlGenericError(xmlGenericErrorContext,
7797 "PathExpr: AbbrRelLocation\n");
7798#endif
7799 lc = 1;
7800 break;
7801 } else if (IS_BLANK(NXT(len))) {
7802 /* skip to next */
7803 blank = 1;
7804 } else if (NXT(len) == ':') {
7805#ifdef DEBUG_STEP
7806 xmlGenericError(xmlGenericErrorContext,
7807 "PathExpr: AbbrRelLocation\n");
7808#endif
7809 lc = 1;
7810 break;
7811 } else if ((NXT(len) == '(')) {
7812 /* Note Type or Function */
7813 if (xmlXPathIsNodeType(name)) {
7814#ifdef DEBUG_STEP
7815 xmlGenericError(xmlGenericErrorContext,
7816 "PathExpr: Type search\n");
7817#endif
7818 lc = 1;
7819 } else {
7820#ifdef DEBUG_STEP
7821 xmlGenericError(xmlGenericErrorContext,
7822 "PathExpr: function call\n");
7823#endif
7824 lc = 0;
7825 }
7826 break;
7827 } else if ((NXT(len) == '[')) {
7828 /* element name */
7829#ifdef DEBUG_STEP
7830 xmlGenericError(xmlGenericErrorContext,
7831 "PathExpr: AbbrRelLocation\n");
7832#endif
7833 lc = 1;
7834 break;
7835 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7836 (NXT(len) == '=')) {
7837 lc = 1;
7838 break;
7839 } else {
7840 lc = 1;
7841 break;
7842 }
7843 len++;
7844 }
7845 if (NXT(len) == 0) {
7846#ifdef DEBUG_STEP
7847 xmlGenericError(xmlGenericErrorContext,
7848 "PathExpr: AbbrRelLocation\n");
7849#endif
7850 /* element name */
7851 lc = 1;
7852 }
7853 xmlFree(name);
7854 } else {
7855 /* make sure all cases are covered explicitely */
7856 XP_ERROR(XPATH_EXPR_ERROR);
7857 }
7858 }
7859
7860 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007861 if (CUR == '/') {
7862 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7863 } else {
7864 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007865 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007866 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007867 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007868 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007869 CHECK_ERROR;
7870 if ((CUR == '/') && (NXT(1) == '/')) {
7871 SKIP(2);
7872 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007873
7874 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7875 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7876 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7877
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007878 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007879 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007880 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007881 }
7882 }
7883 SKIP_BLANKS;
7884}
7885
7886/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007887 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007888 * @ctxt: the XPath Parser context
7889 *
7890 * [18] UnionExpr ::= PathExpr
7891 * | UnionExpr '|' PathExpr
7892 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007893 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007894 */
7895
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007896static void
7897xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7898 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007899 CHECK_ERROR;
7900 SKIP_BLANKS;
7901 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007902 int op1 = ctxt->comp->last;
7903 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007904
7905 NEXT;
7906 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007907 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007908
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007909 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7910
Owen Taylor3473f882001-02-23 17:55:21 +00007911 SKIP_BLANKS;
7912 }
Owen Taylor3473f882001-02-23 17:55:21 +00007913}
7914
7915/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007916 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007917 * @ctxt: the XPath Parser context
7918 *
7919 * [27] UnaryExpr ::= UnionExpr
7920 * | '-' UnaryExpr
7921 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007922 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007923 */
7924
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007925static void
7926xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007927 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007928 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007929
7930 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007931 while (CUR == '-') {
7932 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007933 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007934 NEXT;
7935 SKIP_BLANKS;
7936 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007937
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007938 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007939 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007940 if (found) {
7941 if (minus)
7942 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7943 else
7944 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007945 }
7946}
7947
7948/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007949 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007950 * @ctxt: the XPath Parser context
7951 *
7952 * [26] MultiplicativeExpr ::= UnaryExpr
7953 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7954 * | MultiplicativeExpr 'div' UnaryExpr
7955 * | MultiplicativeExpr 'mod' UnaryExpr
7956 * [34] MultiplyOperator ::= '*'
7957 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007958 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007959 */
7960
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007961static void
7962xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7963 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007964 CHECK_ERROR;
7965 SKIP_BLANKS;
7966 while ((CUR == '*') ||
7967 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7968 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7969 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007970 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007971
7972 if (CUR == '*') {
7973 op = 0;
7974 NEXT;
7975 } else if (CUR == 'd') {
7976 op = 1;
7977 SKIP(3);
7978 } else if (CUR == 'm') {
7979 op = 2;
7980 SKIP(3);
7981 }
7982 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007983 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007984 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007985 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007986 SKIP_BLANKS;
7987 }
7988}
7989
7990/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007991 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007992 * @ctxt: the XPath Parser context
7993 *
7994 * [25] AdditiveExpr ::= MultiplicativeExpr
7995 * | AdditiveExpr '+' MultiplicativeExpr
7996 * | AdditiveExpr '-' MultiplicativeExpr
7997 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007998 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007999 */
8000
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008001static void
8002xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008003
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008004 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008005 CHECK_ERROR;
8006 SKIP_BLANKS;
8007 while ((CUR == '+') || (CUR == '-')) {
8008 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008009 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008010
8011 if (CUR == '+') plus = 1;
8012 else plus = 0;
8013 NEXT;
8014 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008015 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008016 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008017 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008018 SKIP_BLANKS;
8019 }
8020}
8021
8022/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008023 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008024 * @ctxt: the XPath Parser context
8025 *
8026 * [24] RelationalExpr ::= AdditiveExpr
8027 * | RelationalExpr '<' AdditiveExpr
8028 * | RelationalExpr '>' AdditiveExpr
8029 * | RelationalExpr '<=' AdditiveExpr
8030 * | RelationalExpr '>=' AdditiveExpr
8031 *
8032 * A <= B > C is allowed ? Answer from James, yes with
8033 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8034 * which is basically what got implemented.
8035 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008036 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008037 * on the stack
8038 */
8039
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008040static void
8041xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8042 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008043 CHECK_ERROR;
8044 SKIP_BLANKS;
8045 while ((CUR == '<') ||
8046 (CUR == '>') ||
8047 ((CUR == '<') && (NXT(1) == '=')) ||
8048 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008049 int inf, strict;
8050 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008051
8052 if (CUR == '<') inf = 1;
8053 else inf = 0;
8054 if (NXT(1) == '=') strict = 0;
8055 else strict = 1;
8056 NEXT;
8057 if (!strict) NEXT;
8058 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008059 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008060 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008061 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008062 SKIP_BLANKS;
8063 }
8064}
8065
8066/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008067 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008068 * @ctxt: the XPath Parser context
8069 *
8070 * [23] EqualityExpr ::= RelationalExpr
8071 * | EqualityExpr '=' RelationalExpr
8072 * | EqualityExpr '!=' RelationalExpr
8073 *
8074 * A != B != C is allowed ? Answer from James, yes with
8075 * (RelationalExpr = RelationalExpr) = RelationalExpr
8076 * (RelationalExpr != RelationalExpr) != RelationalExpr
8077 * which is basically what got implemented.
8078 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008079 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008080 *
8081 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008082static void
8083xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8084 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008085 CHECK_ERROR;
8086 SKIP_BLANKS;
8087 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008088 int eq;
8089 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008090
8091 if (CUR == '=') eq = 1;
8092 else eq = 0;
8093 NEXT;
8094 if (!eq) NEXT;
8095 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008096 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008097 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008098 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008099 SKIP_BLANKS;
8100 }
8101}
8102
8103/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008104 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008105 * @ctxt: the XPath Parser context
8106 *
8107 * [22] AndExpr ::= EqualityExpr
8108 * | AndExpr 'and' EqualityExpr
8109 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008110 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008111 *
8112 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008113static void
8114xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8115 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008116 CHECK_ERROR;
8117 SKIP_BLANKS;
8118 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008119 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008120 SKIP(3);
8121 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008122 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008123 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008124 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008125 SKIP_BLANKS;
8126 }
8127}
8128
8129/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008130 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008131 * @ctxt: the XPath Parser context
8132 *
8133 * [14] Expr ::= OrExpr
8134 * [21] OrExpr ::= AndExpr
8135 * | OrExpr 'or' AndExpr
8136 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008137 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008138 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008139static void
8140xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8141 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008142 CHECK_ERROR;
8143 SKIP_BLANKS;
8144 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008145 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008146 SKIP(2);
8147 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008148 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008149 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008150 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8151 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008152 SKIP_BLANKS;
8153 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008154 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8155 /* more ops could be optimized too */
8156 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8157 }
Owen Taylor3473f882001-02-23 17:55:21 +00008158}
8159
8160/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008161 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008162 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008163 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008164 *
8165 * [8] Predicate ::= '[' PredicateExpr ']'
8166 * [9] PredicateExpr ::= Expr
8167 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008168 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008169 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008170static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008171xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008172 int op1 = ctxt->comp->last;
8173
8174 SKIP_BLANKS;
8175 if (CUR != '[') {
8176 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8177 }
8178 NEXT;
8179 SKIP_BLANKS;
8180
8181 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008182 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008183 CHECK_ERROR;
8184
8185 if (CUR != ']') {
8186 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8187 }
8188
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008189 if (filter)
8190 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8191 else
8192 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008193
8194 NEXT;
8195 SKIP_BLANKS;
8196}
8197
8198/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008199 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008200 * @ctxt: the XPath Parser context
8201 * @test: pointer to a xmlXPathTestVal
8202 * @type: pointer to a xmlXPathTypeVal
8203 * @prefix: placeholder for a possible name prefix
8204 *
8205 * [7] NodeTest ::= NameTest
8206 * | NodeType '(' ')'
8207 * | 'processing-instruction' '(' Literal ')'
8208 *
8209 * [37] NameTest ::= '*'
8210 * | NCName ':' '*'
8211 * | QName
8212 * [38] NodeType ::= 'comment'
8213 * | 'text'
8214 * | 'processing-instruction'
8215 * | 'node'
8216 *
8217 * Returns the name found and update @test, @type and @prefix appropriately
8218 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008219static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008220xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8221 xmlXPathTypeVal *type, const xmlChar **prefix,
8222 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008223 int blanks;
8224
8225 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8226 STRANGE;
8227 return(NULL);
8228 }
8229 *type = 0;
8230 *test = 0;
8231 *prefix = NULL;
8232 SKIP_BLANKS;
8233
8234 if ((name == NULL) && (CUR == '*')) {
8235 /*
8236 * All elements
8237 */
8238 NEXT;
8239 *test = NODE_TEST_ALL;
8240 return(NULL);
8241 }
8242
8243 if (name == NULL)
8244 name = xmlXPathParseNCName(ctxt);
8245 if (name == NULL) {
8246 XP_ERROR0(XPATH_EXPR_ERROR);
8247 }
8248
8249 blanks = IS_BLANK(CUR);
8250 SKIP_BLANKS;
8251 if (CUR == '(') {
8252 NEXT;
8253 /*
8254 * NodeType or PI search
8255 */
8256 if (xmlStrEqual(name, BAD_CAST "comment"))
8257 *type = NODE_TYPE_COMMENT;
8258 else if (xmlStrEqual(name, BAD_CAST "node"))
8259 *type = NODE_TYPE_NODE;
8260 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8261 *type = NODE_TYPE_PI;
8262 else if (xmlStrEqual(name, BAD_CAST "text"))
8263 *type = NODE_TYPE_TEXT;
8264 else {
8265 if (name != NULL)
8266 xmlFree(name);
8267 XP_ERROR0(XPATH_EXPR_ERROR);
8268 }
8269
8270 *test = NODE_TEST_TYPE;
8271
8272 SKIP_BLANKS;
8273 if (*type == NODE_TYPE_PI) {
8274 /*
8275 * Specific case: search a PI by name.
8276 */
Owen Taylor3473f882001-02-23 17:55:21 +00008277 if (name != NULL)
8278 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008279 name = NULL;
8280 if (CUR != ')') {
8281 name = xmlXPathParseLiteral(ctxt);
8282 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008283 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008284 SKIP_BLANKS;
8285 }
Owen Taylor3473f882001-02-23 17:55:21 +00008286 }
8287 if (CUR != ')') {
8288 if (name != NULL)
8289 xmlFree(name);
8290 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8291 }
8292 NEXT;
8293 return(name);
8294 }
8295 *test = NODE_TEST_NAME;
8296 if ((!blanks) && (CUR == ':')) {
8297 NEXT;
8298
8299 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008300 * Since currently the parser context don't have a
8301 * namespace list associated:
8302 * The namespace name for this prefix can be computed
8303 * only at evaluation time. The compilation is done
8304 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008305 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008306#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008307 *prefix = xmlXPathNsLookup(ctxt->context, name);
8308 if (name != NULL)
8309 xmlFree(name);
8310 if (*prefix == NULL) {
8311 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8312 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008313#else
8314 *prefix = name;
8315#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008316
8317 if (CUR == '*') {
8318 /*
8319 * All elements
8320 */
8321 NEXT;
8322 *test = NODE_TEST_ALL;
8323 return(NULL);
8324 }
8325
8326 name = xmlXPathParseNCName(ctxt);
8327 if (name == NULL) {
8328 XP_ERROR0(XPATH_EXPR_ERROR);
8329 }
8330 }
8331 return(name);
8332}
8333
8334/**
8335 * xmlXPathIsAxisName:
8336 * @name: a preparsed name token
8337 *
8338 * [6] AxisName ::= 'ancestor'
8339 * | 'ancestor-or-self'
8340 * | 'attribute'
8341 * | 'child'
8342 * | 'descendant'
8343 * | 'descendant-or-self'
8344 * | 'following'
8345 * | 'following-sibling'
8346 * | 'namespace'
8347 * | 'parent'
8348 * | 'preceding'
8349 * | 'preceding-sibling'
8350 * | 'self'
8351 *
8352 * Returns the axis or 0
8353 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008354static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008355xmlXPathIsAxisName(const xmlChar *name) {
8356 xmlXPathAxisVal ret = 0;
8357 switch (name[0]) {
8358 case 'a':
8359 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8360 ret = AXIS_ANCESTOR;
8361 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8362 ret = AXIS_ANCESTOR_OR_SELF;
8363 if (xmlStrEqual(name, BAD_CAST "attribute"))
8364 ret = AXIS_ATTRIBUTE;
8365 break;
8366 case 'c':
8367 if (xmlStrEqual(name, BAD_CAST "child"))
8368 ret = AXIS_CHILD;
8369 break;
8370 case 'd':
8371 if (xmlStrEqual(name, BAD_CAST "descendant"))
8372 ret = AXIS_DESCENDANT;
8373 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8374 ret = AXIS_DESCENDANT_OR_SELF;
8375 break;
8376 case 'f':
8377 if (xmlStrEqual(name, BAD_CAST "following"))
8378 ret = AXIS_FOLLOWING;
8379 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8380 ret = AXIS_FOLLOWING_SIBLING;
8381 break;
8382 case 'n':
8383 if (xmlStrEqual(name, BAD_CAST "namespace"))
8384 ret = AXIS_NAMESPACE;
8385 break;
8386 case 'p':
8387 if (xmlStrEqual(name, BAD_CAST "parent"))
8388 ret = AXIS_PARENT;
8389 if (xmlStrEqual(name, BAD_CAST "preceding"))
8390 ret = AXIS_PRECEDING;
8391 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8392 ret = AXIS_PRECEDING_SIBLING;
8393 break;
8394 case 's':
8395 if (xmlStrEqual(name, BAD_CAST "self"))
8396 ret = AXIS_SELF;
8397 break;
8398 }
8399 return(ret);
8400}
8401
8402/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008403 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008404 * @ctxt: the XPath Parser context
8405 *
8406 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8407 * | AbbreviatedStep
8408 *
8409 * [12] AbbreviatedStep ::= '.' | '..'
8410 *
8411 * [5] AxisSpecifier ::= AxisName '::'
8412 * | AbbreviatedAxisSpecifier
8413 *
8414 * [13] AbbreviatedAxisSpecifier ::= '@'?
8415 *
8416 * Modified for XPtr range support as:
8417 *
8418 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8419 * | AbbreviatedStep
8420 * | 'range-to' '(' Expr ')' Predicate*
8421 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008422 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008423 * A location step of . is short for self::node(). This is
8424 * particularly useful in conjunction with //. For example, the
8425 * location path .//para is short for
8426 * self::node()/descendant-or-self::node()/child::para
8427 * and so will select all para descendant elements of the context
8428 * node.
8429 * Similarly, a location step of .. is short for parent::node().
8430 * For example, ../title is short for parent::node()/child::title
8431 * and so will select the title children of the parent of the context
8432 * node.
8433 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008434static void
8435xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008436#ifdef LIBXML_XPTR_ENABLED
8437 int rangeto = 0;
8438 int op2 = -1;
8439#endif
8440
Owen Taylor3473f882001-02-23 17:55:21 +00008441 SKIP_BLANKS;
8442 if ((CUR == '.') && (NXT(1) == '.')) {
8443 SKIP(2);
8444 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008445 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8446 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008447 } else if (CUR == '.') {
8448 NEXT;
8449 SKIP_BLANKS;
8450 } else {
8451 xmlChar *name = NULL;
8452 const xmlChar *prefix = NULL;
8453 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008454 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008455 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008456 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008457
8458 /*
8459 * The modification needed for XPointer change to the production
8460 */
8461#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008462 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008463 name = xmlXPathParseNCName(ctxt);
8464 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008465 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008466 xmlFree(name);
8467 SKIP_BLANKS;
8468 if (CUR != '(') {
8469 XP_ERROR(XPATH_EXPR_ERROR);
8470 }
8471 NEXT;
8472 SKIP_BLANKS;
8473
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008474 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008475 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008476 CHECK_ERROR;
8477
8478 SKIP_BLANKS;
8479 if (CUR != ')') {
8480 XP_ERROR(XPATH_EXPR_ERROR);
8481 }
8482 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008483 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008484 goto eval_predicates;
8485 }
8486 }
8487#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008488 if (CUR == '*') {
8489 axis = AXIS_CHILD;
8490 } else {
8491 if (name == NULL)
8492 name = xmlXPathParseNCName(ctxt);
8493 if (name != NULL) {
8494 axis = xmlXPathIsAxisName(name);
8495 if (axis != 0) {
8496 SKIP_BLANKS;
8497 if ((CUR == ':') && (NXT(1) == ':')) {
8498 SKIP(2);
8499 xmlFree(name);
8500 name = NULL;
8501 } else {
8502 /* an element name can conflict with an axis one :-\ */
8503 axis = AXIS_CHILD;
8504 }
Owen Taylor3473f882001-02-23 17:55:21 +00008505 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008506 axis = AXIS_CHILD;
8507 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008508 } else if (CUR == '@') {
8509 NEXT;
8510 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008511 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008512 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008513 }
Owen Taylor3473f882001-02-23 17:55:21 +00008514 }
8515
8516 CHECK_ERROR;
8517
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008518 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008519 if (test == 0)
8520 return;
8521
8522#ifdef DEBUG_STEP
8523 xmlGenericError(xmlGenericErrorContext,
8524 "Basis : computing new set\n");
8525#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008526
Owen Taylor3473f882001-02-23 17:55:21 +00008527#ifdef DEBUG_STEP
8528 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008529 if (ctxt->value == NULL)
8530 xmlGenericError(xmlGenericErrorContext, "no value\n");
8531 else if (ctxt->value->nodesetval == NULL)
8532 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8533 else
8534 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008535#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008536
8537eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008538 op1 = ctxt->comp->last;
8539 ctxt->comp->last = -1;
8540
Owen Taylor3473f882001-02-23 17:55:21 +00008541 SKIP_BLANKS;
8542 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008543 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008544 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008545
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008546#ifdef LIBXML_XPTR_ENABLED
8547 if (rangeto) {
8548 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8549 } else
8550#endif
8551 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8552 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008553
Owen Taylor3473f882001-02-23 17:55:21 +00008554 }
8555#ifdef DEBUG_STEP
8556 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008557 if (ctxt->value == NULL)
8558 xmlGenericError(xmlGenericErrorContext, "no value\n");
8559 else if (ctxt->value->nodesetval == NULL)
8560 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8561 else
8562 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8563 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008564#endif
8565}
8566
8567/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008568 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008569 * @ctxt: the XPath Parser context
8570 *
8571 * [3] RelativeLocationPath ::= Step
8572 * | RelativeLocationPath '/' Step
8573 * | AbbreviatedRelativeLocationPath
8574 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8575 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008576 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008577 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008578static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008579xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008580(xmlXPathParserContextPtr ctxt) {
8581 SKIP_BLANKS;
8582 if ((CUR == '/') && (NXT(1) == '/')) {
8583 SKIP(2);
8584 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008585 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8586 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008587 } else if (CUR == '/') {
8588 NEXT;
8589 SKIP_BLANKS;
8590 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008591 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008592 SKIP_BLANKS;
8593 while (CUR == '/') {
8594 if ((CUR == '/') && (NXT(1) == '/')) {
8595 SKIP(2);
8596 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008597 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008598 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008599 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008600 } else if (CUR == '/') {
8601 NEXT;
8602 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008603 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008604 }
8605 SKIP_BLANKS;
8606 }
8607}
8608
8609/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008610 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008611 * @ctxt: the XPath Parser context
8612 *
8613 * [1] LocationPath ::= RelativeLocationPath
8614 * | AbsoluteLocationPath
8615 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8616 * | AbbreviatedAbsoluteLocationPath
8617 * [10] AbbreviatedAbsoluteLocationPath ::=
8618 * '//' RelativeLocationPath
8619 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008620 * Compile a location path
8621 *
Owen Taylor3473f882001-02-23 17:55:21 +00008622 * // is short for /descendant-or-self::node()/. For example,
8623 * //para is short for /descendant-or-self::node()/child::para and
8624 * so will select any para element in the document (even a para element
8625 * that is a document element will be selected by //para since the
8626 * document element node is a child of the root node); div//para is
8627 * short for div/descendant-or-self::node()/child::para and so will
8628 * select all para descendants of div children.
8629 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008630static void
8631xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008632 SKIP_BLANKS;
8633 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008634 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008635 } else {
8636 while (CUR == '/') {
8637 if ((CUR == '/') && (NXT(1) == '/')) {
8638 SKIP(2);
8639 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008640 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8641 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008642 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008643 } else if (CUR == '/') {
8644 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008645 SKIP_BLANKS;
8646 if ((CUR != 0 ) &&
8647 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8648 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008649 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008650 }
8651 }
8652 }
8653}
8654
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008655/************************************************************************
8656 * *
8657 * XPath precompiled expression evaluation *
8658 * *
8659 ************************************************************************/
8660
Daniel Veillardf06307e2001-07-03 10:35:50 +00008661static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008662xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8663
8664/**
8665 * xmlXPathNodeCollectAndTest:
8666 * @ctxt: the XPath Parser context
8667 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008668 * @first: pointer to the first element in document order
8669 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008670 *
8671 * This is the function implementing a step: based on the current list
8672 * of nodes, it builds up a new list, looking at all nodes under that
8673 * axis and selecting them it also do the predicate filtering
8674 *
8675 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008676 *
8677 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008678 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008679static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008680xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008681 xmlXPathStepOpPtr op,
8682 xmlNodePtr * first, xmlNodePtr * last)
8683{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008684 xmlXPathAxisVal axis = op->value;
8685 xmlXPathTestVal test = op->value2;
8686 xmlXPathTypeVal type = op->value3;
8687 const xmlChar *prefix = op->value4;
8688 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008689 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008690
8691#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008692 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008693#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008694 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008695 xmlNodeSetPtr ret, list;
8696 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008697 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008698 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008699 xmlNodePtr cur = NULL;
8700 xmlXPathObjectPtr obj;
8701 xmlNodeSetPtr nodelist;
8702 xmlNodePtr tmp;
8703
Daniel Veillardf06307e2001-07-03 10:35:50 +00008704 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008705 obj = valuePop(ctxt);
8706 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008707 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008708 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008709 URI = xmlXPathNsLookup(ctxt->context, prefix);
8710 if (URI == NULL)
8711 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008712 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008713#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008714 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008715#endif
8716 switch (axis) {
8717 case AXIS_ANCESTOR:
8718#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008719 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008720#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008721 first = NULL;
8722 next = xmlXPathNextAncestor;
8723 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008724 case AXIS_ANCESTOR_OR_SELF:
8725#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008726 xmlGenericError(xmlGenericErrorContext,
8727 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008728#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008729 first = NULL;
8730 next = xmlXPathNextAncestorOrSelf;
8731 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008732 case AXIS_ATTRIBUTE:
8733#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008734 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008735#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008736 first = NULL;
8737 last = NULL;
8738 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008739 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008740 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008741 case AXIS_CHILD:
8742#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008743 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008744#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008745 last = NULL;
8746 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008747 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008748 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008749 case AXIS_DESCENDANT:
8750#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008751 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008752#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008753 last = NULL;
8754 next = xmlXPathNextDescendant;
8755 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008756 case AXIS_DESCENDANT_OR_SELF:
8757#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008758 xmlGenericError(xmlGenericErrorContext,
8759 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008760#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008761 last = NULL;
8762 next = xmlXPathNextDescendantOrSelf;
8763 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008764 case AXIS_FOLLOWING:
8765#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008766 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008767#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008768 last = NULL;
8769 next = xmlXPathNextFollowing;
8770 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008771 case AXIS_FOLLOWING_SIBLING:
8772#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008773 xmlGenericError(xmlGenericErrorContext,
8774 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008775#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008776 last = NULL;
8777 next = xmlXPathNextFollowingSibling;
8778 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008779 case AXIS_NAMESPACE:
8780#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008781 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008782#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008783 first = NULL;
8784 last = NULL;
8785 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008786 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008787 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008788 case AXIS_PARENT:
8789#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008790 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008791#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008792 first = NULL;
8793 next = xmlXPathNextParent;
8794 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008795 case AXIS_PRECEDING:
8796#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008797 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008798#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008799 first = NULL;
8800 next = xmlXPathNextPrecedingInternal;
8801 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008802 case AXIS_PRECEDING_SIBLING:
8803#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008804 xmlGenericError(xmlGenericErrorContext,
8805 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008806#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008807 first = NULL;
8808 next = xmlXPathNextPrecedingSibling;
8809 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008810 case AXIS_SELF:
8811#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008812 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008813#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008814 first = NULL;
8815 last = NULL;
8816 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008817 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008818 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008819 }
8820 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008821 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008822
8823 nodelist = obj->nodesetval;
8824 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008825 xmlXPathFreeObject(obj);
8826 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8827 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008828 }
8829 addNode = xmlXPathNodeSetAddUnique;
8830 ret = NULL;
8831#ifdef DEBUG_STEP
8832 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008833 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008834 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008835 case NODE_TEST_NONE:
8836 xmlGenericError(xmlGenericErrorContext,
8837 " searching for none !!!\n");
8838 break;
8839 case NODE_TEST_TYPE:
8840 xmlGenericError(xmlGenericErrorContext,
8841 " searching for type %d\n", type);
8842 break;
8843 case NODE_TEST_PI:
8844 xmlGenericError(xmlGenericErrorContext,
8845 " searching for PI !!!\n");
8846 break;
8847 case NODE_TEST_ALL:
8848 xmlGenericError(xmlGenericErrorContext,
8849 " searching for *\n");
8850 break;
8851 case NODE_TEST_NS:
8852 xmlGenericError(xmlGenericErrorContext,
8853 " searching for namespace %s\n",
8854 prefix);
8855 break;
8856 case NODE_TEST_NAME:
8857 xmlGenericError(xmlGenericErrorContext,
8858 " searching for name %s\n", name);
8859 if (prefix != NULL)
8860 xmlGenericError(xmlGenericErrorContext,
8861 " with namespace %s\n", prefix);
8862 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008863 }
8864 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8865#endif
8866 /*
8867 * 2.3 Node Tests
8868 * - For the attribute axis, the principal node type is attribute.
8869 * - For the namespace axis, the principal node type is namespace.
8870 * - For other axes, the principal node type is element.
8871 *
8872 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008873 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008874 * select all element children of the context node
8875 */
8876 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008877 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008878 ctxt->context->node = nodelist->nodeTab[i];
8879
Daniel Veillardf06307e2001-07-03 10:35:50 +00008880 cur = NULL;
8881 list = xmlXPathNodeSetCreate(NULL);
8882 do {
8883 cur = next(ctxt, cur);
8884 if (cur == NULL)
8885 break;
8886 if ((first != NULL) && (*first == cur))
8887 break;
8888 if (((t % 256) == 0) &&
8889 (first != NULL) && (*first != NULL) &&
8890 (xmlXPathCmpNodes(*first, cur) >= 0))
8891 break;
8892 if ((last != NULL) && (*last == cur))
8893 break;
8894 if (((t % 256) == 0) &&
8895 (last != NULL) && (*last != NULL) &&
8896 (xmlXPathCmpNodes(cur, *last) >= 0))
8897 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008898 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008899#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008900 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8901#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008903 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008904 ctxt->context->node = tmp;
8905 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008906 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008907 if ((cur->type == type) ||
8908 ((type == NODE_TYPE_NODE) &&
8909 ((cur->type == XML_DOCUMENT_NODE) ||
8910 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8911 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008912 (cur->type == XML_NAMESPACE_DECL) ||
8913 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008914 (cur->type == XML_PI_NODE) ||
8915 (cur->type == XML_COMMENT_NODE) ||
8916 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008917 (cur->type == XML_TEXT_NODE))) ||
8918 ((type == NODE_TYPE_TEXT) &&
8919 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008920#ifdef DEBUG_STEP
8921 n++;
8922#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008923 addNode(list, cur);
8924 }
8925 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008927 if (cur->type == XML_PI_NODE) {
8928 if ((name != NULL) &&
8929 (!xmlStrEqual(name, cur->name)))
8930 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008931#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008932 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008933#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008934 addNode(list, cur);
8935 }
8936 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008937 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 if (axis == AXIS_ATTRIBUTE) {
8939 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008940#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008941 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008942#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008943 addNode(list, cur);
8944 }
8945 } else if (axis == AXIS_NAMESPACE) {
8946 if (cur->type == XML_NAMESPACE_DECL) {
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 Veillard044fc6b2002-03-04 17:09:44 +00008950 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8951 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008952 }
8953 } else {
8954 if (cur->type == XML_ELEMENT_NODE) {
8955 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008956#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008957 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008958#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008959 addNode(list, cur);
8960 } else if ((cur->ns != NULL) &&
8961 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008962#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008963 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008964#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008965 addNode(list, cur);
8966 }
8967 }
8968 }
8969 break;
8970 case NODE_TEST_NS:{
8971 TODO;
8972 break;
8973 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008974 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975 switch (cur->type) {
8976 case XML_ELEMENT_NODE:
8977 if (xmlStrEqual(name, cur->name)) {
8978 if (prefix == NULL) {
8979 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008980#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008981 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008982#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008983 addNode(list, cur);
8984 }
8985 } else {
8986 if ((cur->ns != NULL) &&
8987 (xmlStrEqual(URI,
8988 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008989#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008991#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992 addNode(list, cur);
8993 }
8994 }
8995 }
8996 break;
8997 case XML_ATTRIBUTE_NODE:{
8998 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008999
Daniel Veillardf06307e2001-07-03 10:35:50 +00009000 if (xmlStrEqual(name, attr->name)) {
9001 if (prefix == NULL) {
9002 if ((attr->ns == NULL) ||
9003 (attr->ns->prefix == NULL)) {
9004#ifdef DEBUG_STEP
9005 n++;
9006#endif
9007 addNode(list,
9008 (xmlNodePtr) attr);
9009 }
9010 } else {
9011 if ((attr->ns != NULL) &&
9012 (xmlStrEqual(URI,
9013 attr->ns->
9014 href))) {
9015#ifdef DEBUG_STEP
9016 n++;
9017#endif
9018 addNode(list,
9019 (xmlNodePtr) attr);
9020 }
9021 }
9022 }
9023 break;
9024 }
9025 case XML_NAMESPACE_DECL:
9026 if (cur->type == XML_NAMESPACE_DECL) {
9027 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009028
Daniel Veillardf06307e2001-07-03 10:35:50 +00009029 if ((ns->prefix != NULL) && (name != NULL)
9030 && (xmlStrEqual(ns->prefix, name))) {
9031#ifdef DEBUG_STEP
9032 n++;
9033#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009034 xmlXPathNodeSetAddNs(list,
9035 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009036 }
9037 }
9038 break;
9039 default:
9040 break;
9041 }
9042 break;
9043 break;
9044 }
9045 } while (cur != NULL);
9046
9047 /*
9048 * If there is some predicate filtering do it now
9049 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009050 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 xmlXPathObjectPtr obj2;
9052
9053 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9054 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9055 CHECK_TYPE0(XPATH_NODESET);
9056 obj2 = valuePop(ctxt);
9057 list = obj2->nodesetval;
9058 obj2->nodesetval = NULL;
9059 xmlXPathFreeObject(obj2);
9060 }
9061 if (ret == NULL) {
9062 ret = list;
9063 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009064 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009065 xmlXPathFreeNodeSet(list);
9066 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009067 }
9068 ctxt->context->node = tmp;
9069#ifdef DEBUG_STEP
9070 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009071 "\nExamined %d nodes, found %d nodes at that step\n",
9072 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009073#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009074 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009075 if ((obj->boolval) && (obj->user != NULL)) {
9076 ctxt->value->boolval = 1;
9077 ctxt->value->user = obj->user;
9078 obj->user = NULL;
9079 obj->boolval = 0;
9080 }
9081 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009082 return(t);
9083}
9084
9085/**
9086 * xmlXPathNodeCollectAndTestNth:
9087 * @ctxt: the XPath Parser context
9088 * @op: the XPath precompiled step operation
9089 * @indx: the index to collect
9090 * @first: pointer to the first element in document order
9091 * @last: pointer to the last element in document order
9092 *
9093 * This is the function implementing a step: based on the current list
9094 * of nodes, it builds up a new list, looking at all nodes under that
9095 * axis and selecting them it also do the predicate filtering
9096 *
9097 * Pushes the new NodeSet resulting from the search.
9098 * Returns the number of node traversed
9099 */
9100static int
9101xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9102 xmlXPathStepOpPtr op, int indx,
9103 xmlNodePtr * first, xmlNodePtr * last)
9104{
9105 xmlXPathAxisVal axis = op->value;
9106 xmlXPathTestVal test = op->value2;
9107 xmlXPathTypeVal type = op->value3;
9108 const xmlChar *prefix = op->value4;
9109 const xmlChar *name = op->value5;
9110 const xmlChar *URI = NULL;
9111 int n = 0, t = 0;
9112
9113 int i;
9114 xmlNodeSetPtr list;
9115 xmlXPathTraversalFunction next = NULL;
9116 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9117 xmlNodePtr cur = NULL;
9118 xmlXPathObjectPtr obj;
9119 xmlNodeSetPtr nodelist;
9120 xmlNodePtr tmp;
9121
9122 CHECK_TYPE0(XPATH_NODESET);
9123 obj = valuePop(ctxt);
9124 addNode = xmlXPathNodeSetAdd;
9125 if (prefix != NULL) {
9126 URI = xmlXPathNsLookup(ctxt->context, prefix);
9127 if (URI == NULL)
9128 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9129 }
9130#ifdef DEBUG_STEP_NTH
9131 xmlGenericError(xmlGenericErrorContext, "new step : ");
9132 if (first != NULL) {
9133 if (*first != NULL)
9134 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9135 (*first)->name);
9136 else
9137 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9138 }
9139 if (last != NULL) {
9140 if (*last != NULL)
9141 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9142 (*last)->name);
9143 else
9144 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9145 }
9146#endif
9147 switch (axis) {
9148 case AXIS_ANCESTOR:
9149#ifdef DEBUG_STEP_NTH
9150 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9151#endif
9152 first = NULL;
9153 next = xmlXPathNextAncestor;
9154 break;
9155 case AXIS_ANCESTOR_OR_SELF:
9156#ifdef DEBUG_STEP_NTH
9157 xmlGenericError(xmlGenericErrorContext,
9158 "axis 'ancestors-or-self' ");
9159#endif
9160 first = NULL;
9161 next = xmlXPathNextAncestorOrSelf;
9162 break;
9163 case AXIS_ATTRIBUTE:
9164#ifdef DEBUG_STEP_NTH
9165 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9166#endif
9167 first = NULL;
9168 last = NULL;
9169 next = xmlXPathNextAttribute;
9170 break;
9171 case AXIS_CHILD:
9172#ifdef DEBUG_STEP_NTH
9173 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9174#endif
9175 last = NULL;
9176 next = xmlXPathNextChild;
9177 break;
9178 case AXIS_DESCENDANT:
9179#ifdef DEBUG_STEP_NTH
9180 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9181#endif
9182 last = NULL;
9183 next = xmlXPathNextDescendant;
9184 break;
9185 case AXIS_DESCENDANT_OR_SELF:
9186#ifdef DEBUG_STEP_NTH
9187 xmlGenericError(xmlGenericErrorContext,
9188 "axis 'descendant-or-self' ");
9189#endif
9190 last = NULL;
9191 next = xmlXPathNextDescendantOrSelf;
9192 break;
9193 case AXIS_FOLLOWING:
9194#ifdef DEBUG_STEP_NTH
9195 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9196#endif
9197 last = NULL;
9198 next = xmlXPathNextFollowing;
9199 break;
9200 case AXIS_FOLLOWING_SIBLING:
9201#ifdef DEBUG_STEP_NTH
9202 xmlGenericError(xmlGenericErrorContext,
9203 "axis 'following-siblings' ");
9204#endif
9205 last = NULL;
9206 next = xmlXPathNextFollowingSibling;
9207 break;
9208 case AXIS_NAMESPACE:
9209#ifdef DEBUG_STEP_NTH
9210 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9211#endif
9212 last = NULL;
9213 first = NULL;
9214 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9215 break;
9216 case AXIS_PARENT:
9217#ifdef DEBUG_STEP_NTH
9218 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9219#endif
9220 first = NULL;
9221 next = xmlXPathNextParent;
9222 break;
9223 case AXIS_PRECEDING:
9224#ifdef DEBUG_STEP_NTH
9225 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9226#endif
9227 first = NULL;
9228 next = xmlXPathNextPrecedingInternal;
9229 break;
9230 case AXIS_PRECEDING_SIBLING:
9231#ifdef DEBUG_STEP_NTH
9232 xmlGenericError(xmlGenericErrorContext,
9233 "axis 'preceding-sibling' ");
9234#endif
9235 first = NULL;
9236 next = xmlXPathNextPrecedingSibling;
9237 break;
9238 case AXIS_SELF:
9239#ifdef DEBUG_STEP_NTH
9240 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9241#endif
9242 first = NULL;
9243 last = NULL;
9244 next = xmlXPathNextSelf;
9245 break;
9246 }
9247 if (next == NULL)
9248 return(0);
9249
9250 nodelist = obj->nodesetval;
9251 if (nodelist == NULL) {
9252 xmlXPathFreeObject(obj);
9253 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9254 return(0);
9255 }
9256 addNode = xmlXPathNodeSetAddUnique;
9257#ifdef DEBUG_STEP_NTH
9258 xmlGenericError(xmlGenericErrorContext,
9259 " context contains %d nodes\n", nodelist->nodeNr);
9260 switch (test) {
9261 case NODE_TEST_NONE:
9262 xmlGenericError(xmlGenericErrorContext,
9263 " searching for none !!!\n");
9264 break;
9265 case NODE_TEST_TYPE:
9266 xmlGenericError(xmlGenericErrorContext,
9267 " searching for type %d\n", type);
9268 break;
9269 case NODE_TEST_PI:
9270 xmlGenericError(xmlGenericErrorContext,
9271 " searching for PI !!!\n");
9272 break;
9273 case NODE_TEST_ALL:
9274 xmlGenericError(xmlGenericErrorContext,
9275 " searching for *\n");
9276 break;
9277 case NODE_TEST_NS:
9278 xmlGenericError(xmlGenericErrorContext,
9279 " searching for namespace %s\n",
9280 prefix);
9281 break;
9282 case NODE_TEST_NAME:
9283 xmlGenericError(xmlGenericErrorContext,
9284 " searching for name %s\n", name);
9285 if (prefix != NULL)
9286 xmlGenericError(xmlGenericErrorContext,
9287 " with namespace %s\n", prefix);
9288 break;
9289 }
9290 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9291#endif
9292 /*
9293 * 2.3 Node Tests
9294 * - For the attribute axis, the principal node type is attribute.
9295 * - For the namespace axis, the principal node type is namespace.
9296 * - For other axes, the principal node type is element.
9297 *
9298 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009299 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009300 * select all element children of the context node
9301 */
9302 tmp = ctxt->context->node;
9303 list = xmlXPathNodeSetCreate(NULL);
9304 for (i = 0; i < nodelist->nodeNr; i++) {
9305 ctxt->context->node = nodelist->nodeTab[i];
9306
9307 cur = NULL;
9308 n = 0;
9309 do {
9310 cur = next(ctxt, cur);
9311 if (cur == NULL)
9312 break;
9313 if ((first != NULL) && (*first == cur))
9314 break;
9315 if (((t % 256) == 0) &&
9316 (first != NULL) && (*first != NULL) &&
9317 (xmlXPathCmpNodes(*first, cur) >= 0))
9318 break;
9319 if ((last != NULL) && (*last == cur))
9320 break;
9321 if (((t % 256) == 0) &&
9322 (last != NULL) && (*last != NULL) &&
9323 (xmlXPathCmpNodes(cur, *last) >= 0))
9324 break;
9325 t++;
9326 switch (test) {
9327 case NODE_TEST_NONE:
9328 ctxt->context->node = tmp;
9329 STRANGE return(0);
9330 case NODE_TEST_TYPE:
9331 if ((cur->type == type) ||
9332 ((type == NODE_TYPE_NODE) &&
9333 ((cur->type == XML_DOCUMENT_NODE) ||
9334 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9335 (cur->type == XML_ELEMENT_NODE) ||
9336 (cur->type == XML_PI_NODE) ||
9337 (cur->type == XML_COMMENT_NODE) ||
9338 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009339 (cur->type == XML_TEXT_NODE))) ||
9340 ((type == NODE_TYPE_TEXT) &&
9341 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009342 n++;
9343 if (n == indx)
9344 addNode(list, cur);
9345 }
9346 break;
9347 case NODE_TEST_PI:
9348 if (cur->type == XML_PI_NODE) {
9349 if ((name != NULL) &&
9350 (!xmlStrEqual(name, cur->name)))
9351 break;
9352 n++;
9353 if (n == indx)
9354 addNode(list, cur);
9355 }
9356 break;
9357 case NODE_TEST_ALL:
9358 if (axis == AXIS_ATTRIBUTE) {
9359 if (cur->type == XML_ATTRIBUTE_NODE) {
9360 n++;
9361 if (n == indx)
9362 addNode(list, cur);
9363 }
9364 } else if (axis == AXIS_NAMESPACE) {
9365 if (cur->type == XML_NAMESPACE_DECL) {
9366 n++;
9367 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009368 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9369 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009370 }
9371 } else {
9372 if (cur->type == XML_ELEMENT_NODE) {
9373 if (prefix == NULL) {
9374 n++;
9375 if (n == indx)
9376 addNode(list, cur);
9377 } else if ((cur->ns != NULL) &&
9378 (xmlStrEqual(URI, cur->ns->href))) {
9379 n++;
9380 if (n == indx)
9381 addNode(list, cur);
9382 }
9383 }
9384 }
9385 break;
9386 case NODE_TEST_NS:{
9387 TODO;
9388 break;
9389 }
9390 case NODE_TEST_NAME:
9391 switch (cur->type) {
9392 case XML_ELEMENT_NODE:
9393 if (xmlStrEqual(name, cur->name)) {
9394 if (prefix == NULL) {
9395 if (cur->ns == NULL) {
9396 n++;
9397 if (n == indx)
9398 addNode(list, cur);
9399 }
9400 } else {
9401 if ((cur->ns != NULL) &&
9402 (xmlStrEqual(URI,
9403 cur->ns->href))) {
9404 n++;
9405 if (n == indx)
9406 addNode(list, cur);
9407 }
9408 }
9409 }
9410 break;
9411 case XML_ATTRIBUTE_NODE:{
9412 xmlAttrPtr attr = (xmlAttrPtr) cur;
9413
9414 if (xmlStrEqual(name, attr->name)) {
9415 if (prefix == NULL) {
9416 if ((attr->ns == NULL) ||
9417 (attr->ns->prefix == NULL)) {
9418 n++;
9419 if (n == indx)
9420 addNode(list, cur);
9421 }
9422 } else {
9423 if ((attr->ns != NULL) &&
9424 (xmlStrEqual(URI,
9425 attr->ns->
9426 href))) {
9427 n++;
9428 if (n == indx)
9429 addNode(list, cur);
9430 }
9431 }
9432 }
9433 break;
9434 }
9435 case XML_NAMESPACE_DECL:
9436 if (cur->type == XML_NAMESPACE_DECL) {
9437 xmlNsPtr ns = (xmlNsPtr) cur;
9438
9439 if ((ns->prefix != NULL) && (name != NULL)
9440 && (xmlStrEqual(ns->prefix, name))) {
9441 n++;
9442 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009443 xmlXPathNodeSetAddNs(list,
9444 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009445 }
9446 }
9447 break;
9448 default:
9449 break;
9450 }
9451 break;
9452 break;
9453 }
9454 } while (n < indx);
9455 }
9456 ctxt->context->node = tmp;
9457#ifdef DEBUG_STEP_NTH
9458 xmlGenericError(xmlGenericErrorContext,
9459 "\nExamined %d nodes, found %d nodes at that step\n",
9460 t, list->nodeNr);
9461#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009462 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009463 if ((obj->boolval) && (obj->user != NULL)) {
9464 ctxt->value->boolval = 1;
9465 ctxt->value->user = obj->user;
9466 obj->user = NULL;
9467 obj->boolval = 0;
9468 }
9469 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009470 return(t);
9471}
9472
9473/**
9474 * xmlXPathCompOpEvalFirst:
9475 * @ctxt: the XPath parser context with the compiled expression
9476 * @op: an XPath compiled operation
9477 * @first: the first elem found so far
9478 *
9479 * Evaluate the Precompiled XPath operation searching only the first
9480 * element in document order
9481 *
9482 * Returns the number of examined objects.
9483 */
9484static int
9485xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9486 xmlXPathStepOpPtr op, xmlNodePtr * first)
9487{
9488 int total = 0, cur;
9489 xmlXPathCompExprPtr comp;
9490 xmlXPathObjectPtr arg1, arg2;
9491
Daniel Veillard556c6682001-10-06 09:59:51 +00009492 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009493 comp = ctxt->comp;
9494 switch (op->op) {
9495 case XPATH_OP_END:
9496 return (0);
9497 case XPATH_OP_UNION:
9498 total =
9499 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9500 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009501 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009502 if ((ctxt->value != NULL)
9503 && (ctxt->value->type == XPATH_NODESET)
9504 && (ctxt->value->nodesetval != NULL)
9505 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9506 /*
9507 * limit tree traversing to first node in the result
9508 */
9509 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9510 *first = ctxt->value->nodesetval->nodeTab[0];
9511 }
9512 cur =
9513 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9514 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009515 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009516 CHECK_TYPE0(XPATH_NODESET);
9517 arg2 = valuePop(ctxt);
9518
9519 CHECK_TYPE0(XPATH_NODESET);
9520 arg1 = valuePop(ctxt);
9521
9522 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9523 arg2->nodesetval);
9524 valuePush(ctxt, arg1);
9525 xmlXPathFreeObject(arg2);
9526 /* optimizer */
9527 if (total > cur)
9528 xmlXPathCompSwap(op);
9529 return (total + cur);
9530 case XPATH_OP_ROOT:
9531 xmlXPathRoot(ctxt);
9532 return (0);
9533 case XPATH_OP_NODE:
9534 if (op->ch1 != -1)
9535 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009536 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009537 if (op->ch2 != -1)
9538 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009539 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009540 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9541 return (total);
9542 case XPATH_OP_RESET:
9543 if (op->ch1 != -1)
9544 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009545 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009546 if (op->ch2 != -1)
9547 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009548 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009549 ctxt->context->node = NULL;
9550 return (total);
9551 case XPATH_OP_COLLECT:{
9552 if (op->ch1 == -1)
9553 return (total);
9554
9555 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009556 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009557
9558 /*
9559 * Optimization for [n] selection where n is a number
9560 */
9561 if ((op->ch2 != -1) &&
9562 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9563 (comp->steps[op->ch2].ch1 == -1) &&
9564 (comp->steps[op->ch2].ch2 != -1) &&
9565 (comp->steps[comp->steps[op->ch2].ch2].op ==
9566 XPATH_OP_VALUE)) {
9567 xmlXPathObjectPtr val;
9568
9569 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9570 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9571 int indx = (int) val->floatval;
9572
9573 if (val->floatval == (float) indx) {
9574 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9575 first, NULL);
9576 return (total);
9577 }
9578 }
9579 }
9580 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9581 return (total);
9582 }
9583 case XPATH_OP_VALUE:
9584 valuePush(ctxt,
9585 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9586 return (0);
9587 case XPATH_OP_SORT:
9588 if (op->ch1 != -1)
9589 total +=
9590 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9591 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009592 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009593 if ((ctxt->value != NULL)
9594 && (ctxt->value->type == XPATH_NODESET)
9595 && (ctxt->value->nodesetval != NULL))
9596 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9597 return (total);
9598 default:
9599 return (xmlXPathCompOpEval(ctxt, op));
9600 }
9601}
9602
9603/**
9604 * xmlXPathCompOpEvalLast:
9605 * @ctxt: the XPath parser context with the compiled expression
9606 * @op: an XPath compiled operation
9607 * @last: the last elem found so far
9608 *
9609 * Evaluate the Precompiled XPath operation searching only the last
9610 * element in document order
9611 *
9612 * Returns the number of node traversed
9613 */
9614static int
9615xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9616 xmlNodePtr * last)
9617{
9618 int total = 0, cur;
9619 xmlXPathCompExprPtr comp;
9620 xmlXPathObjectPtr arg1, arg2;
9621
Daniel Veillard556c6682001-10-06 09:59:51 +00009622 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009623 comp = ctxt->comp;
9624 switch (op->op) {
9625 case XPATH_OP_END:
9626 return (0);
9627 case XPATH_OP_UNION:
9628 total =
9629 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009630 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009631 if ((ctxt->value != NULL)
9632 && (ctxt->value->type == XPATH_NODESET)
9633 && (ctxt->value->nodesetval != NULL)
9634 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9635 /*
9636 * limit tree traversing to first node in the result
9637 */
9638 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9639 *last =
9640 ctxt->value->nodesetval->nodeTab[ctxt->value->
9641 nodesetval->nodeNr -
9642 1];
9643 }
9644 cur =
9645 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009646 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009647 if ((ctxt->value != NULL)
9648 && (ctxt->value->type == XPATH_NODESET)
9649 && (ctxt->value->nodesetval != NULL)
9650 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9651 }
9652 CHECK_TYPE0(XPATH_NODESET);
9653 arg2 = valuePop(ctxt);
9654
9655 CHECK_TYPE0(XPATH_NODESET);
9656 arg1 = valuePop(ctxt);
9657
9658 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9659 arg2->nodesetval);
9660 valuePush(ctxt, arg1);
9661 xmlXPathFreeObject(arg2);
9662 /* optimizer */
9663 if (total > cur)
9664 xmlXPathCompSwap(op);
9665 return (total + cur);
9666 case XPATH_OP_ROOT:
9667 xmlXPathRoot(ctxt);
9668 return (0);
9669 case XPATH_OP_NODE:
9670 if (op->ch1 != -1)
9671 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009672 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009673 if (op->ch2 != -1)
9674 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009675 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009676 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9677 return (total);
9678 case XPATH_OP_RESET:
9679 if (op->ch1 != -1)
9680 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009681 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009682 if (op->ch2 != -1)
9683 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009684 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009685 ctxt->context->node = NULL;
9686 return (total);
9687 case XPATH_OP_COLLECT:{
9688 if (op->ch1 == -1)
9689 return (0);
9690
9691 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009692 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693
9694 /*
9695 * Optimization for [n] selection where n is a number
9696 */
9697 if ((op->ch2 != -1) &&
9698 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9699 (comp->steps[op->ch2].ch1 == -1) &&
9700 (comp->steps[op->ch2].ch2 != -1) &&
9701 (comp->steps[comp->steps[op->ch2].ch2].op ==
9702 XPATH_OP_VALUE)) {
9703 xmlXPathObjectPtr val;
9704
9705 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9706 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9707 int indx = (int) val->floatval;
9708
9709 if (val->floatval == (float) indx) {
9710 total +=
9711 xmlXPathNodeCollectAndTestNth(ctxt, op,
9712 indx, NULL,
9713 last);
9714 return (total);
9715 }
9716 }
9717 }
9718 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9719 return (total);
9720 }
9721 case XPATH_OP_VALUE:
9722 valuePush(ctxt,
9723 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9724 return (0);
9725 case XPATH_OP_SORT:
9726 if (op->ch1 != -1)
9727 total +=
9728 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9729 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009730 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009731 if ((ctxt->value != NULL)
9732 && (ctxt->value->type == XPATH_NODESET)
9733 && (ctxt->value->nodesetval != NULL))
9734 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9735 return (total);
9736 default:
9737 return (xmlXPathCompOpEval(ctxt, op));
9738 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009739}
9740
Owen Taylor3473f882001-02-23 17:55:21 +00009741/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009742 * xmlXPathCompOpEval:
9743 * @ctxt: the XPath parser context with the compiled expression
9744 * @op: an XPath compiled operation
9745 *
9746 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009747 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009748 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009749static int
9750xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9751{
9752 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009753 int equal, ret;
9754 xmlXPathCompExprPtr comp;
9755 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009756 xmlNodePtr bak;
9757 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009758 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009759 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009760
Daniel Veillard556c6682001-10-06 09:59:51 +00009761 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009762 comp = ctxt->comp;
9763 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009764 case XPATH_OP_END:
9765 return (0);
9766 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009767 bakd = ctxt->context->doc;
9768 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009769 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009770 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009771 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009772 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009773 xmlXPathBooleanFunction(ctxt, 1);
9774 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9775 return (total);
9776 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009777 ctxt->context->doc = bakd;
9778 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009779 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009780 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009781 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009782 if (ctxt->error) {
9783 xmlXPathFreeObject(arg2);
9784 return(0);
9785 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009786 xmlXPathBooleanFunction(ctxt, 1);
9787 arg1 = valuePop(ctxt);
9788 arg1->boolval &= arg2->boolval;
9789 valuePush(ctxt, arg1);
9790 xmlXPathFreeObject(arg2);
9791 return (total);
9792 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009793 bakd = ctxt->context->doc;
9794 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009795 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009796 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009797 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009798 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009799 xmlXPathBooleanFunction(ctxt, 1);
9800 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9801 return (total);
9802 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009803 ctxt->context->doc = bakd;
9804 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009805 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009806 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009807 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009808 if (ctxt->error) {
9809 xmlXPathFreeObject(arg2);
9810 return(0);
9811 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009812 xmlXPathBooleanFunction(ctxt, 1);
9813 arg1 = valuePop(ctxt);
9814 arg1->boolval |= arg2->boolval;
9815 valuePush(ctxt, arg1);
9816 xmlXPathFreeObject(arg2);
9817 return (total);
9818 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009819 bakd = ctxt->context->doc;
9820 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009821 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009822 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009824 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009825 ctxt->context->doc = bakd;
9826 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009827 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009828 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009830 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009831 if (op->value)
9832 equal = xmlXPathEqualValues(ctxt);
9833 else
9834 equal = xmlXPathNotEqualValues(ctxt);
9835 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009836 return (total);
9837 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009838 bakd = ctxt->context->doc;
9839 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009840 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009841 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009843 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009844 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 Veillard556c6682001-10-06 09:59:51 +00009849 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009850 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9851 valuePush(ctxt, xmlXPathNewBoolean(ret));
9852 return (total);
9853 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009854 bakd = ctxt->context->doc;
9855 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009856 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009857 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009858 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009859 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009860 if (op->ch2 != -1) {
9861 ctxt->context->doc = bakd;
9862 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009863 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009864 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009865 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009866 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009867 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009868 if (op->value == 0)
9869 xmlXPathSubValues(ctxt);
9870 else if (op->value == 1)
9871 xmlXPathAddValues(ctxt);
9872 else if (op->value == 2)
9873 xmlXPathValueFlipSign(ctxt);
9874 else if (op->value == 3) {
9875 CAST_TO_NUMBER;
9876 CHECK_TYPE0(XPATH_NUMBER);
9877 }
9878 return (total);
9879 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009880 bakd = ctxt->context->doc;
9881 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009882 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009883 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009884 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009885 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009886 ctxt->context->doc = bakd;
9887 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009888 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009889 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009890 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009891 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009892 if (op->value == 0)
9893 xmlXPathMultValues(ctxt);
9894 else if (op->value == 1)
9895 xmlXPathDivValues(ctxt);
9896 else if (op->value == 2)
9897 xmlXPathModValues(ctxt);
9898 return (total);
9899 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009900 bakd = ctxt->context->doc;
9901 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009902 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009903 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009904 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009905 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009906 ctxt->context->doc = bakd;
9907 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009908 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009909 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009910 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009911 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009912 CHECK_TYPE0(XPATH_NODESET);
9913 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009914
Daniel Veillardf06307e2001-07-03 10:35:50 +00009915 CHECK_TYPE0(XPATH_NODESET);
9916 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009917
Daniel Veillardf06307e2001-07-03 10:35:50 +00009918 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9919 arg2->nodesetval);
9920 valuePush(ctxt, arg1);
9921 xmlXPathFreeObject(arg2);
9922 return (total);
9923 case XPATH_OP_ROOT:
9924 xmlXPathRoot(ctxt);
9925 return (total);
9926 case XPATH_OP_NODE:
9927 if (op->ch1 != -1)
9928 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009929 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009930 if (op->ch2 != -1)
9931 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009932 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009933 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9934 return (total);
9935 case XPATH_OP_RESET:
9936 if (op->ch1 != -1)
9937 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009938 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009939 if (op->ch2 != -1)
9940 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009941 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009942 ctxt->context->node = NULL;
9943 return (total);
9944 case XPATH_OP_COLLECT:{
9945 if (op->ch1 == -1)
9946 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009947
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009949 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009950
Daniel Veillardf06307e2001-07-03 10:35:50 +00009951 /*
9952 * Optimization for [n] selection where n is a number
9953 */
9954 if ((op->ch2 != -1) &&
9955 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9956 (comp->steps[op->ch2].ch1 == -1) &&
9957 (comp->steps[op->ch2].ch2 != -1) &&
9958 (comp->steps[comp->steps[op->ch2].ch2].op ==
9959 XPATH_OP_VALUE)) {
9960 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009961
Daniel Veillardf06307e2001-07-03 10:35:50 +00009962 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9963 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9964 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009965
Daniel Veillardf06307e2001-07-03 10:35:50 +00009966 if (val->floatval == (float) indx) {
9967 total +=
9968 xmlXPathNodeCollectAndTestNth(ctxt, op,
9969 indx, NULL,
9970 NULL);
9971 return (total);
9972 }
9973 }
9974 }
9975 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9976 return (total);
9977 }
9978 case XPATH_OP_VALUE:
9979 valuePush(ctxt,
9980 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9981 return (total);
9982 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009983 xmlXPathObjectPtr val;
9984
Daniel Veillardf06307e2001-07-03 10:35:50 +00009985 if (op->ch1 != -1)
9986 total +=
9987 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009988 if (op->value5 == NULL) {
9989 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9990 if (val == NULL) {
9991 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9992 return(0);
9993 }
9994 valuePush(ctxt, val);
9995 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009997
Daniel Veillardf06307e2001-07-03 10:35:50 +00009998 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9999 if (URI == NULL) {
10000 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010001 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010002 op->value4, op->value5);
10003 return (total);
10004 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010005 val = xmlXPathVariableLookupNS(ctxt->context,
10006 op->value4, URI);
10007 if (val == NULL) {
10008 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10009 return(0);
10010 }
10011 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010012 }
10013 return (total);
10014 }
10015 case XPATH_OP_FUNCTION:{
10016 xmlXPathFunction func;
10017 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010018 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010019
10020 if (op->ch1 != -1)
10021 total +=
10022 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010023 if (ctxt->valueNr < op->value) {
10024 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010025 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010026 ctxt->error = XPATH_INVALID_OPERAND;
10027 return (total);
10028 }
10029 for (i = 0; i < op->value; i++)
10030 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10031 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010032 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010033 ctxt->error = XPATH_INVALID_OPERAND;
10034 return (total);
10035 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010036 if (op->cache != NULL)
10037 func = (xmlXPathFunction) op->cache;
10038 else {
10039 const xmlChar *URI = NULL;
10040
10041 if (op->value5 == NULL)
10042 func =
10043 xmlXPathFunctionLookup(ctxt->context,
10044 op->value4);
10045 else {
10046 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10047 if (URI == NULL) {
10048 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010049 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010050 op->value4, op->value5);
10051 return (total);
10052 }
10053 func = xmlXPathFunctionLookupNS(ctxt->context,
10054 op->value4, URI);
10055 }
10056 if (func == NULL) {
10057 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010058 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059 op->value4);
10060 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061 }
10062 op->cache = (void *) func;
10063 op->cacheURI = (void *) URI;
10064 }
10065 oldFunc = ctxt->context->function;
10066 oldFuncURI = ctxt->context->functionURI;
10067 ctxt->context->function = op->value4;
10068 ctxt->context->functionURI = op->cacheURI;
10069 func(ctxt, op->value);
10070 ctxt->context->function = oldFunc;
10071 ctxt->context->functionURI = oldFuncURI;
10072 return (total);
10073 }
10074 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010075 bakd = ctxt->context->doc;
10076 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010077 if (op->ch1 != -1)
10078 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010079 ctxt->context->doc = bakd;
10080 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010081 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010082 if (op->ch2 != -1)
10083 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010084 ctxt->context->doc = bakd;
10085 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010086 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010087 return (total);
10088 case XPATH_OP_PREDICATE:
10089 case XPATH_OP_FILTER:{
10090 xmlXPathObjectPtr res;
10091 xmlXPathObjectPtr obj, tmp;
10092 xmlNodeSetPtr newset = NULL;
10093 xmlNodeSetPtr oldset;
10094 xmlNodePtr oldnode;
10095 int i;
10096
10097 /*
10098 * Optimization for ()[1] selection i.e. the first elem
10099 */
10100 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10101 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10102 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10103 xmlXPathObjectPtr val;
10104
10105 val = comp->steps[op->ch2].value4;
10106 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10107 (val->floatval == 1.0)) {
10108 xmlNodePtr first = NULL;
10109
10110 total +=
10111 xmlXPathCompOpEvalFirst(ctxt,
10112 &comp->steps[op->ch1],
10113 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010114 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010115 /*
10116 * The nodeset should be in document order,
10117 * Keep only the first value
10118 */
10119 if ((ctxt->value != NULL) &&
10120 (ctxt->value->type == XPATH_NODESET) &&
10121 (ctxt->value->nodesetval != NULL) &&
10122 (ctxt->value->nodesetval->nodeNr > 1))
10123 ctxt->value->nodesetval->nodeNr = 1;
10124 return (total);
10125 }
10126 }
10127 /*
10128 * Optimization for ()[last()] selection i.e. the last elem
10129 */
10130 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10131 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10132 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10133 int f = comp->steps[op->ch2].ch1;
10134
10135 if ((f != -1) &&
10136 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10137 (comp->steps[f].value5 == NULL) &&
10138 (comp->steps[f].value == 0) &&
10139 (comp->steps[f].value4 != NULL) &&
10140 (xmlStrEqual
10141 (comp->steps[f].value4, BAD_CAST "last"))) {
10142 xmlNodePtr last = NULL;
10143
10144 total +=
10145 xmlXPathCompOpEvalLast(ctxt,
10146 &comp->steps[op->ch1],
10147 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010148 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010149 /*
10150 * The nodeset should be in document order,
10151 * Keep only the last value
10152 */
10153 if ((ctxt->value != NULL) &&
10154 (ctxt->value->type == XPATH_NODESET) &&
10155 (ctxt->value->nodesetval != NULL) &&
10156 (ctxt->value->nodesetval->nodeTab != NULL) &&
10157 (ctxt->value->nodesetval->nodeNr > 1)) {
10158 ctxt->value->nodesetval->nodeTab[0] =
10159 ctxt->value->nodesetval->nodeTab[ctxt->
10160 value->
10161 nodesetval->
10162 nodeNr -
10163 1];
10164 ctxt->value->nodesetval->nodeNr = 1;
10165 }
10166 return (total);
10167 }
10168 }
10169
10170 if (op->ch1 != -1)
10171 total +=
10172 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010173 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010174 if (op->ch2 == -1)
10175 return (total);
10176 if (ctxt->value == NULL)
10177 return (total);
10178
10179 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010180
10181#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010182 /*
10183 * Hum are we filtering the result of an XPointer expression
10184 */
10185 if (ctxt->value->type == XPATH_LOCATIONSET) {
10186 xmlLocationSetPtr newlocset = NULL;
10187 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010188
Daniel Veillardf06307e2001-07-03 10:35:50 +000010189 /*
10190 * Extract the old locset, and then evaluate the result of the
10191 * expression for all the element in the locset. use it to grow
10192 * up a new locset.
10193 */
10194 CHECK_TYPE0(XPATH_LOCATIONSET);
10195 obj = valuePop(ctxt);
10196 oldlocset = obj->user;
10197 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010198
Daniel Veillardf06307e2001-07-03 10:35:50 +000010199 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10200 ctxt->context->contextSize = 0;
10201 ctxt->context->proximityPosition = 0;
10202 if (op->ch2 != -1)
10203 total +=
10204 xmlXPathCompOpEval(ctxt,
10205 &comp->steps[op->ch2]);
10206 res = valuePop(ctxt);
10207 if (res != NULL)
10208 xmlXPathFreeObject(res);
10209 valuePush(ctxt, obj);
10210 CHECK_ERROR0;
10211 return (total);
10212 }
10213 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010214
Daniel Veillardf06307e2001-07-03 10:35:50 +000010215 for (i = 0; i < oldlocset->locNr; i++) {
10216 /*
10217 * Run the evaluation with a node list made of a
10218 * single item in the nodelocset.
10219 */
10220 ctxt->context->node = oldlocset->locTab[i]->user;
10221 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10222 valuePush(ctxt, tmp);
10223 ctxt->context->contextSize = oldlocset->locNr;
10224 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010225
Daniel Veillardf06307e2001-07-03 10:35:50 +000010226 if (op->ch2 != -1)
10227 total +=
10228 xmlXPathCompOpEval(ctxt,
10229 &comp->steps[op->ch2]);
10230 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010231
Daniel Veillardf06307e2001-07-03 10:35:50 +000010232 /*
10233 * The result of the evaluation need to be tested to
10234 * decided whether the filter succeeded or not
10235 */
10236 res = valuePop(ctxt);
10237 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10238 xmlXPtrLocationSetAdd(newlocset,
10239 xmlXPathObjectCopy
10240 (oldlocset->locTab[i]));
10241 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010242
Daniel Veillardf06307e2001-07-03 10:35:50 +000010243 /*
10244 * Cleanup
10245 */
10246 if (res != NULL)
10247 xmlXPathFreeObject(res);
10248 if (ctxt->value == tmp) {
10249 res = valuePop(ctxt);
10250 xmlXPathFreeObject(res);
10251 }
10252
10253 ctxt->context->node = NULL;
10254 }
10255
10256 /*
10257 * The result is used as the new evaluation locset.
10258 */
10259 xmlXPathFreeObject(obj);
10260 ctxt->context->node = NULL;
10261 ctxt->context->contextSize = -1;
10262 ctxt->context->proximityPosition = -1;
10263 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10264 ctxt->context->node = oldnode;
10265 return (total);
10266 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010267#endif /* LIBXML_XPTR_ENABLED */
10268
Daniel Veillardf06307e2001-07-03 10:35:50 +000010269 /*
10270 * Extract the old set, and then evaluate the result of the
10271 * expression for all the element in the set. use it to grow
10272 * up a new set.
10273 */
10274 CHECK_TYPE0(XPATH_NODESET);
10275 obj = valuePop(ctxt);
10276 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010277
Daniel Veillardf06307e2001-07-03 10:35:50 +000010278 oldnode = ctxt->context->node;
10279 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010280
Daniel Veillardf06307e2001-07-03 10:35:50 +000010281 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10282 ctxt->context->contextSize = 0;
10283 ctxt->context->proximityPosition = 0;
10284 if (op->ch2 != -1)
10285 total +=
10286 xmlXPathCompOpEval(ctxt,
10287 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010288 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010289 res = valuePop(ctxt);
10290 if (res != NULL)
10291 xmlXPathFreeObject(res);
10292 valuePush(ctxt, obj);
10293 ctxt->context->node = oldnode;
10294 CHECK_ERROR0;
10295 } else {
10296 /*
10297 * Initialize the new set.
10298 */
10299 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010300
Daniel Veillardf06307e2001-07-03 10:35:50 +000010301 for (i = 0; i < oldset->nodeNr; i++) {
10302 /*
10303 * Run the evaluation with a node list made of
10304 * a single item in the nodeset.
10305 */
10306 ctxt->context->node = oldset->nodeTab[i];
10307 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10308 valuePush(ctxt, tmp);
10309 ctxt->context->contextSize = oldset->nodeNr;
10310 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010311
Daniel Veillardf06307e2001-07-03 10:35:50 +000010312 if (op->ch2 != -1)
10313 total +=
10314 xmlXPathCompOpEval(ctxt,
10315 &comp->steps[op->ch2]);
10316 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010317
Daniel Veillardf06307e2001-07-03 10:35:50 +000010318 /*
10319 * The result of the evaluation need to be tested to
10320 * decided whether the filter succeeded or not
10321 */
10322 res = valuePop(ctxt);
10323 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10324 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10325 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010326
Daniel Veillardf06307e2001-07-03 10:35:50 +000010327 /*
10328 * Cleanup
10329 */
10330 if (res != NULL)
10331 xmlXPathFreeObject(res);
10332 if (ctxt->value == tmp) {
10333 res = valuePop(ctxt);
10334 xmlXPathFreeObject(res);
10335 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010336
Daniel Veillardf06307e2001-07-03 10:35:50 +000010337 ctxt->context->node = NULL;
10338 }
10339
10340 /*
10341 * The result is used as the new evaluation set.
10342 */
10343 xmlXPathFreeObject(obj);
10344 ctxt->context->node = NULL;
10345 ctxt->context->contextSize = -1;
10346 ctxt->context->proximityPosition = -1;
10347 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10348 }
10349 ctxt->context->node = oldnode;
10350 return (total);
10351 }
10352 case XPATH_OP_SORT:
10353 if (op->ch1 != -1)
10354 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010355 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010356 if ((ctxt->value != NULL) &&
10357 (ctxt->value->type == XPATH_NODESET) &&
10358 (ctxt->value->nodesetval != NULL))
10359 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10360 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010361#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010362 case XPATH_OP_RANGETO:{
10363 xmlXPathObjectPtr range;
10364 xmlXPathObjectPtr res, obj;
10365 xmlXPathObjectPtr tmp;
10366 xmlLocationSetPtr newset = NULL;
10367 xmlNodeSetPtr oldset;
10368 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010369
Daniel Veillardf06307e2001-07-03 10:35:50 +000010370 if (op->ch1 != -1)
10371 total +=
10372 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10373 if (op->ch2 == -1)
10374 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010375
Daniel Veillardf06307e2001-07-03 10:35:50 +000010376 CHECK_TYPE0(XPATH_NODESET);
10377 obj = valuePop(ctxt);
10378 oldset = obj->nodesetval;
10379 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010380
Daniel Veillardf06307e2001-07-03 10:35:50 +000010381 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010382
Daniel Veillardf06307e2001-07-03 10:35:50 +000010383 if (oldset != NULL) {
10384 for (i = 0; i < oldset->nodeNr; i++) {
10385 /*
10386 * Run the evaluation with a node list made of a single item
10387 * in the nodeset.
10388 */
10389 ctxt->context->node = oldset->nodeTab[i];
10390 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10391 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010392
Daniel Veillardf06307e2001-07-03 10:35:50 +000010393 if (op->ch2 != -1)
10394 total +=
10395 xmlXPathCompOpEval(ctxt,
10396 &comp->steps[op->ch2]);
10397 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010398
Daniel Veillardf06307e2001-07-03 10:35:50 +000010399 /*
10400 * The result of the evaluation need to be tested to
10401 * decided whether the filter succeeded or not
10402 */
10403 res = valuePop(ctxt);
10404 range =
10405 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10406 res);
10407 if (range != NULL) {
10408 xmlXPtrLocationSetAdd(newset, range);
10409 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010410
Daniel Veillardf06307e2001-07-03 10:35:50 +000010411 /*
10412 * Cleanup
10413 */
10414 if (res != NULL)
10415 xmlXPathFreeObject(res);
10416 if (ctxt->value == tmp) {
10417 res = valuePop(ctxt);
10418 xmlXPathFreeObject(res);
10419 }
10420
10421 ctxt->context->node = NULL;
10422 }
10423 }
10424
10425 /*
10426 * The result is used as the new evaluation set.
10427 */
10428 xmlXPathFreeObject(obj);
10429 ctxt->context->node = NULL;
10430 ctxt->context->contextSize = -1;
10431 ctxt->context->proximityPosition = -1;
10432 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10433 return (total);
10434 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010435#endif /* LIBXML_XPTR_ENABLED */
10436 }
10437 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010438 "XPath: unknown precompiled operation %d\n", op->op);
10439 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010440}
10441
10442/**
10443 * xmlXPathRunEval:
10444 * @ctxt: the XPath parser context with the compiled expression
10445 *
10446 * Evaluate the Precompiled XPath expression in the given context.
10447 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010448static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010449xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10450 xmlXPathCompExprPtr comp;
10451
10452 if ((ctxt == NULL) || (ctxt->comp == NULL))
10453 return;
10454
10455 if (ctxt->valueTab == NULL) {
10456 /* Allocate the value stack */
10457 ctxt->valueTab = (xmlXPathObjectPtr *)
10458 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10459 if (ctxt->valueTab == NULL) {
10460 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010461 }
10462 ctxt->valueNr = 0;
10463 ctxt->valueMax = 10;
10464 ctxt->value = NULL;
10465 }
10466 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010467 if(comp->last < 0) {
10468 xmlGenericError(xmlGenericErrorContext,
10469 "xmlXPathRunEval: last is less than zero\n");
10470 return;
10471 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010472 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10473}
10474
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010475/************************************************************************
10476 * *
10477 * Public interfaces *
10478 * *
10479 ************************************************************************/
10480
10481/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010482 * xmlXPathEvalPredicate:
10483 * @ctxt: the XPath context
10484 * @res: the Predicate Expression evaluation result
10485 *
10486 * Evaluate a predicate result for the current node.
10487 * A PredicateExpr is evaluated by evaluating the Expr and converting
10488 * the result to a boolean. If the result is a number, the result will
10489 * be converted to true if the number is equal to the position of the
10490 * context node in the context node list (as returned by the position
10491 * function) and will be converted to false otherwise; if the result
10492 * is not a number, then the result will be converted as if by a call
10493 * to the boolean function.
10494 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010495 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010496 */
10497int
10498xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10499 if (res == NULL) return(0);
10500 switch (res->type) {
10501 case XPATH_BOOLEAN:
10502 return(res->boolval);
10503 case XPATH_NUMBER:
10504 return(res->floatval == ctxt->proximityPosition);
10505 case XPATH_NODESET:
10506 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010507 if (res->nodesetval == NULL)
10508 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010509 return(res->nodesetval->nodeNr != 0);
10510 case XPATH_STRING:
10511 return((res->stringval != NULL) &&
10512 (xmlStrlen(res->stringval) != 0));
10513 default:
10514 STRANGE
10515 }
10516 return(0);
10517}
10518
10519/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010520 * xmlXPathEvaluatePredicateResult:
10521 * @ctxt: the XPath Parser context
10522 * @res: the Predicate Expression evaluation result
10523 *
10524 * Evaluate a predicate result for the current node.
10525 * A PredicateExpr is evaluated by evaluating the Expr and converting
10526 * the result to a boolean. If the result is a number, the result will
10527 * be converted to true if the number is equal to the position of the
10528 * context node in the context node list (as returned by the position
10529 * function) and will be converted to false otherwise; if the result
10530 * is not a number, then the result will be converted as if by a call
10531 * to the boolean function.
10532 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010533 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010534 */
10535int
10536xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10537 xmlXPathObjectPtr res) {
10538 if (res == NULL) return(0);
10539 switch (res->type) {
10540 case XPATH_BOOLEAN:
10541 return(res->boolval);
10542 case XPATH_NUMBER:
10543 return(res->floatval == ctxt->context->proximityPosition);
10544 case XPATH_NODESET:
10545 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010546 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010547 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010548 return(res->nodesetval->nodeNr != 0);
10549 case XPATH_STRING:
10550 return((res->stringval != NULL) &&
10551 (xmlStrlen(res->stringval) != 0));
10552 default:
10553 STRANGE
10554 }
10555 return(0);
10556}
10557
10558/**
10559 * xmlXPathCompile:
10560 * @str: the XPath expression
10561 *
10562 * Compile an XPath expression
10563 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010564 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010565 * the caller has to free the object.
10566 */
10567xmlXPathCompExprPtr
10568xmlXPathCompile(const xmlChar *str) {
10569 xmlXPathParserContextPtr ctxt;
10570 xmlXPathCompExprPtr comp;
10571
10572 xmlXPathInit();
10573
10574 ctxt = xmlXPathNewParserContext(str, NULL);
10575 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010576
Daniel Veillard40af6492001-04-22 08:50:55 +000010577 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010578 /*
10579 * aleksey: in some cases this line prints *second* error message
10580 * (see bug #78858) and probably this should be fixed.
10581 * However, we are not sure that all error messages are printed
10582 * out in other places. It's not critical so we leave it as-is for now
10583 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010584 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10585 comp = NULL;
10586 } else {
10587 comp = ctxt->comp;
10588 ctxt->comp = NULL;
10589 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010590 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010591 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010592 comp->expr = xmlStrdup(str);
10593#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010594 comp->string = xmlStrdup(str);
10595 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010596#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010597 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010598 return(comp);
10599}
10600
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010601/**
10602 * xmlXPathCompiledEval:
10603 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010604 * @ctx: the XPath context
10605 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010606 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010607 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010608 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010609 * the caller has to free the object.
10610 */
10611xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010612xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010613 xmlXPathParserContextPtr ctxt;
10614 xmlXPathObjectPtr res, tmp, init = NULL;
10615 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010616#ifndef LIBXML_THREAD_ENABLED
10617 static int reentance = 0;
10618#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010619
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010620 if ((comp == NULL) || (ctx == NULL))
10621 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010622 xmlXPathInit();
10623
10624 CHECK_CONTEXT(ctx)
10625
Daniel Veillard81463942001-10-16 12:34:39 +000010626#ifndef LIBXML_THREAD_ENABLED
10627 reentance++;
10628 if (reentance > 1)
10629 xmlXPathDisableOptimizer = 1;
10630#endif
10631
Daniel Veillardf06307e2001-07-03 10:35:50 +000010632#ifdef DEBUG_EVAL_COUNTS
10633 comp->nb++;
10634 if ((comp->string != NULL) && (comp->nb > 100)) {
10635 fprintf(stderr, "100 x %s\n", comp->string);
10636 comp->nb = 0;
10637 }
10638#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010639 ctxt = xmlXPathCompParserContext(comp, ctx);
10640 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010641
10642 if (ctxt->value == NULL) {
10643 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010644 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010645 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010646 } else {
10647 res = valuePop(ctxt);
10648 }
10649
Daniel Veillardf06307e2001-07-03 10:35:50 +000010650
Owen Taylor3473f882001-02-23 17:55:21 +000010651 do {
10652 tmp = valuePop(ctxt);
10653 if (tmp != NULL) {
10654 if (tmp != init)
10655 stack++;
10656 xmlXPathFreeObject(tmp);
10657 }
10658 } while (tmp != NULL);
10659 if ((stack != 0) && (res != NULL)) {
10660 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010661 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010662 stack);
10663 }
10664 if (ctxt->error != XPATH_EXPRESSION_OK) {
10665 xmlXPathFreeObject(res);
10666 res = NULL;
10667 }
10668
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010669
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010670 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010671 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010672#ifndef LIBXML_THREAD_ENABLED
10673 reentance--;
10674#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010675 return(res);
10676}
10677
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010678/**
10679 * xmlXPathEvalExpr:
10680 * @ctxt: the XPath Parser context
10681 *
10682 * Parse and evaluate an XPath expression in the given context,
10683 * then push the result on the context stack
10684 */
10685void
10686xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10687 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010688 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010689 xmlXPathRunEval(ctxt);
10690}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010691
10692/**
10693 * xmlXPathEval:
10694 * @str: the XPath expression
10695 * @ctx: the XPath context
10696 *
10697 * Evaluate the XPath Location Path in the given context.
10698 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010699 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010700 * the caller has to free the object.
10701 */
10702xmlXPathObjectPtr
10703xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10704 xmlXPathParserContextPtr ctxt;
10705 xmlXPathObjectPtr res, tmp, init = NULL;
10706 int stack = 0;
10707
10708 xmlXPathInit();
10709
10710 CHECK_CONTEXT(ctx)
10711
10712 ctxt = xmlXPathNewParserContext(str, ctx);
10713 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010714
10715 if (ctxt->value == NULL) {
10716 xmlGenericError(xmlGenericErrorContext,
10717 "xmlXPathEval: evaluation failed\n");
10718 res = NULL;
10719 } else if (*ctxt->cur != 0) {
10720 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10721 res = NULL;
10722 } else {
10723 res = valuePop(ctxt);
10724 }
10725
10726 do {
10727 tmp = valuePop(ctxt);
10728 if (tmp != NULL) {
10729 if (tmp != init)
10730 stack++;
10731 xmlXPathFreeObject(tmp);
10732 }
10733 } while (tmp != NULL);
10734 if ((stack != 0) && (res != NULL)) {
10735 xmlGenericError(xmlGenericErrorContext,
10736 "xmlXPathEval: %d object left on the stack\n",
10737 stack);
10738 }
10739 if (ctxt->error != XPATH_EXPRESSION_OK) {
10740 xmlXPathFreeObject(res);
10741 res = NULL;
10742 }
10743
Owen Taylor3473f882001-02-23 17:55:21 +000010744 xmlXPathFreeParserContext(ctxt);
10745 return(res);
10746}
10747
10748/**
10749 * xmlXPathEvalExpression:
10750 * @str: the XPath expression
10751 * @ctxt: the XPath context
10752 *
10753 * Evaluate the XPath expression in the given context.
10754 *
10755 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10756 * the caller has to free the object.
10757 */
10758xmlXPathObjectPtr
10759xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10760 xmlXPathParserContextPtr pctxt;
10761 xmlXPathObjectPtr res, tmp;
10762 int stack = 0;
10763
10764 xmlXPathInit();
10765
10766 CHECK_CONTEXT(ctxt)
10767
10768 pctxt = xmlXPathNewParserContext(str, ctxt);
10769 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010770
10771 if (*pctxt->cur != 0) {
10772 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10773 res = NULL;
10774 } else {
10775 res = valuePop(pctxt);
10776 }
10777 do {
10778 tmp = valuePop(pctxt);
10779 if (tmp != NULL) {
10780 xmlXPathFreeObject(tmp);
10781 stack++;
10782 }
10783 } while (tmp != NULL);
10784 if ((stack != 0) && (res != NULL)) {
10785 xmlGenericError(xmlGenericErrorContext,
10786 "xmlXPathEvalExpression: %d object left on the stack\n",
10787 stack);
10788 }
10789 xmlXPathFreeParserContext(pctxt);
10790 return(res);
10791}
10792
Daniel Veillard42766c02002-08-22 20:52:17 +000010793/************************************************************************
10794 * *
10795 * Extra functions not pertaining to the XPath spec *
10796 * *
10797 ************************************************************************/
10798/**
10799 * xmlXPathEscapeUriFunction:
10800 * @ctxt: the XPath Parser context
10801 * @nargs: the number of arguments
10802 *
10803 * Implement the escape-uri() XPath function
10804 * string escape-uri(string $str, bool $escape-reserved)
10805 *
10806 * This function applies the URI escaping rules defined in section 2 of [RFC
10807 * 2396] to the string supplied as $uri-part, which typically represents all
10808 * or part of a URI. The effect of the function is to replace any special
10809 * character in the string by an escape sequence of the form %xx%yy...,
10810 * where xxyy... is the hexadecimal representation of the octets used to
10811 * represent the character in UTF-8.
10812 *
10813 * The set of characters that are escaped depends on the setting of the
10814 * boolean argument $escape-reserved.
10815 *
10816 * If $escape-reserved is true, all characters are escaped other than lower
10817 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10818 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10819 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10820 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10821 * A-F).
10822 *
10823 * If $escape-reserved is false, the behavior differs in that characters
10824 * referred to in [RFC 2396] as reserved characters are not escaped. These
10825 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10826 *
10827 * [RFC 2396] does not define whether escaped URIs should use lower case or
10828 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10829 * compared using string comparison functions, this function must always use
10830 * the upper-case letters A-F.
10831 *
10832 * Generally, $escape-reserved should be set to true when escaping a string
10833 * that is to form a single part of a URI, and to false when escaping an
10834 * entire URI or URI reference.
10835 *
10836 * In the case of non-ascii characters, the string is encoded according to
10837 * utf-8 and then converted according to RFC 2396.
10838 *
10839 * Examples
10840 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10841 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10842 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10843 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10844 *
10845 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010846static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010847xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10848 xmlXPathObjectPtr str;
10849 int escape_reserved;
10850 xmlBufferPtr target;
10851 xmlChar *cptr;
10852 xmlChar escape[4];
10853
10854 CHECK_ARITY(2);
10855
10856 escape_reserved = xmlXPathPopBoolean(ctxt);
10857
10858 CAST_TO_STRING;
10859 str = valuePop(ctxt);
10860
10861 target = xmlBufferCreate();
10862
10863 escape[0] = '%';
10864 escape[3] = 0;
10865
10866 if (target) {
10867 for (cptr = str->stringval; *cptr; cptr++) {
10868 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10869 (*cptr >= 'a' && *cptr <= 'z') ||
10870 (*cptr >= '0' && *cptr <= '9') ||
10871 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10872 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10873 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10874 (*cptr == '%' &&
10875 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10876 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10877 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10878 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10879 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10880 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10881 (!escape_reserved &&
10882 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10883 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10884 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10885 *cptr == ','))) {
10886 xmlBufferAdd(target, cptr, 1);
10887 } else {
10888 if ((*cptr >> 4) < 10)
10889 escape[1] = '0' + (*cptr >> 4);
10890 else
10891 escape[1] = 'A' - 10 + (*cptr >> 4);
10892 if ((*cptr & 0xF) < 10)
10893 escape[2] = '0' + (*cptr & 0xF);
10894 else
10895 escape[2] = 'A' - 10 + (*cptr & 0xF);
10896
10897 xmlBufferAdd(target, &escape[0], 3);
10898 }
10899 }
10900 }
10901 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10902 xmlBufferFree(target);
10903 xmlXPathFreeObject(str);
10904}
10905
Owen Taylor3473f882001-02-23 17:55:21 +000010906/**
10907 * xmlXPathRegisterAllFunctions:
10908 * @ctxt: the XPath context
10909 *
10910 * Registers all default XPath functions in this context
10911 */
10912void
10913xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10914{
10915 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10916 xmlXPathBooleanFunction);
10917 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10918 xmlXPathCeilingFunction);
10919 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10920 xmlXPathCountFunction);
10921 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10922 xmlXPathConcatFunction);
10923 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10924 xmlXPathContainsFunction);
10925 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10926 xmlXPathIdFunction);
10927 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10928 xmlXPathFalseFunction);
10929 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10930 xmlXPathFloorFunction);
10931 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10932 xmlXPathLastFunction);
10933 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10934 xmlXPathLangFunction);
10935 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10936 xmlXPathLocalNameFunction);
10937 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10938 xmlXPathNotFunction);
10939 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10940 xmlXPathNameFunction);
10941 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10942 xmlXPathNamespaceURIFunction);
10943 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10944 xmlXPathNormalizeFunction);
10945 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10946 xmlXPathNumberFunction);
10947 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10948 xmlXPathPositionFunction);
10949 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10950 xmlXPathRoundFunction);
10951 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10952 xmlXPathStringFunction);
10953 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10954 xmlXPathStringLengthFunction);
10955 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10956 xmlXPathStartsWithFunction);
10957 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10958 xmlXPathSubstringFunction);
10959 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10960 xmlXPathSubstringBeforeFunction);
10961 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10962 xmlXPathSubstringAfterFunction);
10963 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10964 xmlXPathSumFunction);
10965 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10966 xmlXPathTrueFunction);
10967 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10968 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000010969
10970 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
10971 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
10972 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000010973}
10974
10975#endif /* LIBXML_XPATH_ENABLED */