blob: 6c68d754ed369d3f123d1190af98f41431e0292a [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
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000888/**
889 * valuePop:
890 * @ctxt: an XPath evaluation context
891 *
892 * Pops the top XPath object from the value stack
893 *
894 * Returns the XPath object just removed
895 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000896extern xmlXPathObjectPtr
897valuePop(xmlXPathParserContextPtr ctxt)
898{
899 xmlXPathObjectPtr ret;
900
901 if (ctxt->valueNr <= 0)
902 return (0);
903 ctxt->valueNr--;
904 if (ctxt->valueNr > 0)
905 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
906 else
907 ctxt->value = NULL;
908 ret = ctxt->valueTab[ctxt->valueNr];
909 ctxt->valueTab[ctxt->valueNr] = 0;
910 return (ret);
911}
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000912/**
913 * valuePush:
914 * @ctxt: an XPath evaluation context
915 * @value: the XPath object
916 *
917 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000918 *
919 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000920 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000921extern int
922valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
923{
924 if (ctxt->valueNr >= ctxt->valueMax) {
925 ctxt->valueMax *= 2;
926 ctxt->valueTab =
927 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
928 ctxt->valueMax *
929 sizeof(ctxt->valueTab[0]));
930 if (ctxt->valueTab == NULL) {
931 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
932 return (0);
933 }
934 }
935 ctxt->valueTab[ctxt->valueNr] = value;
936 ctxt->value = value;
937 return (ctxt->valueNr++);
938}
Owen Taylor3473f882001-02-23 17:55:21 +0000939
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
Daniel Veillard68e9e742002-11-16 15:35:11 +00001370#if 0
1371 Unfortunately this does not work. Line number in entities reset
1372 to 1 within the entity :-(
1373
Owen Taylor3473f882001-02-23 17:55:21 +00001374 /*
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001375 * Speedup using line numbers if availble.
1376 */
1377 if ((node1->type == XML_ELEMENT_NODE) &&
1378 (node2->type == XML_ELEMENT_NODE) &&
1379 (0 != (int) node1->content) && (0 != (int) node2->content)) {
1380 int l1, l2;
1381 l1 = (int) node1->content;
1382 l2 = (int) node2->content;
1383 if (l1 < l2)
1384 return(1);
1385 if (l1 > l2)
1386 return(-1);
1387 }
Daniel Veillard68e9e742002-11-16 15:35:11 +00001388#endif
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001389 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001390 * compute depth to root
1391 */
1392 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1393 if (cur == node1)
1394 return(1);
1395 depth2++;
1396 }
1397 root = cur;
1398 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1399 if (cur == node2)
1400 return(-1);
1401 depth1++;
1402 }
1403 /*
1404 * Distinct document (or distinct entities :-( ) case.
1405 */
1406 if (root != cur) {
1407 return(-2);
1408 }
1409 /*
1410 * get the nearest common ancestor.
1411 */
1412 while (depth1 > depth2) {
1413 depth1--;
1414 node1 = node1->parent;
1415 }
1416 while (depth2 > depth1) {
1417 depth2--;
1418 node2 = node2->parent;
1419 }
1420 while (node1->parent != node2->parent) {
1421 node1 = node1->parent;
1422 node2 = node2->parent;
1423 /* should not happen but just in case ... */
1424 if ((node1 == NULL) || (node2 == NULL))
1425 return(-2);
1426 }
1427 /*
1428 * Find who's first.
1429 */
1430 if (node1 == node2->next)
1431 return(-1);
1432 for (cur = node1->next;cur != NULL;cur = cur->next)
1433 if (cur == node2)
1434 return(1);
1435 return(-1); /* assume there is no sibling list corruption */
1436}
1437
1438/**
1439 * xmlXPathNodeSetSort:
1440 * @set: the node set
1441 *
1442 * Sort the node set in document order
1443 */
1444void
1445xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001446 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001447 xmlNodePtr tmp;
1448
1449 if (set == NULL)
1450 return;
1451
1452 /* Use Shell's sort to sort the node-set */
1453 len = set->nodeNr;
1454 for (incr = len / 2; incr > 0; incr /= 2) {
1455 for (i = incr; i < len; i++) {
1456 j = i - incr;
1457 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001458 if (xmlXPathCmpNodes(set->nodeTab[j],
1459 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001460 tmp = set->nodeTab[j];
1461 set->nodeTab[j] = set->nodeTab[j + incr];
1462 set->nodeTab[j + incr] = tmp;
1463 j -= incr;
1464 } else
1465 break;
1466 }
1467 }
1468 }
1469}
1470
1471#define XML_NODESET_DEFAULT 10
1472/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001473 * xmlXPathNodeSetDupNs:
1474 * @node: the parent node of the namespace XPath node
1475 * @ns: the libxml namespace declaration node.
1476 *
1477 * Namespace node in libxml don't match the XPath semantic. In a node set
1478 * the namespace nodes are duplicated and the next pointer is set to the
1479 * parent node in the XPath semantic.
1480 *
1481 * Returns the newly created object.
1482 */
1483static xmlNodePtr
1484xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1485 xmlNsPtr cur;
1486
1487 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1488 return(NULL);
1489 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1490 return((xmlNodePtr) ns);
1491
1492 /*
1493 * Allocate a new Namespace and fill the fields.
1494 */
1495 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1496 if (cur == NULL) {
1497 xmlGenericError(xmlGenericErrorContext,
1498 "xmlXPathNodeSetDupNs : malloc failed\n");
1499 return(NULL);
1500 }
1501 memset(cur, 0, sizeof(xmlNs));
1502 cur->type = XML_NAMESPACE_DECL;
1503 if (ns->href != NULL)
1504 cur->href = xmlStrdup(ns->href);
1505 if (ns->prefix != NULL)
1506 cur->prefix = xmlStrdup(ns->prefix);
1507 cur->next = (xmlNsPtr) node;
1508 return((xmlNodePtr) cur);
1509}
1510
1511/**
1512 * xmlXPathNodeSetFreeNs:
1513 * @ns: the XPath namespace node found in a nodeset.
1514 *
1515 * Namespace node in libxml don't match the XPath semantic. In a node set
1516 * the namespace nodes are duplicated and the next pointer is set to the
1517 * parent node in the XPath semantic. Check if such a node need to be freed
1518 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001519void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001520xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1521 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1522 return;
1523
1524 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1525 if (ns->href != NULL)
1526 xmlFree((xmlChar *)ns->href);
1527 if (ns->prefix != NULL)
1528 xmlFree((xmlChar *)ns->prefix);
1529 xmlFree(ns);
1530 }
1531}
1532
1533/**
Owen Taylor3473f882001-02-23 17:55:21 +00001534 * xmlXPathNodeSetCreate:
1535 * @val: an initial xmlNodePtr, or NULL
1536 *
1537 * Create a new xmlNodeSetPtr of type double and of value @val
1538 *
1539 * Returns the newly created object.
1540 */
1541xmlNodeSetPtr
1542xmlXPathNodeSetCreate(xmlNodePtr val) {
1543 xmlNodeSetPtr ret;
1544
1545 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1546 if (ret == NULL) {
1547 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001548 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001549 return(NULL);
1550 }
1551 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1552 if (val != NULL) {
1553 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1554 sizeof(xmlNodePtr));
1555 if (ret->nodeTab == NULL) {
1556 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001557 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001558 return(NULL);
1559 }
1560 memset(ret->nodeTab, 0 ,
1561 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1562 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001563 if (val->type == XML_NAMESPACE_DECL) {
1564 xmlNsPtr ns = (xmlNsPtr) val;
1565
1566 ret->nodeTab[ret->nodeNr++] =
1567 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1568 } else
1569 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001570 }
1571 return(ret);
1572}
1573
1574/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001575 * xmlXPathNodeSetContains:
1576 * @cur: the node-set
1577 * @val: the node
1578 *
1579 * checks whether @cur contains @val
1580 *
1581 * Returns true (1) if @cur contains @val, false (0) otherwise
1582 */
1583int
1584xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1585 int i;
1586
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001587 if (val->type == XML_NAMESPACE_DECL) {
1588 for (i = 0; i < cur->nodeNr; i++) {
1589 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1590 xmlNsPtr ns1, ns2;
1591
1592 ns1 = (xmlNsPtr) val;
1593 ns2 = (xmlNsPtr) cur->nodeTab[i];
1594 if (ns1 == ns2)
1595 return(1);
1596 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1597 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1598 return(1);
1599 }
1600 }
1601 } else {
1602 for (i = 0; i < cur->nodeNr; i++) {
1603 if (cur->nodeTab[i] == val)
1604 return(1);
1605 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001606 }
1607 return(0);
1608}
1609
1610/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001611 * xmlXPathNodeSetAddNs:
1612 * @cur: the initial node set
1613 * @node: the hosting node
1614 * @ns: a the namespace node
1615 *
1616 * add a new namespace node to an existing NodeSet
1617 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001618void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001619xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1620 int i;
1621
1622 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1623 (node->type != XML_ELEMENT_NODE))
1624 return;
1625
1626 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1627 /*
1628 * check against doublons
1629 */
1630 for (i = 0;i < cur->nodeNr;i++) {
1631 if ((cur->nodeTab[i] != NULL) &&
1632 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001633 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001634 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1635 return;
1636 }
1637
1638 /*
1639 * grow the nodeTab if needed
1640 */
1641 if (cur->nodeMax == 0) {
1642 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1643 sizeof(xmlNodePtr));
1644 if (cur->nodeTab == NULL) {
1645 xmlGenericError(xmlGenericErrorContext,
1646 "xmlXPathNodeSetAdd: out of memory\n");
1647 return;
1648 }
1649 memset(cur->nodeTab, 0 ,
1650 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1651 cur->nodeMax = XML_NODESET_DEFAULT;
1652 } else if (cur->nodeNr == cur->nodeMax) {
1653 xmlNodePtr *temp;
1654
1655 cur->nodeMax *= 2;
1656 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1657 sizeof(xmlNodePtr));
1658 if (temp == NULL) {
1659 xmlGenericError(xmlGenericErrorContext,
1660 "xmlXPathNodeSetAdd: out of memory\n");
1661 return;
1662 }
1663 cur->nodeTab = temp;
1664 }
1665 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1666}
1667
1668/**
Owen Taylor3473f882001-02-23 17:55:21 +00001669 * xmlXPathNodeSetAdd:
1670 * @cur: the initial node set
1671 * @val: a new xmlNodePtr
1672 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001673 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001674 */
1675void
1676xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1677 int i;
1678
1679 if (val == NULL) return;
1680
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001681 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001682 /*
1683 * check against doublons
1684 */
1685 for (i = 0;i < cur->nodeNr;i++)
1686 if (cur->nodeTab[i] == val) return;
1687
1688 /*
1689 * grow the nodeTab if needed
1690 */
1691 if (cur->nodeMax == 0) {
1692 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1693 sizeof(xmlNodePtr));
1694 if (cur->nodeTab == NULL) {
1695 xmlGenericError(xmlGenericErrorContext,
1696 "xmlXPathNodeSetAdd: out of memory\n");
1697 return;
1698 }
1699 memset(cur->nodeTab, 0 ,
1700 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1701 cur->nodeMax = XML_NODESET_DEFAULT;
1702 } else if (cur->nodeNr == cur->nodeMax) {
1703 xmlNodePtr *temp;
1704
1705 cur->nodeMax *= 2;
1706 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1707 sizeof(xmlNodePtr));
1708 if (temp == NULL) {
1709 xmlGenericError(xmlGenericErrorContext,
1710 "xmlXPathNodeSetAdd: out of memory\n");
1711 return;
1712 }
1713 cur->nodeTab = temp;
1714 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001715 if (val->type == XML_NAMESPACE_DECL) {
1716 xmlNsPtr ns = (xmlNsPtr) val;
1717
1718 cur->nodeTab[cur->nodeNr++] =
1719 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1720 } else
1721 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001722}
1723
1724/**
1725 * xmlXPathNodeSetAddUnique:
1726 * @cur: the initial node set
1727 * @val: a new xmlNodePtr
1728 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001729 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001730 * when we are sure the node is not already in the set.
1731 */
1732void
1733xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1734 if (val == NULL) return;
1735
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001736 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001737 /*
1738 * grow the nodeTab if needed
1739 */
1740 if (cur->nodeMax == 0) {
1741 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1742 sizeof(xmlNodePtr));
1743 if (cur->nodeTab == NULL) {
1744 xmlGenericError(xmlGenericErrorContext,
1745 "xmlXPathNodeSetAddUnique: out of memory\n");
1746 return;
1747 }
1748 memset(cur->nodeTab, 0 ,
1749 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1750 cur->nodeMax = XML_NODESET_DEFAULT;
1751 } else if (cur->nodeNr == cur->nodeMax) {
1752 xmlNodePtr *temp;
1753
1754 cur->nodeMax *= 2;
1755 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1756 sizeof(xmlNodePtr));
1757 if (temp == NULL) {
1758 xmlGenericError(xmlGenericErrorContext,
1759 "xmlXPathNodeSetAddUnique: out of memory\n");
1760 return;
1761 }
1762 cur->nodeTab = temp;
1763 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001764 if (val->type == XML_NAMESPACE_DECL) {
1765 xmlNsPtr ns = (xmlNsPtr) val;
1766
1767 cur->nodeTab[cur->nodeNr++] =
1768 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1769 } else
1770 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001771}
1772
1773/**
1774 * xmlXPathNodeSetMerge:
1775 * @val1: the first NodeSet or NULL
1776 * @val2: the second NodeSet
1777 *
1778 * Merges two nodesets, all nodes from @val2 are added to @val1
1779 * if @val1 is NULL, a new set is created and copied from @val2
1780 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001781 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001782 */
1783xmlNodeSetPtr
1784xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001785 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001786
1787 if (val2 == NULL) return(val1);
1788 if (val1 == NULL) {
1789 val1 = xmlXPathNodeSetCreate(NULL);
1790 }
1791
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001792 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001793 initNr = val1->nodeNr;
1794
1795 for (i = 0;i < val2->nodeNr;i++) {
1796 /*
1797 * check against doublons
1798 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001799 skip = 0;
1800 for (j = 0; j < initNr; j++) {
1801 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1802 skip = 1;
1803 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001804 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1805 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1806 xmlNsPtr ns1, ns2;
1807 ns1 = (xmlNsPtr) val1->nodeTab[j];
1808 ns2 = (xmlNsPtr) val2->nodeTab[i];
1809 if ((ns1->next == ns2->next) &&
1810 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1811 skip = 1;
1812 break;
1813 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001814 }
1815 }
1816 if (skip)
1817 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001818
1819 /*
1820 * grow the nodeTab if needed
1821 */
1822 if (val1->nodeMax == 0) {
1823 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1824 sizeof(xmlNodePtr));
1825 if (val1->nodeTab == NULL) {
1826 xmlGenericError(xmlGenericErrorContext,
1827 "xmlXPathNodeSetMerge: out of memory\n");
1828 return(NULL);
1829 }
1830 memset(val1->nodeTab, 0 ,
1831 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1832 val1->nodeMax = XML_NODESET_DEFAULT;
1833 } else if (val1->nodeNr == val1->nodeMax) {
1834 xmlNodePtr *temp;
1835
1836 val1->nodeMax *= 2;
1837 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1838 sizeof(xmlNodePtr));
1839 if (temp == NULL) {
1840 xmlGenericError(xmlGenericErrorContext,
1841 "xmlXPathNodeSetMerge: out of memory\n");
1842 return(NULL);
1843 }
1844 val1->nodeTab = temp;
1845 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001846 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1847 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1848
1849 val1->nodeTab[val1->nodeNr++] =
1850 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1851 } else
1852 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001853 }
1854
1855 return(val1);
1856}
1857
1858/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001859 * xmlXPathNodeSetMergeUnique:
1860 * @val1: the first NodeSet or NULL
1861 * @val2: the second NodeSet
1862 *
1863 * Merges two nodesets, all nodes from @val2 are added to @val1
1864 * if @val1 is NULL, a new set is created and copied from @val2
1865 *
1866 * Returns @val1 once extended or NULL in case of error.
1867 */
1868static xmlNodeSetPtr
1869xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1870 int i, initNr;
1871
1872 if (val2 == NULL) return(val1);
1873 if (val1 == NULL) {
1874 val1 = xmlXPathNodeSetCreate(NULL);
1875 }
1876
1877 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1878 initNr = val1->nodeNr;
1879
1880 for (i = 0;i < val2->nodeNr;i++) {
1881 /*
1882 * grow the nodeTab if needed
1883 */
1884 if (val1->nodeMax == 0) {
1885 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1886 sizeof(xmlNodePtr));
1887 if (val1->nodeTab == NULL) {
1888 xmlGenericError(xmlGenericErrorContext,
1889 "xmlXPathNodeSetMerge: out of memory\n");
1890 return(NULL);
1891 }
1892 memset(val1->nodeTab, 0 ,
1893 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1894 val1->nodeMax = XML_NODESET_DEFAULT;
1895 } else if (val1->nodeNr == val1->nodeMax) {
1896 xmlNodePtr *temp;
1897
1898 val1->nodeMax *= 2;
1899 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1900 sizeof(xmlNodePtr));
1901 if (temp == NULL) {
1902 xmlGenericError(xmlGenericErrorContext,
1903 "xmlXPathNodeSetMerge: out of memory\n");
1904 return(NULL);
1905 }
1906 val1->nodeTab = temp;
1907 }
1908 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1909 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1910
1911 val1->nodeTab[val1->nodeNr++] =
1912 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1913 } else
1914 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1915 }
1916
1917 return(val1);
1918}
1919
1920/**
Owen Taylor3473f882001-02-23 17:55:21 +00001921 * xmlXPathNodeSetDel:
1922 * @cur: the initial node set
1923 * @val: an xmlNodePtr
1924 *
1925 * Removes an xmlNodePtr from an existing NodeSet
1926 */
1927void
1928xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1929 int i;
1930
1931 if (cur == NULL) return;
1932 if (val == NULL) return;
1933
1934 /*
1935 * check against doublons
1936 */
1937 for (i = 0;i < cur->nodeNr;i++)
1938 if (cur->nodeTab[i] == val) break;
1939
1940 if (i >= cur->nodeNr) {
1941#ifdef DEBUG
1942 xmlGenericError(xmlGenericErrorContext,
1943 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1944 val->name);
1945#endif
1946 return;
1947 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001948 if ((cur->nodeTab[i] != NULL) &&
1949 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1950 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001951 cur->nodeNr--;
1952 for (;i < cur->nodeNr;i++)
1953 cur->nodeTab[i] = cur->nodeTab[i + 1];
1954 cur->nodeTab[cur->nodeNr] = NULL;
1955}
1956
1957/**
1958 * xmlXPathNodeSetRemove:
1959 * @cur: the initial node set
1960 * @val: the index to remove
1961 *
1962 * Removes an entry from an existing NodeSet list.
1963 */
1964void
1965xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1966 if (cur == NULL) return;
1967 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001968 if ((cur->nodeTab[val] != NULL) &&
1969 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1970 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001971 cur->nodeNr--;
1972 for (;val < cur->nodeNr;val++)
1973 cur->nodeTab[val] = cur->nodeTab[val + 1];
1974 cur->nodeTab[cur->nodeNr] = NULL;
1975}
1976
1977/**
1978 * xmlXPathFreeNodeSet:
1979 * @obj: the xmlNodeSetPtr to free
1980 *
1981 * Free the NodeSet compound (not the actual nodes !).
1982 */
1983void
1984xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1985 if (obj == NULL) return;
1986 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001987 int i;
1988
1989 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1990 for (i = 0;i < obj->nodeNr;i++)
1991 if ((obj->nodeTab[i] != NULL) &&
1992 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1993 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001994 xmlFree(obj->nodeTab);
1995 }
Owen Taylor3473f882001-02-23 17:55:21 +00001996 xmlFree(obj);
1997}
1998
1999/**
2000 * xmlXPathFreeValueTree:
2001 * @obj: the xmlNodeSetPtr to free
2002 *
2003 * Free the NodeSet compound and the actual tree, this is different
2004 * from xmlXPathFreeNodeSet()
2005 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002006static void
Owen Taylor3473f882001-02-23 17:55:21 +00002007xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2008 int i;
2009
2010 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002011
2012 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002013 for (i = 0;i < obj->nodeNr;i++) {
2014 if (obj->nodeTab[i] != NULL) {
2015 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2016 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2017 } else {
2018 xmlFreeNodeList(obj->nodeTab[i]);
2019 }
2020 }
2021 }
Owen Taylor3473f882001-02-23 17:55:21 +00002022 xmlFree(obj->nodeTab);
2023 }
Owen Taylor3473f882001-02-23 17:55:21 +00002024 xmlFree(obj);
2025}
2026
2027#if defined(DEBUG) || defined(DEBUG_STEP)
2028/**
2029 * xmlGenericErrorContextNodeSet:
2030 * @output: a FILE * for the output
2031 * @obj: the xmlNodeSetPtr to free
2032 *
2033 * Quick display of a NodeSet
2034 */
2035void
2036xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2037 int i;
2038
2039 if (output == NULL) output = xmlGenericErrorContext;
2040 if (obj == NULL) {
2041 fprintf(output, "NodeSet == NULL !\n");
2042 return;
2043 }
2044 if (obj->nodeNr == 0) {
2045 fprintf(output, "NodeSet is empty\n");
2046 return;
2047 }
2048 if (obj->nodeTab == NULL) {
2049 fprintf(output, " nodeTab == NULL !\n");
2050 return;
2051 }
2052 for (i = 0; i < obj->nodeNr; i++) {
2053 if (obj->nodeTab[i] == NULL) {
2054 fprintf(output, " NULL !\n");
2055 return;
2056 }
2057 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2058 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2059 fprintf(output, " /");
2060 else if (obj->nodeTab[i]->name == NULL)
2061 fprintf(output, " noname!");
2062 else fprintf(output, " %s", obj->nodeTab[i]->name);
2063 }
2064 fprintf(output, "\n");
2065}
2066#endif
2067
2068/**
2069 * xmlXPathNewNodeSet:
2070 * @val: the NodePtr value
2071 *
2072 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2073 * it with the single Node @val
2074 *
2075 * Returns the newly created object.
2076 */
2077xmlXPathObjectPtr
2078xmlXPathNewNodeSet(xmlNodePtr val) {
2079 xmlXPathObjectPtr ret;
2080
2081 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2082 if (ret == NULL) {
2083 xmlGenericError(xmlGenericErrorContext,
2084 "xmlXPathNewNodeSet: out of memory\n");
2085 return(NULL);
2086 }
2087 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2088 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002089 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002090 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002091 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002092 return(ret);
2093}
2094
2095/**
2096 * xmlXPathNewValueTree:
2097 * @val: the NodePtr value
2098 *
2099 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2100 * it with the tree root @val
2101 *
2102 * Returns the newly created object.
2103 */
2104xmlXPathObjectPtr
2105xmlXPathNewValueTree(xmlNodePtr val) {
2106 xmlXPathObjectPtr ret;
2107
2108 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2109 if (ret == NULL) {
2110 xmlGenericError(xmlGenericErrorContext,
2111 "xmlXPathNewNodeSet: out of memory\n");
2112 return(NULL);
2113 }
2114 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2115 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002116 ret->boolval = 1;
2117 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002118 ret->nodesetval = xmlXPathNodeSetCreate(val);
2119 return(ret);
2120}
2121
2122/**
2123 * xmlXPathNewNodeSetList:
2124 * @val: an existing NodeSet
2125 *
2126 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2127 * it with the Nodeset @val
2128 *
2129 * Returns the newly created object.
2130 */
2131xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002132xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2133{
Owen Taylor3473f882001-02-23 17:55:21 +00002134 xmlXPathObjectPtr ret;
2135 int i;
2136
2137 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002138 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002139 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002140 ret = xmlXPathNewNodeSet(NULL);
2141 else {
2142 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2143 for (i = 1; i < val->nodeNr; ++i)
2144 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2145 }
Owen Taylor3473f882001-02-23 17:55:21 +00002146
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002147 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002148}
2149
2150/**
2151 * xmlXPathWrapNodeSet:
2152 * @val: the NodePtr value
2153 *
2154 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2155 *
2156 * Returns the newly created object.
2157 */
2158xmlXPathObjectPtr
2159xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2160 xmlXPathObjectPtr ret;
2161
2162 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2163 if (ret == NULL) {
2164 xmlGenericError(xmlGenericErrorContext,
2165 "xmlXPathWrapNodeSet: out of memory\n");
2166 return(NULL);
2167 }
2168 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2169 ret->type = XPATH_NODESET;
2170 ret->nodesetval = val;
2171 return(ret);
2172}
2173
2174/**
2175 * xmlXPathFreeNodeSetList:
2176 * @obj: an existing NodeSetList object
2177 *
2178 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2179 * the list contrary to xmlXPathFreeObject().
2180 */
2181void
2182xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2183 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002184 xmlFree(obj);
2185}
2186
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002187/**
2188 * xmlXPathDifference:
2189 * @nodes1: a node-set
2190 * @nodes2: a node-set
2191 *
2192 * Implements the EXSLT - Sets difference() function:
2193 * node-set set:difference (node-set, node-set)
2194 *
2195 * Returns the difference between the two node sets, or nodes1 if
2196 * nodes2 is empty
2197 */
2198xmlNodeSetPtr
2199xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2200 xmlNodeSetPtr ret;
2201 int i, l1;
2202 xmlNodePtr cur;
2203
2204 if (xmlXPathNodeSetIsEmpty(nodes2))
2205 return(nodes1);
2206
2207 ret = xmlXPathNodeSetCreate(NULL);
2208 if (xmlXPathNodeSetIsEmpty(nodes1))
2209 return(ret);
2210
2211 l1 = xmlXPathNodeSetGetLength(nodes1);
2212
2213 for (i = 0; i < l1; i++) {
2214 cur = xmlXPathNodeSetItem(nodes1, i);
2215 if (!xmlXPathNodeSetContains(nodes2, cur))
2216 xmlXPathNodeSetAddUnique(ret, cur);
2217 }
2218 return(ret);
2219}
2220
2221/**
2222 * xmlXPathIntersection:
2223 * @nodes1: a node-set
2224 * @nodes2: a node-set
2225 *
2226 * Implements the EXSLT - Sets intersection() function:
2227 * node-set set:intersection (node-set, node-set)
2228 *
2229 * Returns a node set comprising the nodes that are within both the
2230 * node sets passed as arguments
2231 */
2232xmlNodeSetPtr
2233xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2234 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2235 int i, l1;
2236 xmlNodePtr cur;
2237
2238 if (xmlXPathNodeSetIsEmpty(nodes1))
2239 return(ret);
2240 if (xmlXPathNodeSetIsEmpty(nodes2))
2241 return(ret);
2242
2243 l1 = xmlXPathNodeSetGetLength(nodes1);
2244
2245 for (i = 0; i < l1; i++) {
2246 cur = xmlXPathNodeSetItem(nodes1, i);
2247 if (xmlXPathNodeSetContains(nodes2, cur))
2248 xmlXPathNodeSetAddUnique(ret, cur);
2249 }
2250 return(ret);
2251}
2252
2253/**
2254 * xmlXPathDistinctSorted:
2255 * @nodes: a node-set, sorted by document order
2256 *
2257 * Implements the EXSLT - Sets distinct() function:
2258 * node-set set:distinct (node-set)
2259 *
2260 * Returns a subset of the nodes contained in @nodes, or @nodes if
2261 * it is empty
2262 */
2263xmlNodeSetPtr
2264xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2265 xmlNodeSetPtr ret;
2266 xmlHashTablePtr hash;
2267 int i, l;
2268 xmlChar * strval;
2269 xmlNodePtr cur;
2270
2271 if (xmlXPathNodeSetIsEmpty(nodes))
2272 return(nodes);
2273
2274 ret = xmlXPathNodeSetCreate(NULL);
2275 l = xmlXPathNodeSetGetLength(nodes);
2276 hash = xmlHashCreate (l);
2277 for (i = 0; i < l; i++) {
2278 cur = xmlXPathNodeSetItem(nodes, i);
2279 strval = xmlXPathCastNodeToString(cur);
2280 if (xmlHashLookup(hash, strval) == NULL) {
2281 xmlHashAddEntry(hash, strval, strval);
2282 xmlXPathNodeSetAddUnique(ret, cur);
2283 } else {
2284 xmlFree(strval);
2285 }
2286 }
2287 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2288 return(ret);
2289}
2290
2291/**
2292 * xmlXPathDistinct:
2293 * @nodes: a node-set
2294 *
2295 * Implements the EXSLT - Sets distinct() function:
2296 * node-set set:distinct (node-set)
2297 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2298 * is called with the sorted node-set
2299 *
2300 * Returns a subset of the nodes contained in @nodes, or @nodes if
2301 * it is empty
2302 */
2303xmlNodeSetPtr
2304xmlXPathDistinct (xmlNodeSetPtr nodes) {
2305 if (xmlXPathNodeSetIsEmpty(nodes))
2306 return(nodes);
2307
2308 xmlXPathNodeSetSort(nodes);
2309 return(xmlXPathDistinctSorted(nodes));
2310}
2311
2312/**
2313 * xmlXPathHasSameNodes:
2314 * @nodes1: a node-set
2315 * @nodes2: a node-set
2316 *
2317 * Implements the EXSLT - Sets has-same-nodes function:
2318 * boolean set:has-same-node(node-set, node-set)
2319 *
2320 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2321 * otherwise
2322 */
2323int
2324xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2325 int i, l;
2326 xmlNodePtr cur;
2327
2328 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2329 xmlXPathNodeSetIsEmpty(nodes2))
2330 return(0);
2331
2332 l = xmlXPathNodeSetGetLength(nodes1);
2333 for (i = 0; i < l; i++) {
2334 cur = xmlXPathNodeSetItem(nodes1, i);
2335 if (xmlXPathNodeSetContains(nodes2, cur))
2336 return(1);
2337 }
2338 return(0);
2339}
2340
2341/**
2342 * xmlXPathNodeLeadingSorted:
2343 * @nodes: a node-set, sorted by document order
2344 * @node: a node
2345 *
2346 * Implements the EXSLT - Sets leading() function:
2347 * node-set set:leading (node-set, node-set)
2348 *
2349 * Returns the nodes in @nodes that precede @node in document order,
2350 * @nodes if @node is NULL or an empty node-set if @nodes
2351 * doesn't contain @node
2352 */
2353xmlNodeSetPtr
2354xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2355 int i, l;
2356 xmlNodePtr cur;
2357 xmlNodeSetPtr ret;
2358
2359 if (node == NULL)
2360 return(nodes);
2361
2362 ret = xmlXPathNodeSetCreate(NULL);
2363 if (xmlXPathNodeSetIsEmpty(nodes) ||
2364 (!xmlXPathNodeSetContains(nodes, node)))
2365 return(ret);
2366
2367 l = xmlXPathNodeSetGetLength(nodes);
2368 for (i = 0; i < l; i++) {
2369 cur = xmlXPathNodeSetItem(nodes, i);
2370 if (cur == node)
2371 break;
2372 xmlXPathNodeSetAddUnique(ret, cur);
2373 }
2374 return(ret);
2375}
2376
2377/**
2378 * xmlXPathNodeLeading:
2379 * @nodes: a node-set
2380 * @node: a node
2381 *
2382 * Implements the EXSLT - Sets leading() function:
2383 * node-set set:leading (node-set, node-set)
2384 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2385 * is called.
2386 *
2387 * Returns the nodes in @nodes that precede @node in document order,
2388 * @nodes if @node is NULL or an empty node-set if @nodes
2389 * doesn't contain @node
2390 */
2391xmlNodeSetPtr
2392xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2393 xmlXPathNodeSetSort(nodes);
2394 return(xmlXPathNodeLeadingSorted(nodes, node));
2395}
2396
2397/**
2398 * xmlXPathLeadingSorted:
2399 * @nodes1: a node-set, sorted by document order
2400 * @nodes2: a node-set, sorted by document order
2401 *
2402 * Implements the EXSLT - Sets leading() function:
2403 * node-set set:leading (node-set, node-set)
2404 *
2405 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2406 * in document order, @nodes1 if @nodes2 is NULL or empty or
2407 * an empty node-set if @nodes1 doesn't contain @nodes2
2408 */
2409xmlNodeSetPtr
2410xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2411 if (xmlXPathNodeSetIsEmpty(nodes2))
2412 return(nodes1);
2413 return(xmlXPathNodeLeadingSorted(nodes1,
2414 xmlXPathNodeSetItem(nodes2, 1)));
2415}
2416
2417/**
2418 * xmlXPathLeading:
2419 * @nodes1: a node-set
2420 * @nodes2: a node-set
2421 *
2422 * Implements the EXSLT - Sets leading() function:
2423 * node-set set:leading (node-set, node-set)
2424 * @nodes1 and @nodes2 are sorted by document order, then
2425 * #exslSetsLeadingSorted is called.
2426 *
2427 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2428 * in document order, @nodes1 if @nodes2 is NULL or empty or
2429 * an empty node-set if @nodes1 doesn't contain @nodes2
2430 */
2431xmlNodeSetPtr
2432xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2433 if (xmlXPathNodeSetIsEmpty(nodes2))
2434 return(nodes1);
2435 if (xmlXPathNodeSetIsEmpty(nodes1))
2436 return(xmlXPathNodeSetCreate(NULL));
2437 xmlXPathNodeSetSort(nodes1);
2438 xmlXPathNodeSetSort(nodes2);
2439 return(xmlXPathNodeLeadingSorted(nodes1,
2440 xmlXPathNodeSetItem(nodes2, 1)));
2441}
2442
2443/**
2444 * xmlXPathNodeTrailingSorted:
2445 * @nodes: a node-set, sorted by document order
2446 * @node: a node
2447 *
2448 * Implements the EXSLT - Sets trailing() function:
2449 * node-set set:trailing (node-set, node-set)
2450 *
2451 * Returns the nodes in @nodes that follow @node in document order,
2452 * @nodes if @node is NULL or an empty node-set if @nodes
2453 * doesn't contain @node
2454 */
2455xmlNodeSetPtr
2456xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2457 int i, l;
2458 xmlNodePtr cur;
2459 xmlNodeSetPtr ret;
2460
2461 if (node == NULL)
2462 return(nodes);
2463
2464 ret = xmlXPathNodeSetCreate(NULL);
2465 if (xmlXPathNodeSetIsEmpty(nodes) ||
2466 (!xmlXPathNodeSetContains(nodes, node)))
2467 return(ret);
2468
2469 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002470 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002471 cur = xmlXPathNodeSetItem(nodes, i);
2472 if (cur == node)
2473 break;
2474 xmlXPathNodeSetAddUnique(ret, cur);
2475 }
2476 return(ret);
2477}
2478
2479/**
2480 * xmlXPathNodeTrailing:
2481 * @nodes: a node-set
2482 * @node: a node
2483 *
2484 * Implements the EXSLT - Sets trailing() function:
2485 * node-set set:trailing (node-set, node-set)
2486 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2487 * is called.
2488 *
2489 * Returns the nodes in @nodes that follow @node in document order,
2490 * @nodes if @node is NULL or an empty node-set if @nodes
2491 * doesn't contain @node
2492 */
2493xmlNodeSetPtr
2494xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2495 xmlXPathNodeSetSort(nodes);
2496 return(xmlXPathNodeTrailingSorted(nodes, node));
2497}
2498
2499/**
2500 * xmlXPathTrailingSorted:
2501 * @nodes1: a node-set, sorted by document order
2502 * @nodes2: a node-set, sorted by document order
2503 *
2504 * Implements the EXSLT - Sets trailing() function:
2505 * node-set set:trailing (node-set, node-set)
2506 *
2507 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2508 * in document order, @nodes1 if @nodes2 is NULL or empty or
2509 * an empty node-set if @nodes1 doesn't contain @nodes2
2510 */
2511xmlNodeSetPtr
2512xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2513 if (xmlXPathNodeSetIsEmpty(nodes2))
2514 return(nodes1);
2515 return(xmlXPathNodeTrailingSorted(nodes1,
2516 xmlXPathNodeSetItem(nodes2, 0)));
2517}
2518
2519/**
2520 * xmlXPathTrailing:
2521 * @nodes1: a node-set
2522 * @nodes2: a node-set
2523 *
2524 * Implements the EXSLT - Sets trailing() function:
2525 * node-set set:trailing (node-set, node-set)
2526 * @nodes1 and @nodes2 are sorted by document order, then
2527 * #xmlXPathTrailingSorted is called.
2528 *
2529 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2530 * in document order, @nodes1 if @nodes2 is NULL or empty or
2531 * an empty node-set if @nodes1 doesn't contain @nodes2
2532 */
2533xmlNodeSetPtr
2534xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2535 if (xmlXPathNodeSetIsEmpty(nodes2))
2536 return(nodes1);
2537 if (xmlXPathNodeSetIsEmpty(nodes1))
2538 return(xmlXPathNodeSetCreate(NULL));
2539 xmlXPathNodeSetSort(nodes1);
2540 xmlXPathNodeSetSort(nodes2);
2541 return(xmlXPathNodeTrailingSorted(nodes1,
2542 xmlXPathNodeSetItem(nodes2, 0)));
2543}
2544
Owen Taylor3473f882001-02-23 17:55:21 +00002545/************************************************************************
2546 * *
2547 * Routines to handle extra functions *
2548 * *
2549 ************************************************************************/
2550
2551/**
2552 * xmlXPathRegisterFunc:
2553 * @ctxt: the XPath context
2554 * @name: the function name
2555 * @f: the function implementation or NULL
2556 *
2557 * Register a new function. If @f is NULL it unregisters the function
2558 *
2559 * Returns 0 in case of success, -1 in case of error
2560 */
2561int
2562xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2563 xmlXPathFunction f) {
2564 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2565}
2566
2567/**
2568 * xmlXPathRegisterFuncNS:
2569 * @ctxt: the XPath context
2570 * @name: the function name
2571 * @ns_uri: the function namespace URI
2572 * @f: the function implementation or NULL
2573 *
2574 * Register a new function. If @f is NULL it unregisters the function
2575 *
2576 * Returns 0 in case of success, -1 in case of error
2577 */
2578int
2579xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2580 const xmlChar *ns_uri, xmlXPathFunction f) {
2581 if (ctxt == NULL)
2582 return(-1);
2583 if (name == NULL)
2584 return(-1);
2585
2586 if (ctxt->funcHash == NULL)
2587 ctxt->funcHash = xmlHashCreate(0);
2588 if (ctxt->funcHash == NULL)
2589 return(-1);
2590 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2591}
2592
2593/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002594 * xmlXPathRegisterFuncLookup:
2595 * @ctxt: the XPath context
2596 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002597 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002598 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002599 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002600 */
2601void
2602xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2603 xmlXPathFuncLookupFunc f,
2604 void *funcCtxt) {
2605 if (ctxt == NULL)
2606 return;
2607 ctxt->funcLookupFunc = (void *) f;
2608 ctxt->funcLookupData = funcCtxt;
2609}
2610
2611/**
Owen Taylor3473f882001-02-23 17:55:21 +00002612 * xmlXPathFunctionLookup:
2613 * @ctxt: the XPath context
2614 * @name: the function name
2615 *
2616 * Search in the Function array of the context for the given
2617 * function.
2618 *
2619 * Returns the xmlXPathFunction or NULL if not found
2620 */
2621xmlXPathFunction
2622xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002623 if (ctxt == NULL)
2624 return (NULL);
2625
2626 if (ctxt->funcLookupFunc != NULL) {
2627 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002628 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002629
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002630 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002631 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002632 if (ret != NULL)
2633 return(ret);
2634 }
Owen Taylor3473f882001-02-23 17:55:21 +00002635 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2636}
2637
2638/**
2639 * xmlXPathFunctionLookupNS:
2640 * @ctxt: the XPath context
2641 * @name: the function name
2642 * @ns_uri: the function namespace URI
2643 *
2644 * Search in the Function array of the context for the given
2645 * function.
2646 *
2647 * Returns the xmlXPathFunction or NULL if not found
2648 */
2649xmlXPathFunction
2650xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2651 const xmlChar *ns_uri) {
2652 if (ctxt == NULL)
2653 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002654 if (name == NULL)
2655 return(NULL);
2656
Thomas Broyerba4ad322001-07-26 16:55:21 +00002657 if (ctxt->funcLookupFunc != NULL) {
2658 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002659 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002660
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002661 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002662 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002663 if (ret != NULL)
2664 return(ret);
2665 }
2666
2667 if (ctxt->funcHash == NULL)
2668 return(NULL);
2669
Owen Taylor3473f882001-02-23 17:55:21 +00002670 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2671}
2672
2673/**
2674 * xmlXPathRegisteredFuncsCleanup:
2675 * @ctxt: the XPath context
2676 *
2677 * Cleanup the XPath context data associated to registered functions
2678 */
2679void
2680xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2681 if (ctxt == NULL)
2682 return;
2683
2684 xmlHashFree(ctxt->funcHash, NULL);
2685 ctxt->funcHash = NULL;
2686}
2687
2688/************************************************************************
2689 * *
2690 * Routines to handle Variable *
2691 * *
2692 ************************************************************************/
2693
2694/**
2695 * xmlXPathRegisterVariable:
2696 * @ctxt: the XPath context
2697 * @name: the variable name
2698 * @value: the variable value or NULL
2699 *
2700 * Register a new variable value. If @value is NULL it unregisters
2701 * the variable
2702 *
2703 * Returns 0 in case of success, -1 in case of error
2704 */
2705int
2706xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2707 xmlXPathObjectPtr value) {
2708 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2709}
2710
2711/**
2712 * xmlXPathRegisterVariableNS:
2713 * @ctxt: the XPath context
2714 * @name: the variable name
2715 * @ns_uri: the variable namespace URI
2716 * @value: the variable value or NULL
2717 *
2718 * Register a new variable value. If @value is NULL it unregisters
2719 * the variable
2720 *
2721 * Returns 0 in case of success, -1 in case of error
2722 */
2723int
2724xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2725 const xmlChar *ns_uri,
2726 xmlXPathObjectPtr value) {
2727 if (ctxt == NULL)
2728 return(-1);
2729 if (name == NULL)
2730 return(-1);
2731
2732 if (ctxt->varHash == NULL)
2733 ctxt->varHash = xmlHashCreate(0);
2734 if (ctxt->varHash == NULL)
2735 return(-1);
2736 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2737 (void *) value,
2738 (xmlHashDeallocator)xmlXPathFreeObject));
2739}
2740
2741/**
2742 * xmlXPathRegisterVariableLookup:
2743 * @ctxt: the XPath context
2744 * @f: the lookup function
2745 * @data: the lookup data
2746 *
2747 * register an external mechanism to do variable lookup
2748 */
2749void
2750xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2751 xmlXPathVariableLookupFunc f, void *data) {
2752 if (ctxt == NULL)
2753 return;
2754 ctxt->varLookupFunc = (void *) f;
2755 ctxt->varLookupData = data;
2756}
2757
2758/**
2759 * xmlXPathVariableLookup:
2760 * @ctxt: the XPath context
2761 * @name: the variable name
2762 *
2763 * Search in the Variable array of the context for the given
2764 * variable value.
2765 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002766 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002767 */
2768xmlXPathObjectPtr
2769xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2770 if (ctxt == NULL)
2771 return(NULL);
2772
2773 if (ctxt->varLookupFunc != NULL) {
2774 xmlXPathObjectPtr ret;
2775
2776 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2777 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002778 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002779 }
2780 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2781}
2782
2783/**
2784 * xmlXPathVariableLookupNS:
2785 * @ctxt: the XPath context
2786 * @name: the variable name
2787 * @ns_uri: the variable namespace URI
2788 *
2789 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002790 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002791 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002792 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002793 */
2794xmlXPathObjectPtr
2795xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2796 const xmlChar *ns_uri) {
2797 if (ctxt == NULL)
2798 return(NULL);
2799
2800 if (ctxt->varLookupFunc != NULL) {
2801 xmlXPathObjectPtr ret;
2802
2803 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2804 (ctxt->varLookupData, name, ns_uri);
2805 if (ret != NULL) return(ret);
2806 }
2807
2808 if (ctxt->varHash == NULL)
2809 return(NULL);
2810 if (name == NULL)
2811 return(NULL);
2812
Daniel Veillard8c357d52001-07-03 23:43:33 +00002813 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2814 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002815}
2816
2817/**
2818 * xmlXPathRegisteredVariablesCleanup:
2819 * @ctxt: the XPath context
2820 *
2821 * Cleanup the XPath context data associated to registered variables
2822 */
2823void
2824xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2825 if (ctxt == NULL)
2826 return;
2827
Daniel Veillard76d66f42001-05-16 21:05:17 +00002828 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002829 ctxt->varHash = NULL;
2830}
2831
2832/**
2833 * xmlXPathRegisterNs:
2834 * @ctxt: the XPath context
2835 * @prefix: the namespace prefix
2836 * @ns_uri: the namespace name
2837 *
2838 * Register a new namespace. If @ns_uri is NULL it unregisters
2839 * the namespace
2840 *
2841 * Returns 0 in case of success, -1 in case of error
2842 */
2843int
2844xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2845 const xmlChar *ns_uri) {
2846 if (ctxt == NULL)
2847 return(-1);
2848 if (prefix == NULL)
2849 return(-1);
2850
2851 if (ctxt->nsHash == NULL)
2852 ctxt->nsHash = xmlHashCreate(10);
2853 if (ctxt->nsHash == NULL)
2854 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002855 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002856 (xmlHashDeallocator)xmlFree));
2857}
2858
2859/**
2860 * xmlXPathNsLookup:
2861 * @ctxt: the XPath context
2862 * @prefix: the namespace prefix value
2863 *
2864 * Search in the namespace declaration array of the context for the given
2865 * namespace name associated to the given prefix
2866 *
2867 * Returns the value or NULL if not found
2868 */
2869const xmlChar *
2870xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2871 if (ctxt == NULL)
2872 return(NULL);
2873 if (prefix == NULL)
2874 return(NULL);
2875
2876#ifdef XML_XML_NAMESPACE
2877 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2878 return(XML_XML_NAMESPACE);
2879#endif
2880
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002881 if (ctxt->namespaces != NULL) {
2882 int i;
2883
2884 for (i = 0;i < ctxt->nsNr;i++) {
2885 if ((ctxt->namespaces[i] != NULL) &&
2886 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2887 return(ctxt->namespaces[i]->href);
2888 }
2889 }
Owen Taylor3473f882001-02-23 17:55:21 +00002890
2891 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2892}
2893
2894/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002895 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002896 * @ctxt: the XPath context
2897 *
2898 * Cleanup the XPath context data associated to registered variables
2899 */
2900void
2901xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2902 if (ctxt == NULL)
2903 return;
2904
Daniel Veillard42766c02002-08-22 20:52:17 +00002905 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002906 ctxt->nsHash = NULL;
2907}
2908
2909/************************************************************************
2910 * *
2911 * Routines to handle Values *
2912 * *
2913 ************************************************************************/
2914
2915/* Allocations are terrible, one need to optimize all this !!! */
2916
2917/**
2918 * xmlXPathNewFloat:
2919 * @val: the double value
2920 *
2921 * Create a new xmlXPathObjectPtr of type double and of value @val
2922 *
2923 * Returns the newly created object.
2924 */
2925xmlXPathObjectPtr
2926xmlXPathNewFloat(double val) {
2927 xmlXPathObjectPtr ret;
2928
2929 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2930 if (ret == NULL) {
2931 xmlGenericError(xmlGenericErrorContext,
2932 "xmlXPathNewFloat: out of memory\n");
2933 return(NULL);
2934 }
2935 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2936 ret->type = XPATH_NUMBER;
2937 ret->floatval = val;
2938 return(ret);
2939}
2940
2941/**
2942 * xmlXPathNewBoolean:
2943 * @val: the boolean value
2944 *
2945 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2946 *
2947 * Returns the newly created object.
2948 */
2949xmlXPathObjectPtr
2950xmlXPathNewBoolean(int val) {
2951 xmlXPathObjectPtr ret;
2952
2953 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2954 if (ret == NULL) {
2955 xmlGenericError(xmlGenericErrorContext,
2956 "xmlXPathNewBoolean: out of memory\n");
2957 return(NULL);
2958 }
2959 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2960 ret->type = XPATH_BOOLEAN;
2961 ret->boolval = (val != 0);
2962 return(ret);
2963}
2964
2965/**
2966 * xmlXPathNewString:
2967 * @val: the xmlChar * value
2968 *
2969 * Create a new xmlXPathObjectPtr of type string and of value @val
2970 *
2971 * Returns the newly created object.
2972 */
2973xmlXPathObjectPtr
2974xmlXPathNewString(const xmlChar *val) {
2975 xmlXPathObjectPtr ret;
2976
2977 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2978 if (ret == NULL) {
2979 xmlGenericError(xmlGenericErrorContext,
2980 "xmlXPathNewString: out of memory\n");
2981 return(NULL);
2982 }
2983 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2984 ret->type = XPATH_STRING;
2985 if (val != NULL)
2986 ret->stringval = xmlStrdup(val);
2987 else
2988 ret->stringval = xmlStrdup((const xmlChar *)"");
2989 return(ret);
2990}
2991
2992/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002993 * xmlXPathWrapString:
2994 * @val: the xmlChar * value
2995 *
2996 * Wraps the @val string into an XPath object.
2997 *
2998 * Returns the newly created object.
2999 */
3000xmlXPathObjectPtr
3001xmlXPathWrapString (xmlChar *val) {
3002 xmlXPathObjectPtr ret;
3003
3004 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3005 if (ret == NULL) {
3006 xmlGenericError(xmlGenericErrorContext,
3007 "xmlXPathWrapString: out of memory\n");
3008 return(NULL);
3009 }
3010 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3011 ret->type = XPATH_STRING;
3012 ret->stringval = val;
3013 return(ret);
3014}
3015
3016/**
Owen Taylor3473f882001-02-23 17:55:21 +00003017 * xmlXPathNewCString:
3018 * @val: the char * value
3019 *
3020 * Create a new xmlXPathObjectPtr of type string and of value @val
3021 *
3022 * Returns the newly created object.
3023 */
3024xmlXPathObjectPtr
3025xmlXPathNewCString(const char *val) {
3026 xmlXPathObjectPtr ret;
3027
3028 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3029 if (ret == NULL) {
3030 xmlGenericError(xmlGenericErrorContext,
3031 "xmlXPathNewCString: out of memory\n");
3032 return(NULL);
3033 }
3034 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3035 ret->type = XPATH_STRING;
3036 ret->stringval = xmlStrdup(BAD_CAST val);
3037 return(ret);
3038}
3039
3040/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003041 * xmlXPathWrapCString:
3042 * @val: the char * value
3043 *
3044 * Wraps a string into an XPath object.
3045 *
3046 * Returns the newly created object.
3047 */
3048xmlXPathObjectPtr
3049xmlXPathWrapCString (char * val) {
3050 return(xmlXPathWrapString((xmlChar *)(val)));
3051}
3052
3053/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003054 * xmlXPathWrapExternal:
3055 * @val: the user data
3056 *
3057 * Wraps the @val data into an XPath object.
3058 *
3059 * Returns the newly created object.
3060 */
3061xmlXPathObjectPtr
3062xmlXPathWrapExternal (void *val) {
3063 xmlXPathObjectPtr ret;
3064
3065 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3066 if (ret == NULL) {
3067 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003068 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003069 return(NULL);
3070 }
3071 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3072 ret->type = XPATH_USERS;
3073 ret->user = val;
3074 return(ret);
3075}
3076
3077/**
Owen Taylor3473f882001-02-23 17:55:21 +00003078 * xmlXPathObjectCopy:
3079 * @val: the original object
3080 *
3081 * allocate a new copy of a given object
3082 *
3083 * Returns the newly created object.
3084 */
3085xmlXPathObjectPtr
3086xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3087 xmlXPathObjectPtr ret;
3088
3089 if (val == NULL)
3090 return(NULL);
3091
3092 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3093 if (ret == NULL) {
3094 xmlGenericError(xmlGenericErrorContext,
3095 "xmlXPathObjectCopy: out of memory\n");
3096 return(NULL);
3097 }
3098 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3099 switch (val->type) {
3100 case XPATH_BOOLEAN:
3101 case XPATH_NUMBER:
3102 case XPATH_POINT:
3103 case XPATH_RANGE:
3104 break;
3105 case XPATH_STRING:
3106 ret->stringval = xmlStrdup(val->stringval);
3107 break;
3108 case XPATH_XSLT_TREE:
3109 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003110 (val->nodesetval->nodeTab != NULL)) {
3111 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003112 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3113 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003114 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003115 (xmlNodePtr) ret->user);
3116 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003117 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003118 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003119 break;
3120 case XPATH_NODESET:
3121 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003122 /* Do not deallocate the copied tree value */
3123 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003124 break;
3125 case XPATH_LOCATIONSET:
3126#ifdef LIBXML_XPTR_ENABLED
3127 {
3128 xmlLocationSetPtr loc = val->user;
3129 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3130 break;
3131 }
3132#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003133 case XPATH_USERS:
3134 ret->user = val->user;
3135 break;
3136 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003137 xmlGenericError(xmlGenericErrorContext,
3138 "xmlXPathObjectCopy: unsupported type %d\n",
3139 val->type);
3140 break;
3141 }
3142 return(ret);
3143}
3144
3145/**
3146 * xmlXPathFreeObject:
3147 * @obj: the object to free
3148 *
3149 * Free up an xmlXPathObjectPtr object.
3150 */
3151void
3152xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3153 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003154 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003155 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003156 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003157 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003158 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003159 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003160 xmlXPathFreeValueTree(obj->nodesetval);
3161 } else {
3162 if (obj->nodesetval != NULL)
3163 xmlXPathFreeNodeSet(obj->nodesetval);
3164 }
Owen Taylor3473f882001-02-23 17:55:21 +00003165#ifdef LIBXML_XPTR_ENABLED
3166 } else if (obj->type == XPATH_LOCATIONSET) {
3167 if (obj->user != NULL)
3168 xmlXPtrFreeLocationSet(obj->user);
3169#endif
3170 } else if (obj->type == XPATH_STRING) {
3171 if (obj->stringval != NULL)
3172 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003173 }
3174
Owen Taylor3473f882001-02-23 17:55:21 +00003175 xmlFree(obj);
3176}
3177
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003178
3179/************************************************************************
3180 * *
3181 * Type Casting Routines *
3182 * *
3183 ************************************************************************/
3184
3185/**
3186 * xmlXPathCastBooleanToString:
3187 * @val: a boolean
3188 *
3189 * Converts a boolean to its string value.
3190 *
3191 * Returns a newly allocated string.
3192 */
3193xmlChar *
3194xmlXPathCastBooleanToString (int val) {
3195 xmlChar *ret;
3196 if (val)
3197 ret = xmlStrdup((const xmlChar *) "true");
3198 else
3199 ret = xmlStrdup((const xmlChar *) "false");
3200 return(ret);
3201}
3202
3203/**
3204 * xmlXPathCastNumberToString:
3205 * @val: a number
3206 *
3207 * Converts a number to its string value.
3208 *
3209 * Returns a newly allocated string.
3210 */
3211xmlChar *
3212xmlXPathCastNumberToString (double val) {
3213 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003214 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003215 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003216 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003217 break;
3218 case -1:
3219 ret = xmlStrdup((const xmlChar *) "-Infinity");
3220 break;
3221 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003222 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003223 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003224 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3225 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003226 } else {
3227 /* could be improved */
3228 char buf[100];
3229 xmlXPathFormatNumber(val, buf, 100);
3230 ret = xmlStrdup((const xmlChar *) buf);
3231 }
3232 }
3233 return(ret);
3234}
3235
3236/**
3237 * xmlXPathCastNodeToString:
3238 * @node: a node
3239 *
3240 * Converts a node to its string value.
3241 *
3242 * Returns a newly allocated string.
3243 */
3244xmlChar *
3245xmlXPathCastNodeToString (xmlNodePtr node) {
Daniel Veillard23b1f372002-04-18 15:50:05 +00003246 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE))
3247 node = xmlDocGetRootElement((xmlDocPtr) node);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003248 return(xmlNodeGetContent(node));
3249}
3250
3251/**
3252 * xmlXPathCastNodeSetToString:
3253 * @ns: a node-set
3254 *
3255 * Converts a node-set to its string value.
3256 *
3257 * Returns a newly allocated string.
3258 */
3259xmlChar *
3260xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3261 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3262 return(xmlStrdup((const xmlChar *) ""));
3263
3264 xmlXPathNodeSetSort(ns);
3265 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3266}
3267
3268/**
3269 * xmlXPathCastToString:
3270 * @val: an XPath object
3271 *
3272 * Converts an existing object to its string() equivalent
3273 *
3274 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003275 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003276 * string object).
3277 */
3278xmlChar *
3279xmlXPathCastToString(xmlXPathObjectPtr val) {
3280 xmlChar *ret = NULL;
3281
3282 if (val == NULL)
3283 return(xmlStrdup((const xmlChar *) ""));
3284 switch (val->type) {
3285 case XPATH_UNDEFINED:
3286#ifdef DEBUG_EXPR
3287 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3288#endif
3289 ret = xmlStrdup((const xmlChar *) "");
3290 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003291 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003292 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003293 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3294 break;
3295 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003296 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003297 case XPATH_BOOLEAN:
3298 ret = xmlXPathCastBooleanToString(val->boolval);
3299 break;
3300 case XPATH_NUMBER: {
3301 ret = xmlXPathCastNumberToString(val->floatval);
3302 break;
3303 }
3304 case XPATH_USERS:
3305 case XPATH_POINT:
3306 case XPATH_RANGE:
3307 case XPATH_LOCATIONSET:
3308 TODO
3309 ret = xmlStrdup((const xmlChar *) "");
3310 break;
3311 }
3312 return(ret);
3313}
3314
3315/**
3316 * xmlXPathConvertString:
3317 * @val: an XPath object
3318 *
3319 * Converts an existing object to its string() equivalent
3320 *
3321 * Returns the new object, the old one is freed (or the operation
3322 * is done directly on @val)
3323 */
3324xmlXPathObjectPtr
3325xmlXPathConvertString(xmlXPathObjectPtr val) {
3326 xmlChar *res = NULL;
3327
3328 if (val == NULL)
3329 return(xmlXPathNewCString(""));
3330
3331 switch (val->type) {
3332 case XPATH_UNDEFINED:
3333#ifdef DEBUG_EXPR
3334 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3335#endif
3336 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003337 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003338 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003339 res = xmlXPathCastNodeSetToString(val->nodesetval);
3340 break;
3341 case XPATH_STRING:
3342 return(val);
3343 case XPATH_BOOLEAN:
3344 res = xmlXPathCastBooleanToString(val->boolval);
3345 break;
3346 case XPATH_NUMBER:
3347 res = xmlXPathCastNumberToString(val->floatval);
3348 break;
3349 case XPATH_USERS:
3350 case XPATH_POINT:
3351 case XPATH_RANGE:
3352 case XPATH_LOCATIONSET:
3353 TODO;
3354 break;
3355 }
3356 xmlXPathFreeObject(val);
3357 if (res == NULL)
3358 return(xmlXPathNewCString(""));
3359 return(xmlXPathWrapString(res));
3360}
3361
3362/**
3363 * xmlXPathCastBooleanToNumber:
3364 * @val: a boolean
3365 *
3366 * Converts a boolean to its number value
3367 *
3368 * Returns the number value
3369 */
3370double
3371xmlXPathCastBooleanToNumber(int val) {
3372 if (val)
3373 return(1.0);
3374 return(0.0);
3375}
3376
3377/**
3378 * xmlXPathCastStringToNumber:
3379 * @val: a string
3380 *
3381 * Converts a string to its number value
3382 *
3383 * Returns the number value
3384 */
3385double
3386xmlXPathCastStringToNumber(const xmlChar * val) {
3387 return(xmlXPathStringEvalNumber(val));
3388}
3389
3390/**
3391 * xmlXPathCastNodeToNumber:
3392 * @node: a node
3393 *
3394 * Converts a node to its number value
3395 *
3396 * Returns the number value
3397 */
3398double
3399xmlXPathCastNodeToNumber (xmlNodePtr node) {
3400 xmlChar *strval;
3401 double ret;
3402
3403 if (node == NULL)
3404 return(xmlXPathNAN);
3405 strval = xmlXPathCastNodeToString(node);
3406 if (strval == NULL)
3407 return(xmlXPathNAN);
3408 ret = xmlXPathCastStringToNumber(strval);
3409 xmlFree(strval);
3410
3411 return(ret);
3412}
3413
3414/**
3415 * xmlXPathCastNodeSetToNumber:
3416 * @ns: a node-set
3417 *
3418 * Converts a node-set to its number value
3419 *
3420 * Returns the number value
3421 */
3422double
3423xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3424 xmlChar *str;
3425 double ret;
3426
3427 if (ns == NULL)
3428 return(xmlXPathNAN);
3429 str = xmlXPathCastNodeSetToString(ns);
3430 ret = xmlXPathCastStringToNumber(str);
3431 xmlFree(str);
3432 return(ret);
3433}
3434
3435/**
3436 * xmlXPathCastToNumber:
3437 * @val: an XPath object
3438 *
3439 * Converts an XPath object to its number value
3440 *
3441 * Returns the number value
3442 */
3443double
3444xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3445 double ret = 0.0;
3446
3447 if (val == NULL)
3448 return(xmlXPathNAN);
3449 switch (val->type) {
3450 case XPATH_UNDEFINED:
3451#ifdef DEGUB_EXPR
3452 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3453#endif
3454 ret = xmlXPathNAN;
3455 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003456 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003457 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003458 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3459 break;
3460 case XPATH_STRING:
3461 ret = xmlXPathCastStringToNumber(val->stringval);
3462 break;
3463 case XPATH_NUMBER:
3464 ret = val->floatval;
3465 break;
3466 case XPATH_BOOLEAN:
3467 ret = xmlXPathCastBooleanToNumber(val->boolval);
3468 break;
3469 case XPATH_USERS:
3470 case XPATH_POINT:
3471 case XPATH_RANGE:
3472 case XPATH_LOCATIONSET:
3473 TODO;
3474 ret = xmlXPathNAN;
3475 break;
3476 }
3477 return(ret);
3478}
3479
3480/**
3481 * xmlXPathConvertNumber:
3482 * @val: an XPath object
3483 *
3484 * Converts an existing object to its number() equivalent
3485 *
3486 * Returns the new object, the old one is freed (or the operation
3487 * is done directly on @val)
3488 */
3489xmlXPathObjectPtr
3490xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3491 xmlXPathObjectPtr ret;
3492
3493 if (val == NULL)
3494 return(xmlXPathNewFloat(0.0));
3495 if (val->type == XPATH_NUMBER)
3496 return(val);
3497 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3498 xmlXPathFreeObject(val);
3499 return(ret);
3500}
3501
3502/**
3503 * xmlXPathCastNumberToBoolean:
3504 * @val: a number
3505 *
3506 * Converts a number to its boolean value
3507 *
3508 * Returns the boolean value
3509 */
3510int
3511xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003512 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003513 return(0);
3514 return(1);
3515}
3516
3517/**
3518 * xmlXPathCastStringToBoolean:
3519 * @val: a string
3520 *
3521 * Converts a string to its boolean value
3522 *
3523 * Returns the boolean value
3524 */
3525int
3526xmlXPathCastStringToBoolean (const xmlChar *val) {
3527 if ((val == NULL) || (xmlStrlen(val) == 0))
3528 return(0);
3529 return(1);
3530}
3531
3532/**
3533 * xmlXPathCastNodeSetToBoolean:
3534 * @ns: a node-set
3535 *
3536 * Converts a node-set to its boolean value
3537 *
3538 * Returns the boolean value
3539 */
3540int
3541xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3542 if ((ns == NULL) || (ns->nodeNr == 0))
3543 return(0);
3544 return(1);
3545}
3546
3547/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003548 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003549 * @val: an XPath object
3550 *
3551 * Converts an XPath object to its boolean value
3552 *
3553 * Returns the boolean value
3554 */
3555int
3556xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3557 int ret = 0;
3558
3559 if (val == NULL)
3560 return(0);
3561 switch (val->type) {
3562 case XPATH_UNDEFINED:
3563#ifdef DEBUG_EXPR
3564 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3565#endif
3566 ret = 0;
3567 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003568 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003569 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003570 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3571 break;
3572 case XPATH_STRING:
3573 ret = xmlXPathCastStringToBoolean(val->stringval);
3574 break;
3575 case XPATH_NUMBER:
3576 ret = xmlXPathCastNumberToBoolean(val->floatval);
3577 break;
3578 case XPATH_BOOLEAN:
3579 ret = val->boolval;
3580 break;
3581 case XPATH_USERS:
3582 case XPATH_POINT:
3583 case XPATH_RANGE:
3584 case XPATH_LOCATIONSET:
3585 TODO;
3586 ret = 0;
3587 break;
3588 }
3589 return(ret);
3590}
3591
3592
3593/**
3594 * xmlXPathConvertBoolean:
3595 * @val: an XPath object
3596 *
3597 * Converts an existing object to its boolean() equivalent
3598 *
3599 * Returns the new object, the old one is freed (or the operation
3600 * is done directly on @val)
3601 */
3602xmlXPathObjectPtr
3603xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3604 xmlXPathObjectPtr ret;
3605
3606 if (val == NULL)
3607 return(xmlXPathNewBoolean(0));
3608 if (val->type == XPATH_BOOLEAN)
3609 return(val);
3610 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3611 xmlXPathFreeObject(val);
3612 return(ret);
3613}
3614
Owen Taylor3473f882001-02-23 17:55:21 +00003615/************************************************************************
3616 * *
3617 * Routines to handle XPath contexts *
3618 * *
3619 ************************************************************************/
3620
3621/**
3622 * xmlXPathNewContext:
3623 * @doc: the XML document
3624 *
3625 * Create a new xmlXPathContext
3626 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003627 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003628 */
3629xmlXPathContextPtr
3630xmlXPathNewContext(xmlDocPtr doc) {
3631 xmlXPathContextPtr ret;
3632
3633 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3634 if (ret == NULL) {
3635 xmlGenericError(xmlGenericErrorContext,
3636 "xmlXPathNewContext: out of memory\n");
3637 return(NULL);
3638 }
3639 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3640 ret->doc = doc;
3641 ret->node = NULL;
3642
3643 ret->varHash = NULL;
3644
3645 ret->nb_types = 0;
3646 ret->max_types = 0;
3647 ret->types = NULL;
3648
3649 ret->funcHash = xmlHashCreate(0);
3650
3651 ret->nb_axis = 0;
3652 ret->max_axis = 0;
3653 ret->axis = NULL;
3654
3655 ret->nsHash = NULL;
3656 ret->user = NULL;
3657
3658 ret->contextSize = -1;
3659 ret->proximityPosition = -1;
3660
3661 xmlXPathRegisterAllFunctions(ret);
3662
3663 return(ret);
3664}
3665
3666/**
3667 * xmlXPathFreeContext:
3668 * @ctxt: the context to free
3669 *
3670 * Free up an xmlXPathContext
3671 */
3672void
3673xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3674 xmlXPathRegisteredNsCleanup(ctxt);
3675 xmlXPathRegisteredFuncsCleanup(ctxt);
3676 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003677 xmlFree(ctxt);
3678}
3679
3680/************************************************************************
3681 * *
3682 * Routines to handle XPath parser contexts *
3683 * *
3684 ************************************************************************/
3685
3686#define CHECK_CTXT(ctxt) \
3687 if (ctxt == NULL) { \
3688 xmlGenericError(xmlGenericErrorContext, \
3689 "%s:%d Internal error: ctxt == NULL\n", \
3690 __FILE__, __LINE__); \
3691 } \
3692
3693
3694#define CHECK_CONTEXT(ctxt) \
3695 if (ctxt == NULL) { \
3696 xmlGenericError(xmlGenericErrorContext, \
3697 "%s:%d Internal error: no context\n", \
3698 __FILE__, __LINE__); \
3699 } \
3700 else if (ctxt->doc == NULL) { \
3701 xmlGenericError(xmlGenericErrorContext, \
3702 "%s:%d Internal error: no document\n", \
3703 __FILE__, __LINE__); \
3704 } \
3705 else if (ctxt->doc->children == NULL) { \
3706 xmlGenericError(xmlGenericErrorContext, \
3707 "%s:%d Internal error: document without root\n", \
3708 __FILE__, __LINE__); \
3709 } \
3710
3711
3712/**
3713 * xmlXPathNewParserContext:
3714 * @str: the XPath expression
3715 * @ctxt: the XPath context
3716 *
3717 * Create a new xmlXPathParserContext
3718 *
3719 * Returns the xmlXPathParserContext just allocated.
3720 */
3721xmlXPathParserContextPtr
3722xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3723 xmlXPathParserContextPtr ret;
3724
3725 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3726 if (ret == NULL) {
3727 xmlGenericError(xmlGenericErrorContext,
3728 "xmlXPathNewParserContext: out of memory\n");
3729 return(NULL);
3730 }
3731 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3732 ret->cur = ret->base = str;
3733 ret->context = ctxt;
3734
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003735 ret->comp = xmlXPathNewCompExpr();
3736 if (ret->comp == NULL) {
3737 xmlFree(ret->valueTab);
3738 xmlFree(ret);
3739 return(NULL);
3740 }
3741
3742 return(ret);
3743}
3744
3745/**
3746 * xmlXPathCompParserContext:
3747 * @comp: the XPath compiled expression
3748 * @ctxt: the XPath context
3749 *
3750 * Create a new xmlXPathParserContext when processing a compiled expression
3751 *
3752 * Returns the xmlXPathParserContext just allocated.
3753 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003754static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003755xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3756 xmlXPathParserContextPtr ret;
3757
3758 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3759 if (ret == NULL) {
3760 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003761 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003762 return(NULL);
3763 }
3764 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3765
Owen Taylor3473f882001-02-23 17:55:21 +00003766 /* Allocate the value stack */
3767 ret->valueTab = (xmlXPathObjectPtr *)
3768 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003769 if (ret->valueTab == NULL) {
3770 xmlFree(ret);
3771 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003772 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003773 return(NULL);
3774 }
Owen Taylor3473f882001-02-23 17:55:21 +00003775 ret->valueNr = 0;
3776 ret->valueMax = 10;
3777 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003778
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003779 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003780 ret->comp = comp;
3781
Owen Taylor3473f882001-02-23 17:55:21 +00003782 return(ret);
3783}
3784
3785/**
3786 * xmlXPathFreeParserContext:
3787 * @ctxt: the context to free
3788 *
3789 * Free up an xmlXPathParserContext
3790 */
3791void
3792xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3793 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003794 xmlFree(ctxt->valueTab);
3795 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003796 if (ctxt->comp)
3797 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003798 xmlFree(ctxt);
3799}
3800
3801/************************************************************************
3802 * *
3803 * The implicit core function library *
3804 * *
3805 ************************************************************************/
3806
Owen Taylor3473f882001-02-23 17:55:21 +00003807/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003808 * xmlXPathNodeStringHash:
3809 * @node: a node pointer
3810 *
3811 * Function computing the beginning of the string value of the node,
3812 * used to speed up comparisons
3813 *
3814 * Returns an int usable as a hash
3815 */
3816static unsigned int
3817xmlXPathNodeValHash(xmlNodePtr node) {
3818 int len = 2;
3819 const xmlChar * string = NULL;
3820 xmlNodePtr tmp = NULL;
3821 unsigned int ret = 0;
3822
3823 if (node == NULL)
3824 return(0);
3825
3826
3827 switch (node->type) {
3828 case XML_COMMENT_NODE:
3829 case XML_PI_NODE:
3830 case XML_CDATA_SECTION_NODE:
3831 case XML_TEXT_NODE:
3832 string = node->content;
3833 if (string == NULL)
3834 return(0);
3835 if (string[0] == 0)
3836 return(0);
3837 return(((unsigned int) string[0]) +
3838 (((unsigned int) string[1]) << 8));
3839 case XML_NAMESPACE_DECL:
3840 string = ((xmlNsPtr)node)->href;
3841 if (string == NULL)
3842 return(0);
3843 if (string[0] == 0)
3844 return(0);
3845 return(((unsigned int) string[0]) +
3846 (((unsigned int) string[1]) << 8));
3847 case XML_ATTRIBUTE_NODE:
3848 tmp = ((xmlAttrPtr) node)->children;
3849 break;
3850 case XML_ELEMENT_NODE:
3851 tmp = node->children;
3852 break;
3853 default:
3854 return(0);
3855 }
3856 while (tmp != NULL) {
3857 switch (tmp->type) {
3858 case XML_COMMENT_NODE:
3859 case XML_PI_NODE:
3860 case XML_CDATA_SECTION_NODE:
3861 case XML_TEXT_NODE:
3862 string = tmp->content;
3863 break;
3864 case XML_NAMESPACE_DECL:
3865 string = ((xmlNsPtr)tmp)->href;
3866 break;
3867 default:
3868 break;
3869 }
3870 if ((string != NULL) && (string[0] != 0)) {
3871 if (string[0] == 0)
3872 return(0);
3873 if (len == 1) {
3874 return(ret + (((unsigned int) string[0]) << 8));
3875 }
3876 if (string[1] == 0) {
3877 len = 1;
3878 ret = (unsigned int) string[0];
3879 } else {
3880 return(((unsigned int) string[0]) +
3881 (((unsigned int) string[1]) << 8));
3882 }
3883 }
3884 /*
3885 * Skip to next node
3886 */
3887 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3888 if (tmp->children->type != XML_ENTITY_DECL) {
3889 tmp = tmp->children;
3890 continue;
3891 }
3892 }
3893 if (tmp == node)
3894 break;
3895
3896 if (tmp->next != NULL) {
3897 tmp = tmp->next;
3898 continue;
3899 }
3900
3901 do {
3902 tmp = tmp->parent;
3903 if (tmp == NULL)
3904 break;
3905 if (tmp == node) {
3906 tmp = NULL;
3907 break;
3908 }
3909 if (tmp->next != NULL) {
3910 tmp = tmp->next;
3911 break;
3912 }
3913 } while (tmp != NULL);
3914 }
3915 return(ret);
3916}
3917
3918/**
3919 * xmlXPathStringHash:
3920 * @string: a string
3921 *
3922 * Function computing the beginning of the string value of the node,
3923 * used to speed up comparisons
3924 *
3925 * Returns an int usable as a hash
3926 */
3927static unsigned int
3928xmlXPathStringHash(const xmlChar * string) {
3929 if (string == NULL)
3930 return((unsigned int) 0);
3931 if (string[0] == 0)
3932 return(0);
3933 return(((unsigned int) string[0]) +
3934 (((unsigned int) string[1]) << 8));
3935}
3936
3937/**
Owen Taylor3473f882001-02-23 17:55:21 +00003938 * xmlXPathCompareNodeSetFloat:
3939 * @ctxt: the XPath Parser context
3940 * @inf: less than (1) or greater than (0)
3941 * @strict: is the comparison strict
3942 * @arg: the node set
3943 * @f: the value
3944 *
3945 * Implement the compare operation between a nodeset and a number
3946 * @ns < @val (1, 1, ...
3947 * @ns <= @val (1, 0, ...
3948 * @ns > @val (0, 1, ...
3949 * @ns >= @val (0, 0, ...
3950 *
3951 * If one object to be compared is a node-set and the other is a number,
3952 * then the comparison will be true if and only if there is a node in the
3953 * node-set such that the result of performing the comparison on the number
3954 * to be compared and on the result of converting the string-value of that
3955 * node to a number using the number function is true.
3956 *
3957 * Returns 0 or 1 depending on the results of the test.
3958 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003959static int
Owen Taylor3473f882001-02-23 17:55:21 +00003960xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3961 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3962 int i, ret = 0;
3963 xmlNodeSetPtr ns;
3964 xmlChar *str2;
3965
3966 if ((f == NULL) || (arg == NULL) ||
3967 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3968 xmlXPathFreeObject(arg);
3969 xmlXPathFreeObject(f);
3970 return(0);
3971 }
3972 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003973 if (ns != NULL) {
3974 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003975 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003976 if (str2 != NULL) {
3977 valuePush(ctxt,
3978 xmlXPathNewString(str2));
3979 xmlFree(str2);
3980 xmlXPathNumberFunction(ctxt, 1);
3981 valuePush(ctxt, xmlXPathObjectCopy(f));
3982 ret = xmlXPathCompareValues(ctxt, inf, strict);
3983 if (ret)
3984 break;
3985 }
3986 }
Owen Taylor3473f882001-02-23 17:55:21 +00003987 }
3988 xmlXPathFreeObject(arg);
3989 xmlXPathFreeObject(f);
3990 return(ret);
3991}
3992
3993/**
3994 * xmlXPathCompareNodeSetString:
3995 * @ctxt: the XPath Parser context
3996 * @inf: less than (1) or greater than (0)
3997 * @strict: is the comparison strict
3998 * @arg: the node set
3999 * @s: the value
4000 *
4001 * Implement the compare operation between a nodeset and a string
4002 * @ns < @val (1, 1, ...
4003 * @ns <= @val (1, 0, ...
4004 * @ns > @val (0, 1, ...
4005 * @ns >= @val (0, 0, ...
4006 *
4007 * If one object to be compared is a node-set and the other is a string,
4008 * then the comparison will be true if and only if there is a node in
4009 * the node-set such that the result of performing the comparison on the
4010 * string-value of the node and the other string is true.
4011 *
4012 * Returns 0 or 1 depending on the results of the test.
4013 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004014static int
Owen Taylor3473f882001-02-23 17:55:21 +00004015xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4016 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4017 int i, ret = 0;
4018 xmlNodeSetPtr ns;
4019 xmlChar *str2;
4020
4021 if ((s == NULL) || (arg == NULL) ||
4022 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4023 xmlXPathFreeObject(arg);
4024 xmlXPathFreeObject(s);
4025 return(0);
4026 }
4027 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004028 if (ns != NULL) {
4029 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004030 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004031 if (str2 != NULL) {
4032 valuePush(ctxt,
4033 xmlXPathNewString(str2));
4034 xmlFree(str2);
4035 valuePush(ctxt, xmlXPathObjectCopy(s));
4036 ret = xmlXPathCompareValues(ctxt, inf, strict);
4037 if (ret)
4038 break;
4039 }
4040 }
Owen Taylor3473f882001-02-23 17:55:21 +00004041 }
4042 xmlXPathFreeObject(arg);
4043 xmlXPathFreeObject(s);
4044 return(ret);
4045}
4046
4047/**
4048 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004049 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004050 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004051 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004052 * @arg2: the second node set object
4053 *
4054 * Implement the compare operation on nodesets:
4055 *
4056 * If both objects to be compared are node-sets, then the comparison
4057 * will be true if and only if there is a node in the first node-set
4058 * and a node in the second node-set such that the result of performing
4059 * the comparison on the string-values of the two nodes is true.
4060 * ....
4061 * When neither object to be compared is a node-set and the operator
4062 * is <=, <, >= or >, then the objects are compared by converting both
4063 * objects to numbers and comparing the numbers according to IEEE 754.
4064 * ....
4065 * The number function converts its argument to a number as follows:
4066 * - a string that consists of optional whitespace followed by an
4067 * optional minus sign followed by a Number followed by whitespace
4068 * is converted to the IEEE 754 number that is nearest (according
4069 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4070 * represented by the string; any other string is converted to NaN
4071 *
4072 * Conclusion all nodes need to be converted first to their string value
4073 * and then the comparison must be done when possible
4074 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004075static int
4076xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004077 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4078 int i, j, init = 0;
4079 double val1;
4080 double *values2;
4081 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004082 xmlNodeSetPtr ns1;
4083 xmlNodeSetPtr ns2;
4084
4085 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004086 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4087 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004088 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004089 }
Owen Taylor3473f882001-02-23 17:55:21 +00004090 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004091 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4092 xmlXPathFreeObject(arg1);
4093 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004094 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004095 }
Owen Taylor3473f882001-02-23 17:55:21 +00004096
4097 ns1 = arg1->nodesetval;
4098 ns2 = arg2->nodesetval;
4099
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004100 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004101 xmlXPathFreeObject(arg1);
4102 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004103 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004104 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004105 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004106 xmlXPathFreeObject(arg1);
4107 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004108 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004109 }
Owen Taylor3473f882001-02-23 17:55:21 +00004110
4111 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4112 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004113 xmlXPathFreeObject(arg1);
4114 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004115 return(0);
4116 }
4117 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004118 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004119 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004120 continue;
4121 for (j = 0;j < ns2->nodeNr;j++) {
4122 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004123 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004124 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004125 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004126 continue;
4127 if (inf && strict)
4128 ret = (val1 < values2[j]);
4129 else if (inf && !strict)
4130 ret = (val1 <= values2[j]);
4131 else if (!inf && strict)
4132 ret = (val1 > values2[j]);
4133 else if (!inf && !strict)
4134 ret = (val1 >= values2[j]);
4135 if (ret)
4136 break;
4137 }
4138 if (ret)
4139 break;
4140 init = 1;
4141 }
4142 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004143 xmlXPathFreeObject(arg1);
4144 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004145 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004146}
4147
4148/**
4149 * xmlXPathCompareNodeSetValue:
4150 * @ctxt: the XPath Parser context
4151 * @inf: less than (1) or greater than (0)
4152 * @strict: is the comparison strict
4153 * @arg: the node set
4154 * @val: the value
4155 *
4156 * Implement the compare operation between a nodeset and a value
4157 * @ns < @val (1, 1, ...
4158 * @ns <= @val (1, 0, ...
4159 * @ns > @val (0, 1, ...
4160 * @ns >= @val (0, 0, ...
4161 *
4162 * If one object to be compared is a node-set and the other is a boolean,
4163 * then the comparison will be true if and only if the result of performing
4164 * the comparison on the boolean and on the result of converting
4165 * the node-set to a boolean using the boolean function is true.
4166 *
4167 * Returns 0 or 1 depending on the results of the test.
4168 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004169static int
Owen Taylor3473f882001-02-23 17:55:21 +00004170xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4171 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4172 if ((val == NULL) || (arg == NULL) ||
4173 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4174 return(0);
4175
4176 switch(val->type) {
4177 case XPATH_NUMBER:
4178 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4179 case XPATH_NODESET:
4180 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004181 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004182 case XPATH_STRING:
4183 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4184 case XPATH_BOOLEAN:
4185 valuePush(ctxt, arg);
4186 xmlXPathBooleanFunction(ctxt, 1);
4187 valuePush(ctxt, val);
4188 return(xmlXPathCompareValues(ctxt, inf, strict));
4189 default:
4190 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004191 }
4192 return(0);
4193}
4194
4195/**
4196 * xmlXPathEqualNodeSetString
4197 * @arg: the nodeset object argument
4198 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004199 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004200 *
4201 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4202 * If one object to be compared is a node-set and the other is a string,
4203 * then the comparison will be true if and only if there is a node in
4204 * the node-set such that the result of performing the comparison on the
4205 * string-value of the node and the other string is true.
4206 *
4207 * Returns 0 or 1 depending on the results of the test.
4208 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004209static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004210xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004211{
Owen Taylor3473f882001-02-23 17:55:21 +00004212 int i;
4213 xmlNodeSetPtr ns;
4214 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004215 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004216
4217 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004218 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4219 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004220 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004221 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004222 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004223 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004224 if (ns->nodeNr <= 0) {
4225 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004226 return(neq ^ 1);
4227 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004228 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004229 for (i = 0; i < ns->nodeNr; i++) {
4230 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4231 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4232 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4233 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004234 if (neq)
4235 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004236 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004237 } else if (neq) {
4238 if (str2 != NULL)
4239 xmlFree(str2);
4240 return (1);
4241 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004242 if (str2 != NULL)
4243 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004244 } else if (neq)
4245 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004246 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004247 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004248}
4249
4250/**
4251 * xmlXPathEqualNodeSetFloat
4252 * @arg: the nodeset object argument
4253 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004254 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004255 *
4256 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4257 * If one object to be compared is a node-set and the other is a number,
4258 * then the comparison will be true if and only if there is a node in
4259 * the node-set such that the result of performing the comparison on the
4260 * number to be compared and on the result of converting the string-value
4261 * of that node to a number using the number function is true.
4262 *
4263 * Returns 0 or 1 depending on the results of the test.
4264 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004265static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004266xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4267 xmlXPathObjectPtr arg, double f, int neq) {
4268 int i, ret=0;
4269 xmlNodeSetPtr ns;
4270 xmlChar *str2;
4271 xmlXPathObjectPtr val;
4272 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004273
4274 if ((arg == NULL) ||
4275 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4276 return(0);
4277
William M. Brack0c022ad2002-07-12 00:56:01 +00004278 ns = arg->nodesetval;
4279 if (ns != NULL) {
4280 for (i=0;i<ns->nodeNr;i++) {
4281 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4282 if (str2 != NULL) {
4283 valuePush(ctxt, xmlXPathNewString(str2));
4284 xmlFree(str2);
4285 xmlXPathNumberFunction(ctxt, 1);
4286 val = valuePop(ctxt);
4287 v = val->floatval;
4288 xmlXPathFreeObject(val);
4289 if (!xmlXPathIsNaN(v)) {
4290 if ((!neq) && (v==f)) {
4291 ret = 1;
4292 break;
4293 } else if ((neq) && (v!=f)) {
4294 ret = 1;
4295 break;
4296 }
4297 }
4298 }
4299 }
4300 }
4301
4302 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004303}
4304
4305
4306/**
4307 * xmlXPathEqualNodeSets
4308 * @arg1: first nodeset object argument
4309 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004310 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004311 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004312 * Implement the equal / not equal operation on XPath nodesets:
4313 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004314 * If both objects to be compared are node-sets, then the comparison
4315 * will be true if and only if there is a node in the first node-set and
4316 * a node in the second node-set such that the result of performing the
4317 * comparison on the string-values of the two nodes is true.
4318 *
4319 * (needless to say, this is a costly operation)
4320 *
4321 * Returns 0 or 1 depending on the results of the test.
4322 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004323static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004324xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004325 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004326 unsigned int *hashs1;
4327 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004328 xmlChar **values1;
4329 xmlChar **values2;
4330 int ret = 0;
4331 xmlNodeSetPtr ns1;
4332 xmlNodeSetPtr ns2;
4333
4334 if ((arg1 == NULL) ||
4335 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4336 return(0);
4337 if ((arg2 == NULL) ||
4338 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4339 return(0);
4340
4341 ns1 = arg1->nodesetval;
4342 ns2 = arg2->nodesetval;
4343
Daniel Veillard911f49a2001-04-07 15:39:35 +00004344 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004345 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004346 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004347 return(0);
4348
4349 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004350 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004351 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004352 if (neq == 0)
4353 for (i = 0;i < ns1->nodeNr;i++)
4354 for (j = 0;j < ns2->nodeNr;j++)
4355 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4356 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004357
4358 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4359 if (values1 == NULL)
4360 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004361 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4362 if (hashs1 == NULL) {
4363 xmlFree(values1);
4364 return(0);
4365 }
Owen Taylor3473f882001-02-23 17:55:21 +00004366 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4367 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4368 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004369 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004370 xmlFree(values1);
4371 return(0);
4372 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004373 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4374 if (hashs2 == NULL) {
4375 xmlFree(hashs1);
4376 xmlFree(values1);
4377 xmlFree(values2);
4378 return(0);
4379 }
Owen Taylor3473f882001-02-23 17:55:21 +00004380 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4381 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004382 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004383 for (j = 0;j < ns2->nodeNr;j++) {
4384 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004385 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004386 if (hashs1[i] != hashs2[j]) {
4387 if (neq) {
4388 ret = 1;
4389 break;
4390 }
4391 }
4392 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004393 if (values1[i] == NULL)
4394 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4395 if (values2[j] == NULL)
4396 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004397 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004398 if (ret)
4399 break;
4400 }
Owen Taylor3473f882001-02-23 17:55:21 +00004401 }
4402 if (ret)
4403 break;
4404 }
4405 for (i = 0;i < ns1->nodeNr;i++)
4406 if (values1[i] != NULL)
4407 xmlFree(values1[i]);
4408 for (j = 0;j < ns2->nodeNr;j++)
4409 if (values2[j] != NULL)
4410 xmlFree(values2[j]);
4411 xmlFree(values1);
4412 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004413 xmlFree(hashs1);
4414 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004415 return(ret);
4416}
4417
William M. Brack0c022ad2002-07-12 00:56:01 +00004418static int
4419xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4420 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004421 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004422 /*
4423 *At this point we are assured neither arg1 nor arg2
4424 *is a nodeset, so we can just pick the appropriate routine.
4425 */
Owen Taylor3473f882001-02-23 17:55:21 +00004426 switch (arg1->type) {
4427 case XPATH_UNDEFINED:
4428#ifdef DEBUG_EXPR
4429 xmlGenericError(xmlGenericErrorContext,
4430 "Equal: undefined\n");
4431#endif
4432 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004433 case XPATH_BOOLEAN:
4434 switch (arg2->type) {
4435 case XPATH_UNDEFINED:
4436#ifdef DEBUG_EXPR
4437 xmlGenericError(xmlGenericErrorContext,
4438 "Equal: undefined\n");
4439#endif
4440 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004441 case XPATH_BOOLEAN:
4442#ifdef DEBUG_EXPR
4443 xmlGenericError(xmlGenericErrorContext,
4444 "Equal: %d boolean %d \n",
4445 arg1->boolval, arg2->boolval);
4446#endif
4447 ret = (arg1->boolval == arg2->boolval);
4448 break;
4449 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004450 ret = (arg1->boolval ==
4451 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004452 break;
4453 case XPATH_STRING:
4454 if ((arg2->stringval == NULL) ||
4455 (arg2->stringval[0] == 0)) ret = 0;
4456 else
4457 ret = 1;
4458 ret = (arg1->boolval == ret);
4459 break;
4460 case XPATH_USERS:
4461 case XPATH_POINT:
4462 case XPATH_RANGE:
4463 case XPATH_LOCATIONSET:
4464 TODO
4465 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004466 case XPATH_NODESET:
4467 case XPATH_XSLT_TREE:
4468 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004469 }
4470 break;
4471 case XPATH_NUMBER:
4472 switch (arg2->type) {
4473 case XPATH_UNDEFINED:
4474#ifdef DEBUG_EXPR
4475 xmlGenericError(xmlGenericErrorContext,
4476 "Equal: undefined\n");
4477#endif
4478 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004479 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004480 ret = (arg2->boolval==
4481 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004482 break;
4483 case XPATH_STRING:
4484 valuePush(ctxt, arg2);
4485 xmlXPathNumberFunction(ctxt, 1);
4486 arg2 = valuePop(ctxt);
4487 /* no break on purpose */
4488 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004489 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004490 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4491 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004492 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4493 if (xmlXPathIsInf(arg2->floatval) == 1)
4494 ret = 1;
4495 else
4496 ret = 0;
4497 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4498 if (xmlXPathIsInf(arg2->floatval) == -1)
4499 ret = 1;
4500 else
4501 ret = 0;
4502 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4503 if (xmlXPathIsInf(arg1->floatval) == 1)
4504 ret = 1;
4505 else
4506 ret = 0;
4507 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4508 if (xmlXPathIsInf(arg1->floatval) == -1)
4509 ret = 1;
4510 else
4511 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004512 } else {
4513 ret = (arg1->floatval == arg2->floatval);
4514 }
Owen Taylor3473f882001-02-23 17:55:21 +00004515 break;
4516 case XPATH_USERS:
4517 case XPATH_POINT:
4518 case XPATH_RANGE:
4519 case XPATH_LOCATIONSET:
4520 TODO
4521 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004522 case XPATH_NODESET:
4523 case XPATH_XSLT_TREE:
4524 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004525 }
4526 break;
4527 case XPATH_STRING:
4528 switch (arg2->type) {
4529 case XPATH_UNDEFINED:
4530#ifdef DEBUG_EXPR
4531 xmlGenericError(xmlGenericErrorContext,
4532 "Equal: undefined\n");
4533#endif
4534 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004535 case XPATH_BOOLEAN:
4536 if ((arg1->stringval == NULL) ||
4537 (arg1->stringval[0] == 0)) ret = 0;
4538 else
4539 ret = 1;
4540 ret = (arg2->boolval == ret);
4541 break;
4542 case XPATH_STRING:
4543 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4544 break;
4545 case XPATH_NUMBER:
4546 valuePush(ctxt, arg1);
4547 xmlXPathNumberFunction(ctxt, 1);
4548 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004549 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004550 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4551 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004552 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4553 if (xmlXPathIsInf(arg2->floatval) == 1)
4554 ret = 1;
4555 else
4556 ret = 0;
4557 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4558 if (xmlXPathIsInf(arg2->floatval) == -1)
4559 ret = 1;
4560 else
4561 ret = 0;
4562 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4563 if (xmlXPathIsInf(arg1->floatval) == 1)
4564 ret = 1;
4565 else
4566 ret = 0;
4567 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4568 if (xmlXPathIsInf(arg1->floatval) == -1)
4569 ret = 1;
4570 else
4571 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004572 } else {
4573 ret = (arg1->floatval == arg2->floatval);
4574 }
Owen Taylor3473f882001-02-23 17:55:21 +00004575 break;
4576 case XPATH_USERS:
4577 case XPATH_POINT:
4578 case XPATH_RANGE:
4579 case XPATH_LOCATIONSET:
4580 TODO
4581 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004582 case XPATH_NODESET:
4583 case XPATH_XSLT_TREE:
4584 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004585 }
4586 break;
4587 case XPATH_USERS:
4588 case XPATH_POINT:
4589 case XPATH_RANGE:
4590 case XPATH_LOCATIONSET:
4591 TODO
4592 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004593 case XPATH_NODESET:
4594 case XPATH_XSLT_TREE:
4595 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004596 }
4597 xmlXPathFreeObject(arg1);
4598 xmlXPathFreeObject(arg2);
4599 return(ret);
4600}
4601
William M. Brack0c022ad2002-07-12 00:56:01 +00004602/**
4603 * xmlXPathEqualValues:
4604 * @ctxt: the XPath Parser context
4605 *
4606 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4607 *
4608 * Returns 0 or 1 depending on the results of the test.
4609 */
4610int
4611xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4612 xmlXPathObjectPtr arg1, arg2, argtmp;
4613 int ret = 0;
4614
4615 arg2 = valuePop(ctxt);
4616 arg1 = valuePop(ctxt);
4617 if ((arg1 == NULL) || (arg2 == NULL)) {
4618 if (arg1 != NULL)
4619 xmlXPathFreeObject(arg1);
4620 else
4621 xmlXPathFreeObject(arg2);
4622 XP_ERROR0(XPATH_INVALID_OPERAND);
4623 }
4624
4625 if (arg1 == arg2) {
4626#ifdef DEBUG_EXPR
4627 xmlGenericError(xmlGenericErrorContext,
4628 "Equal: by pointer\n");
4629#endif
4630 return(1);
4631 }
4632
4633 /*
4634 *If either argument is a nodeset, it's a 'special case'
4635 */
4636 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4637 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4638 /*
4639 *Hack it to assure arg1 is the nodeset
4640 */
4641 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4642 argtmp = arg2;
4643 arg2 = arg1;
4644 arg1 = argtmp;
4645 }
4646 switch (arg2->type) {
4647 case XPATH_UNDEFINED:
4648#ifdef DEBUG_EXPR
4649 xmlGenericError(xmlGenericErrorContext,
4650 "Equal: undefined\n");
4651#endif
4652 break;
4653 case XPATH_NODESET:
4654 case XPATH_XSLT_TREE:
4655 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4656 break;
4657 case XPATH_BOOLEAN:
4658 if ((arg1->nodesetval == NULL) ||
4659 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4660 else
4661 ret = 1;
4662 ret = (ret == arg2->boolval);
4663 break;
4664 case XPATH_NUMBER:
4665 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4666 break;
4667 case XPATH_STRING:
4668 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4669 break;
4670 case XPATH_USERS:
4671 case XPATH_POINT:
4672 case XPATH_RANGE:
4673 case XPATH_LOCATIONSET:
4674 TODO
4675 break;
4676 }
4677 xmlXPathFreeObject(arg1);
4678 xmlXPathFreeObject(arg2);
4679 return(ret);
4680 }
4681
4682 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4683}
4684
4685/**
4686 * xmlXPathNotEqualValues:
4687 * @ctxt: the XPath Parser context
4688 *
4689 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4690 *
4691 * Returns 0 or 1 depending on the results of the test.
4692 */
4693int
4694xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4695 xmlXPathObjectPtr arg1, arg2, argtmp;
4696 int ret = 0;
4697
4698 arg2 = valuePop(ctxt);
4699 arg1 = valuePop(ctxt);
4700 if ((arg1 == NULL) || (arg2 == NULL)) {
4701 if (arg1 != NULL)
4702 xmlXPathFreeObject(arg1);
4703 else
4704 xmlXPathFreeObject(arg2);
4705 XP_ERROR0(XPATH_INVALID_OPERAND);
4706 }
4707
4708 if (arg1 == arg2) {
4709#ifdef DEBUG_EXPR
4710 xmlGenericError(xmlGenericErrorContext,
4711 "NotEqual: by pointer\n");
4712#endif
4713 return(0);
4714 }
4715
4716 /*
4717 *If either argument is a nodeset, it's a 'special case'
4718 */
4719 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4720 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4721 /*
4722 *Hack it to assure arg1 is the nodeset
4723 */
4724 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4725 argtmp = arg2;
4726 arg2 = arg1;
4727 arg1 = argtmp;
4728 }
4729 switch (arg2->type) {
4730 case XPATH_UNDEFINED:
4731#ifdef DEBUG_EXPR
4732 xmlGenericError(xmlGenericErrorContext,
4733 "NotEqual: undefined\n");
4734#endif
4735 break;
4736 case XPATH_NODESET:
4737 case XPATH_XSLT_TREE:
4738 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4739 break;
4740 case XPATH_BOOLEAN:
4741 if ((arg1->nodesetval == NULL) ||
4742 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4743 else
4744 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004745 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004746 break;
4747 case XPATH_NUMBER:
4748 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4749 break;
4750 case XPATH_STRING:
4751 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4752 break;
4753 case XPATH_USERS:
4754 case XPATH_POINT:
4755 case XPATH_RANGE:
4756 case XPATH_LOCATIONSET:
4757 TODO
4758 break;
4759 }
4760 xmlXPathFreeObject(arg1);
4761 xmlXPathFreeObject(arg2);
4762 return(ret);
4763 }
4764
4765 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4766}
Owen Taylor3473f882001-02-23 17:55:21 +00004767
4768/**
4769 * xmlXPathCompareValues:
4770 * @ctxt: the XPath Parser context
4771 * @inf: less than (1) or greater than (0)
4772 * @strict: is the comparison strict
4773 *
4774 * Implement the compare operation on XPath objects:
4775 * @arg1 < @arg2 (1, 1, ...
4776 * @arg1 <= @arg2 (1, 0, ...
4777 * @arg1 > @arg2 (0, 1, ...
4778 * @arg1 >= @arg2 (0, 0, ...
4779 *
4780 * When neither object to be compared is a node-set and the operator is
4781 * <=, <, >=, >, then the objects are compared by converted both objects
4782 * to numbers and comparing the numbers according to IEEE 754. The <
4783 * comparison will be true if and only if the first number is less than the
4784 * second number. The <= comparison will be true if and only if the first
4785 * number is less than or equal to the second number. The > comparison
4786 * will be true if and only if the first number is greater than the second
4787 * number. The >= comparison will be true if and only if the first number
4788 * is greater than or equal to the second number.
4789 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004790 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004791 */
4792int
4793xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004794 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004795 xmlXPathObjectPtr arg1, arg2;
4796
William M. Brack0c022ad2002-07-12 00:56:01 +00004797 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004798 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004799 if ((arg1 == NULL) || (arg2 == NULL)) {
4800 if (arg1 != NULL)
4801 xmlXPathFreeObject(arg1);
4802 else
4803 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004804 XP_ERROR0(XPATH_INVALID_OPERAND);
4805 }
4806
William M. Brack0c022ad2002-07-12 00:56:01 +00004807 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4808 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4809 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4810 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004811 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004812 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004813 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004814 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4815 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004816 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004817 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4818 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004819 }
4820 }
4821 return(ret);
4822 }
4823
4824 if (arg1->type != XPATH_NUMBER) {
4825 valuePush(ctxt, arg1);
4826 xmlXPathNumberFunction(ctxt, 1);
4827 arg1 = valuePop(ctxt);
4828 }
4829 if (arg1->type != XPATH_NUMBER) {
4830 xmlXPathFreeObject(arg1);
4831 xmlXPathFreeObject(arg2);
4832 XP_ERROR0(XPATH_INVALID_OPERAND);
4833 }
4834 if (arg2->type != XPATH_NUMBER) {
4835 valuePush(ctxt, arg2);
4836 xmlXPathNumberFunction(ctxt, 1);
4837 arg2 = valuePop(ctxt);
4838 }
4839 if (arg2->type != XPATH_NUMBER) {
4840 xmlXPathFreeObject(arg1);
4841 xmlXPathFreeObject(arg2);
4842 XP_ERROR0(XPATH_INVALID_OPERAND);
4843 }
4844 /*
4845 * Add tests for infinity and nan
4846 * => feedback on 3.4 for Inf and NaN
4847 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004848 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004849 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004850 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004851 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004852 arg1i=xmlXPathIsInf(arg1->floatval);
4853 arg2i=xmlXPathIsInf(arg2->floatval);
4854 if (inf && strict) {
4855 if ((arg1i == -1 && arg2i != -1) ||
4856 (arg2i == 1 && arg1i != 1)) {
4857 ret = 1;
4858 } else if (arg1i == 0 && arg2i == 0) {
4859 ret = (arg1->floatval < arg2->floatval);
4860 } else {
4861 ret = 0;
4862 }
4863 }
4864 else if (inf && !strict) {
4865 if (arg1i == -1 || arg2i == 1) {
4866 ret = 1;
4867 } else if (arg1i == 0 && arg2i == 0) {
4868 ret = (arg1->floatval <= arg2->floatval);
4869 } else {
4870 ret = 0;
4871 }
4872 }
4873 else if (!inf && strict) {
4874 if ((arg1i == 1 && arg2i != 1) ||
4875 (arg2i == -1 && arg1i != -1)) {
4876 ret = 1;
4877 } else if (arg1i == 0 && arg2i == 0) {
4878 ret = (arg1->floatval > arg2->floatval);
4879 } else {
4880 ret = 0;
4881 }
4882 }
4883 else if (!inf && !strict) {
4884 if (arg1i == 1 || arg2i == -1) {
4885 ret = 1;
4886 } else if (arg1i == 0 && arg2i == 0) {
4887 ret = (arg1->floatval >= arg2->floatval);
4888 } else {
4889 ret = 0;
4890 }
4891 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004892 }
Owen Taylor3473f882001-02-23 17:55:21 +00004893 xmlXPathFreeObject(arg1);
4894 xmlXPathFreeObject(arg2);
4895 return(ret);
4896}
4897
4898/**
4899 * xmlXPathValueFlipSign:
4900 * @ctxt: the XPath Parser context
4901 *
4902 * Implement the unary - operation on an XPath object
4903 * The numeric operators convert their operands to numbers as if
4904 * by calling the number function.
4905 */
4906void
4907xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004908 CAST_TO_NUMBER;
4909 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00004910 if (xmlXPathIsNaN(ctxt->value->floatval))
4911 ctxt->value->floatval=xmlXPathNAN;
4912 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
4913 ctxt->value->floatval=xmlXPathNINF;
4914 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
4915 ctxt->value->floatval=xmlXPathPINF;
4916 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00004917 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
4918 ctxt->value->floatval = xmlXPathNZERO;
4919 else
4920 ctxt->value->floatval = 0;
4921 }
4922 else
4923 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004924}
4925
4926/**
4927 * xmlXPathAddValues:
4928 * @ctxt: the XPath Parser context
4929 *
4930 * Implement the add operation on XPath objects:
4931 * The numeric operators convert their operands to numbers as if
4932 * by calling the number function.
4933 */
4934void
4935xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4936 xmlXPathObjectPtr arg;
4937 double val;
4938
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004939 arg = valuePop(ctxt);
4940 if (arg == NULL)
4941 XP_ERROR(XPATH_INVALID_OPERAND);
4942 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004943 xmlXPathFreeObject(arg);
4944
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004945 CAST_TO_NUMBER;
4946 CHECK_TYPE(XPATH_NUMBER);
4947 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004948}
4949
4950/**
4951 * xmlXPathSubValues:
4952 * @ctxt: the XPath Parser context
4953 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004954 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004955 * The numeric operators convert their operands to numbers as if
4956 * by calling the number function.
4957 */
4958void
4959xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4960 xmlXPathObjectPtr arg;
4961 double val;
4962
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004963 arg = valuePop(ctxt);
4964 if (arg == NULL)
4965 XP_ERROR(XPATH_INVALID_OPERAND);
4966 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004967 xmlXPathFreeObject(arg);
4968
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004969 CAST_TO_NUMBER;
4970 CHECK_TYPE(XPATH_NUMBER);
4971 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004972}
4973
4974/**
4975 * xmlXPathMultValues:
4976 * @ctxt: the XPath Parser context
4977 *
4978 * Implement the multiply operation on XPath objects:
4979 * The numeric operators convert their operands to numbers as if
4980 * by calling the number function.
4981 */
4982void
4983xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4984 xmlXPathObjectPtr arg;
4985 double val;
4986
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004987 arg = valuePop(ctxt);
4988 if (arg == NULL)
4989 XP_ERROR(XPATH_INVALID_OPERAND);
4990 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004991 xmlXPathFreeObject(arg);
4992
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004993 CAST_TO_NUMBER;
4994 CHECK_TYPE(XPATH_NUMBER);
4995 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004996}
4997
4998/**
4999 * xmlXPathDivValues:
5000 * @ctxt: the XPath Parser context
5001 *
5002 * Implement the div operation on XPath objects @arg1 / @arg2:
5003 * The numeric operators convert their operands to numbers as if
5004 * by calling the number function.
5005 */
5006void
5007xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5008 xmlXPathObjectPtr arg;
5009 double val;
5010
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005011 arg = valuePop(ctxt);
5012 if (arg == NULL)
5013 XP_ERROR(XPATH_INVALID_OPERAND);
5014 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005015 xmlXPathFreeObject(arg);
5016
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005017 CAST_TO_NUMBER;
5018 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005019 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5020 ctxt->value->floatval = xmlXPathNAN;
5021 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005022 if (ctxt->value->floatval == 0)
5023 ctxt->value->floatval = xmlXPathNAN;
5024 else if (ctxt->value->floatval > 0)
5025 ctxt->value->floatval = xmlXPathNINF;
5026 else if (ctxt->value->floatval < 0)
5027 ctxt->value->floatval = xmlXPathPINF;
5028 }
5029 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005030 if (ctxt->value->floatval == 0)
5031 ctxt->value->floatval = xmlXPathNAN;
5032 else if (ctxt->value->floatval > 0)
5033 ctxt->value->floatval = xmlXPathPINF;
5034 else if (ctxt->value->floatval < 0)
5035 ctxt->value->floatval = xmlXPathNINF;
5036 } else
5037 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005038}
5039
5040/**
5041 * xmlXPathModValues:
5042 * @ctxt: the XPath Parser context
5043 *
5044 * Implement the mod operation on XPath objects: @arg1 / @arg2
5045 * The numeric operators convert their operands to numbers as if
5046 * by calling the number function.
5047 */
5048void
5049xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5050 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005051 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005052
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005053 arg = valuePop(ctxt);
5054 if (arg == NULL)
5055 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005056 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005057 xmlXPathFreeObject(arg);
5058
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005059 CAST_TO_NUMBER;
5060 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005061 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005062 if (arg2 == 0)
5063 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005064 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005065 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005066 }
Owen Taylor3473f882001-02-23 17:55:21 +00005067}
5068
5069/************************************************************************
5070 * *
5071 * The traversal functions *
5072 * *
5073 ************************************************************************/
5074
Owen Taylor3473f882001-02-23 17:55:21 +00005075/*
5076 * A traversal function enumerates nodes along an axis.
5077 * Initially it must be called with NULL, and it indicates
5078 * termination on the axis by returning NULL.
5079 */
5080typedef xmlNodePtr (*xmlXPathTraversalFunction)
5081 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5082
5083/**
5084 * xmlXPathNextSelf:
5085 * @ctxt: the XPath Parser context
5086 * @cur: the current node in the traversal
5087 *
5088 * Traversal function for the "self" direction
5089 * The self axis contains just the context node itself
5090 *
5091 * Returns the next element following that axis
5092 */
5093xmlNodePtr
5094xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5095 if (cur == NULL)
5096 return(ctxt->context->node);
5097 return(NULL);
5098}
5099
5100/**
5101 * xmlXPathNextChild:
5102 * @ctxt: the XPath Parser context
5103 * @cur: the current node in the traversal
5104 *
5105 * Traversal function for the "child" direction
5106 * The child axis contains the children of the context node in document order.
5107 *
5108 * Returns the next element following that axis
5109 */
5110xmlNodePtr
5111xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5112 if (cur == NULL) {
5113 if (ctxt->context->node == NULL) return(NULL);
5114 switch (ctxt->context->node->type) {
5115 case XML_ELEMENT_NODE:
5116 case XML_TEXT_NODE:
5117 case XML_CDATA_SECTION_NODE:
5118 case XML_ENTITY_REF_NODE:
5119 case XML_ENTITY_NODE:
5120 case XML_PI_NODE:
5121 case XML_COMMENT_NODE:
5122 case XML_NOTATION_NODE:
5123 case XML_DTD_NODE:
5124 return(ctxt->context->node->children);
5125 case XML_DOCUMENT_NODE:
5126 case XML_DOCUMENT_TYPE_NODE:
5127 case XML_DOCUMENT_FRAG_NODE:
5128 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005129#ifdef LIBXML_DOCB_ENABLED
5130 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005131#endif
5132 return(((xmlDocPtr) ctxt->context->node)->children);
5133 case XML_ELEMENT_DECL:
5134 case XML_ATTRIBUTE_DECL:
5135 case XML_ENTITY_DECL:
5136 case XML_ATTRIBUTE_NODE:
5137 case XML_NAMESPACE_DECL:
5138 case XML_XINCLUDE_START:
5139 case XML_XINCLUDE_END:
5140 return(NULL);
5141 }
5142 return(NULL);
5143 }
5144 if ((cur->type == XML_DOCUMENT_NODE) ||
5145 (cur->type == XML_HTML_DOCUMENT_NODE))
5146 return(NULL);
5147 return(cur->next);
5148}
5149
5150/**
5151 * xmlXPathNextDescendant:
5152 * @ctxt: the XPath Parser context
5153 * @cur: the current node in the traversal
5154 *
5155 * Traversal function for the "descendant" direction
5156 * the descendant axis contains the descendants of the context node in document
5157 * order; a descendant is a child or a child of a child and so on.
5158 *
5159 * Returns the next element following that axis
5160 */
5161xmlNodePtr
5162xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5163 if (cur == NULL) {
5164 if (ctxt->context->node == NULL)
5165 return(NULL);
5166 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5167 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5168 return(NULL);
5169
5170 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5171 return(ctxt->context->doc->children);
5172 return(ctxt->context->node->children);
5173 }
5174
Daniel Veillard567e1b42001-08-01 15:53:47 +00005175 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005176 /*
5177 * Do not descend on entities declarations
5178 */
5179 if (cur->children->type != XML_ENTITY_DECL) {
5180 cur = cur->children;
5181 /*
5182 * Skip DTDs
5183 */
5184 if (cur->type != XML_DTD_NODE)
5185 return(cur);
5186 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005187 }
5188
5189 if (cur == ctxt->context->node) return(NULL);
5190
Daniel Veillard68e9e742002-11-16 15:35:11 +00005191 while (cur->next != NULL) {
5192 cur = cur->next;
5193 if ((cur->type != XML_ENTITY_DECL) &&
5194 (cur->type != XML_DTD_NODE))
5195 return(cur);
5196 }
Owen Taylor3473f882001-02-23 17:55:21 +00005197
5198 do {
5199 cur = cur->parent;
5200 if (cur == NULL) return(NULL);
5201 if (cur == ctxt->context->node) return(NULL);
5202 if (cur->next != NULL) {
5203 cur = cur->next;
5204 return(cur);
5205 }
5206 } while (cur != NULL);
5207 return(cur);
5208}
5209
5210/**
5211 * xmlXPathNextDescendantOrSelf:
5212 * @ctxt: the XPath Parser context
5213 * @cur: the current node in the traversal
5214 *
5215 * Traversal function for the "descendant-or-self" direction
5216 * the descendant-or-self axis contains the context node and the descendants
5217 * of the context node in document order; thus the context node is the first
5218 * node on the axis, and the first child of the context node is the second node
5219 * on the axis
5220 *
5221 * Returns the next element following that axis
5222 */
5223xmlNodePtr
5224xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5225 if (cur == NULL) {
5226 if (ctxt->context->node == NULL)
5227 return(NULL);
5228 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5229 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5230 return(NULL);
5231 return(ctxt->context->node);
5232 }
5233
5234 return(xmlXPathNextDescendant(ctxt, cur));
5235}
5236
5237/**
5238 * xmlXPathNextParent:
5239 * @ctxt: the XPath Parser context
5240 * @cur: the current node in the traversal
5241 *
5242 * Traversal function for the "parent" direction
5243 * The parent axis contains the parent of the context node, if there is one.
5244 *
5245 * Returns the next element following that axis
5246 */
5247xmlNodePtr
5248xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5249 /*
5250 * the parent of an attribute or namespace node is the element
5251 * to which the attribute or namespace node is attached
5252 * Namespace handling !!!
5253 */
5254 if (cur == NULL) {
5255 if (ctxt->context->node == NULL) return(NULL);
5256 switch (ctxt->context->node->type) {
5257 case XML_ELEMENT_NODE:
5258 case XML_TEXT_NODE:
5259 case XML_CDATA_SECTION_NODE:
5260 case XML_ENTITY_REF_NODE:
5261 case XML_ENTITY_NODE:
5262 case XML_PI_NODE:
5263 case XML_COMMENT_NODE:
5264 case XML_NOTATION_NODE:
5265 case XML_DTD_NODE:
5266 case XML_ELEMENT_DECL:
5267 case XML_ATTRIBUTE_DECL:
5268 case XML_XINCLUDE_START:
5269 case XML_XINCLUDE_END:
5270 case XML_ENTITY_DECL:
5271 if (ctxt->context->node->parent == NULL)
5272 return((xmlNodePtr) ctxt->context->doc);
5273 return(ctxt->context->node->parent);
5274 case XML_ATTRIBUTE_NODE: {
5275 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5276
5277 return(att->parent);
5278 }
5279 case XML_DOCUMENT_NODE:
5280 case XML_DOCUMENT_TYPE_NODE:
5281 case XML_DOCUMENT_FRAG_NODE:
5282 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005283#ifdef LIBXML_DOCB_ENABLED
5284 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005285#endif
5286 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005287 case XML_NAMESPACE_DECL: {
5288 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5289
5290 if ((ns->next != NULL) &&
5291 (ns->next->type != XML_NAMESPACE_DECL))
5292 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005293 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005294 }
Owen Taylor3473f882001-02-23 17:55:21 +00005295 }
5296 }
5297 return(NULL);
5298}
5299
5300/**
5301 * xmlXPathNextAncestor:
5302 * @ctxt: the XPath Parser context
5303 * @cur: the current node in the traversal
5304 *
5305 * Traversal function for the "ancestor" direction
5306 * the ancestor axis contains the ancestors of the context node; the ancestors
5307 * of the context node consist of the parent of context node and the parent's
5308 * parent and so on; the nodes are ordered in reverse document order; thus the
5309 * parent is the first node on the axis, and the parent's parent is the second
5310 * node on the axis
5311 *
5312 * Returns the next element following that axis
5313 */
5314xmlNodePtr
5315xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5316 /*
5317 * the parent of an attribute or namespace node is the element
5318 * to which the attribute or namespace node is attached
5319 * !!!!!!!!!!!!!
5320 */
5321 if (cur == NULL) {
5322 if (ctxt->context->node == NULL) return(NULL);
5323 switch (ctxt->context->node->type) {
5324 case XML_ELEMENT_NODE:
5325 case XML_TEXT_NODE:
5326 case XML_CDATA_SECTION_NODE:
5327 case XML_ENTITY_REF_NODE:
5328 case XML_ENTITY_NODE:
5329 case XML_PI_NODE:
5330 case XML_COMMENT_NODE:
5331 case XML_DTD_NODE:
5332 case XML_ELEMENT_DECL:
5333 case XML_ATTRIBUTE_DECL:
5334 case XML_ENTITY_DECL:
5335 case XML_NOTATION_NODE:
5336 case XML_XINCLUDE_START:
5337 case XML_XINCLUDE_END:
5338 if (ctxt->context->node->parent == NULL)
5339 return((xmlNodePtr) ctxt->context->doc);
5340 return(ctxt->context->node->parent);
5341 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005342 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005343
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005344 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005345 }
5346 case XML_DOCUMENT_NODE:
5347 case XML_DOCUMENT_TYPE_NODE:
5348 case XML_DOCUMENT_FRAG_NODE:
5349 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005350#ifdef LIBXML_DOCB_ENABLED
5351 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005352#endif
5353 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005354 case XML_NAMESPACE_DECL: {
5355 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5356
5357 if ((ns->next != NULL) &&
5358 (ns->next->type != XML_NAMESPACE_DECL))
5359 return((xmlNodePtr) ns->next);
5360 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005361 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005362 }
Owen Taylor3473f882001-02-23 17:55:21 +00005363 }
5364 return(NULL);
5365 }
5366 if (cur == ctxt->context->doc->children)
5367 return((xmlNodePtr) ctxt->context->doc);
5368 if (cur == (xmlNodePtr) ctxt->context->doc)
5369 return(NULL);
5370 switch (cur->type) {
5371 case XML_ELEMENT_NODE:
5372 case XML_TEXT_NODE:
5373 case XML_CDATA_SECTION_NODE:
5374 case XML_ENTITY_REF_NODE:
5375 case XML_ENTITY_NODE:
5376 case XML_PI_NODE:
5377 case XML_COMMENT_NODE:
5378 case XML_NOTATION_NODE:
5379 case XML_DTD_NODE:
5380 case XML_ELEMENT_DECL:
5381 case XML_ATTRIBUTE_DECL:
5382 case XML_ENTITY_DECL:
5383 case XML_XINCLUDE_START:
5384 case XML_XINCLUDE_END:
5385 return(cur->parent);
5386 case XML_ATTRIBUTE_NODE: {
5387 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5388
5389 return(att->parent);
5390 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005391 case XML_NAMESPACE_DECL: {
5392 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5393
5394 if ((ns->next != NULL) &&
5395 (ns->next->type != XML_NAMESPACE_DECL))
5396 return((xmlNodePtr) ns->next);
5397 /* Bad, how did that namespace ended-up there ? */
5398 return(NULL);
5399 }
Owen Taylor3473f882001-02-23 17:55:21 +00005400 case XML_DOCUMENT_NODE:
5401 case XML_DOCUMENT_TYPE_NODE:
5402 case XML_DOCUMENT_FRAG_NODE:
5403 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005404#ifdef LIBXML_DOCB_ENABLED
5405 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005406#endif
5407 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005408 }
5409 return(NULL);
5410}
5411
5412/**
5413 * xmlXPathNextAncestorOrSelf:
5414 * @ctxt: the XPath Parser context
5415 * @cur: the current node in the traversal
5416 *
5417 * Traversal function for the "ancestor-or-self" direction
5418 * he ancestor-or-self axis contains the context node and ancestors of
5419 * the context node in reverse document order; thus the context node is
5420 * the first node on the axis, and the context node's parent the second;
5421 * parent here is defined the same as with the parent axis.
5422 *
5423 * Returns the next element following that axis
5424 */
5425xmlNodePtr
5426xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5427 if (cur == NULL)
5428 return(ctxt->context->node);
5429 return(xmlXPathNextAncestor(ctxt, cur));
5430}
5431
5432/**
5433 * xmlXPathNextFollowingSibling:
5434 * @ctxt: the XPath Parser context
5435 * @cur: the current node in the traversal
5436 *
5437 * Traversal function for the "following-sibling" direction
5438 * The following-sibling axis contains the following siblings of the context
5439 * node in document order.
5440 *
5441 * Returns the next element following that axis
5442 */
5443xmlNodePtr
5444xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5445 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5446 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5447 return(NULL);
5448 if (cur == (xmlNodePtr) ctxt->context->doc)
5449 return(NULL);
5450 if (cur == NULL)
5451 return(ctxt->context->node->next);
5452 return(cur->next);
5453}
5454
5455/**
5456 * xmlXPathNextPrecedingSibling:
5457 * @ctxt: the XPath Parser context
5458 * @cur: the current node in the traversal
5459 *
5460 * Traversal function for the "preceding-sibling" direction
5461 * The preceding-sibling axis contains the preceding siblings of the context
5462 * node in reverse document order; the first preceding sibling is first on the
5463 * axis; the sibling preceding that node is the second on the axis and so on.
5464 *
5465 * Returns the next element following that axis
5466 */
5467xmlNodePtr
5468xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5469 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5470 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5471 return(NULL);
5472 if (cur == (xmlNodePtr) ctxt->context->doc)
5473 return(NULL);
5474 if (cur == NULL)
5475 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005476 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5477 cur = cur->prev;
5478 if (cur == NULL)
5479 return(ctxt->context->node->prev);
5480 }
Owen Taylor3473f882001-02-23 17:55:21 +00005481 return(cur->prev);
5482}
5483
5484/**
5485 * xmlXPathNextFollowing:
5486 * @ctxt: the XPath Parser context
5487 * @cur: the current node in the traversal
5488 *
5489 * Traversal function for the "following" direction
5490 * The following axis contains all nodes in the same document as the context
5491 * node that are after the context node in document order, excluding any
5492 * descendants and excluding attribute nodes and namespace nodes; the nodes
5493 * are ordered in document order
5494 *
5495 * Returns the next element following that axis
5496 */
5497xmlNodePtr
5498xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5499 if (cur != NULL && cur->children != NULL)
5500 return cur->children ;
5501 if (cur == NULL) cur = ctxt->context->node;
5502 if (cur == NULL) return(NULL) ; /* ERROR */
5503 if (cur->next != NULL) return(cur->next) ;
5504 do {
5505 cur = cur->parent;
5506 if (cur == NULL) return(NULL);
5507 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5508 if (cur->next != NULL) return(cur->next);
5509 } while (cur != NULL);
5510 return(cur);
5511}
5512
5513/*
5514 * xmlXPathIsAncestor:
5515 * @ancestor: the ancestor node
5516 * @node: the current node
5517 *
5518 * Check that @ancestor is a @node's ancestor
5519 *
5520 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5521 */
5522static int
5523xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5524 if ((ancestor == NULL) || (node == NULL)) return(0);
5525 /* nodes need to be in the same document */
5526 if (ancestor->doc != node->doc) return(0);
5527 /* avoid searching if ancestor or node is the root node */
5528 if (ancestor == (xmlNodePtr) node->doc) return(1);
5529 if (node == (xmlNodePtr) ancestor->doc) return(0);
5530 while (node->parent != NULL) {
5531 if (node->parent == ancestor)
5532 return(1);
5533 node = node->parent;
5534 }
5535 return(0);
5536}
5537
5538/**
5539 * xmlXPathNextPreceding:
5540 * @ctxt: the XPath Parser context
5541 * @cur: the current node in the traversal
5542 *
5543 * Traversal function for the "preceding" direction
5544 * the preceding axis contains all nodes in the same document as the context
5545 * node that are before the context node in document order, excluding any
5546 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5547 * ordered in reverse document order
5548 *
5549 * Returns the next element following that axis
5550 */
5551xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005552xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5553{
Owen Taylor3473f882001-02-23 17:55:21 +00005554 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005555 cur = ctxt->context->node;
5556 if (cur == NULL)
5557 return (NULL);
5558 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5559 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005560 do {
5561 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005562 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5563 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005564 }
5565
5566 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005567 if (cur == NULL)
5568 return (NULL);
5569 if (cur == ctxt->context->doc->children)
5570 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005571 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005572 return (cur);
5573}
5574
5575/**
5576 * xmlXPathNextPrecedingInternal:
5577 * @ctxt: the XPath Parser context
5578 * @cur: the current node in the traversal
5579 *
5580 * Traversal function for the "preceding" direction
5581 * the preceding axis contains all nodes in the same document as the context
5582 * node that are before the context node in document order, excluding any
5583 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5584 * ordered in reverse document order
5585 * This is a faster implementation but internal only since it requires a
5586 * state kept in the parser context: ctxt->ancestor.
5587 *
5588 * Returns the next element following that axis
5589 */
5590static xmlNodePtr
5591xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5592 xmlNodePtr cur)
5593{
5594 if (cur == NULL) {
5595 cur = ctxt->context->node;
5596 if (cur == NULL)
5597 return (NULL);
5598 ctxt->ancestor = cur->parent;
5599 }
5600 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5601 cur = cur->prev;
5602 while (cur->prev == NULL) {
5603 cur = cur->parent;
5604 if (cur == NULL)
5605 return (NULL);
5606 if (cur == ctxt->context->doc->children)
5607 return (NULL);
5608 if (cur != ctxt->ancestor)
5609 return (cur);
5610 ctxt->ancestor = cur->parent;
5611 }
5612 cur = cur->prev;
5613 while (cur->last != NULL)
5614 cur = cur->last;
5615 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005616}
5617
5618/**
5619 * xmlXPathNextNamespace:
5620 * @ctxt: the XPath Parser context
5621 * @cur: the current attribute in the traversal
5622 *
5623 * Traversal function for the "namespace" direction
5624 * the namespace axis contains the namespace nodes of the context node;
5625 * the order of nodes on this axis is implementation-defined; the axis will
5626 * be empty unless the context node is an element
5627 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005628 * We keep the XML namespace node at the end of the list.
5629 *
Owen Taylor3473f882001-02-23 17:55:21 +00005630 * Returns the next element following that axis
5631 */
5632xmlNodePtr
5633xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5634 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005635 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005636 if (ctxt->context->tmpNsList != NULL)
5637 xmlFree(ctxt->context->tmpNsList);
5638 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005639 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005640 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005641 if (ctxt->context->tmpNsList != NULL) {
5642 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5643 ctxt->context->tmpNsNr++;
5644 }
5645 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005646 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005647 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005648 if (ctxt->context->tmpNsNr > 0) {
5649 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5650 } else {
5651 if (ctxt->context->tmpNsList != NULL)
5652 xmlFree(ctxt->context->tmpNsList);
5653 ctxt->context->tmpNsList = NULL;
5654 return(NULL);
5655 }
Owen Taylor3473f882001-02-23 17:55:21 +00005656}
5657
5658/**
5659 * xmlXPathNextAttribute:
5660 * @ctxt: the XPath Parser context
5661 * @cur: the current attribute in the traversal
5662 *
5663 * Traversal function for the "attribute" direction
5664 * TODO: support DTD inherited default attributes
5665 *
5666 * Returns the next element following that axis
5667 */
5668xmlNodePtr
5669xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005670 if (ctxt->context->node == NULL)
5671 return(NULL);
5672 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5673 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005674 if (cur == NULL) {
5675 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5676 return(NULL);
5677 return((xmlNodePtr)ctxt->context->node->properties);
5678 }
5679 return((xmlNodePtr)cur->next);
5680}
5681
5682/************************************************************************
5683 * *
5684 * NodeTest Functions *
5685 * *
5686 ************************************************************************/
5687
Owen Taylor3473f882001-02-23 17:55:21 +00005688#define IS_FUNCTION 200
5689
Owen Taylor3473f882001-02-23 17:55:21 +00005690
5691/************************************************************************
5692 * *
5693 * Implicit tree core function library *
5694 * *
5695 ************************************************************************/
5696
5697/**
5698 * xmlXPathRoot:
5699 * @ctxt: the XPath Parser context
5700 *
5701 * Initialize the context to the root of the document
5702 */
5703void
5704xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5705 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5706 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5707}
5708
5709/************************************************************************
5710 * *
5711 * The explicit core function library *
5712 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5713 * *
5714 ************************************************************************/
5715
5716
5717/**
5718 * xmlXPathLastFunction:
5719 * @ctxt: the XPath Parser context
5720 * @nargs: the number of arguments
5721 *
5722 * Implement the last() XPath function
5723 * number last()
5724 * The last function returns the number of nodes in the context node list.
5725 */
5726void
5727xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5728 CHECK_ARITY(0);
5729 if (ctxt->context->contextSize >= 0) {
5730 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5731#ifdef DEBUG_EXPR
5732 xmlGenericError(xmlGenericErrorContext,
5733 "last() : %d\n", ctxt->context->contextSize);
5734#endif
5735 } else {
5736 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5737 }
5738}
5739
5740/**
5741 * xmlXPathPositionFunction:
5742 * @ctxt: the XPath Parser context
5743 * @nargs: the number of arguments
5744 *
5745 * Implement the position() XPath function
5746 * number position()
5747 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005748 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005749 * will be equal to last().
5750 */
5751void
5752xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5753 CHECK_ARITY(0);
5754 if (ctxt->context->proximityPosition >= 0) {
5755 valuePush(ctxt,
5756 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5757#ifdef DEBUG_EXPR
5758 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5759 ctxt->context->proximityPosition);
5760#endif
5761 } else {
5762 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5763 }
5764}
5765
5766/**
5767 * xmlXPathCountFunction:
5768 * @ctxt: the XPath Parser context
5769 * @nargs: the number of arguments
5770 *
5771 * Implement the count() XPath function
5772 * number count(node-set)
5773 */
5774void
5775xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5776 xmlXPathObjectPtr cur;
5777
5778 CHECK_ARITY(1);
5779 if ((ctxt->value == NULL) ||
5780 ((ctxt->value->type != XPATH_NODESET) &&
5781 (ctxt->value->type != XPATH_XSLT_TREE)))
5782 XP_ERROR(XPATH_INVALID_TYPE);
5783 cur = valuePop(ctxt);
5784
Daniel Veillard911f49a2001-04-07 15:39:35 +00005785 if ((cur == NULL) || (cur->nodesetval == NULL))
5786 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005787 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005788 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005789 } else {
5790 if ((cur->nodesetval->nodeNr != 1) ||
5791 (cur->nodesetval->nodeTab == NULL)) {
5792 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5793 } else {
5794 xmlNodePtr tmp;
5795 int i = 0;
5796
5797 tmp = cur->nodesetval->nodeTab[0];
5798 if (tmp != NULL) {
5799 tmp = tmp->children;
5800 while (tmp != NULL) {
5801 tmp = tmp->next;
5802 i++;
5803 }
5804 }
5805 valuePush(ctxt, xmlXPathNewFloat((double) i));
5806 }
5807 }
Owen Taylor3473f882001-02-23 17:55:21 +00005808 xmlXPathFreeObject(cur);
5809}
5810
5811/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005812 * xmlXPathGetElementsByIds:
5813 * @doc: the document
5814 * @ids: a whitespace separated list of IDs
5815 *
5816 * Selects elements by their unique ID.
5817 *
5818 * Returns a node-set of selected elements.
5819 */
5820static xmlNodeSetPtr
5821xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5822 xmlNodeSetPtr ret;
5823 const xmlChar *cur = ids;
5824 xmlChar *ID;
5825 xmlAttrPtr attr;
5826 xmlNodePtr elem = NULL;
5827
5828 ret = xmlXPathNodeSetCreate(NULL);
5829
5830 while (IS_BLANK(*cur)) cur++;
5831 while (*cur != 0) {
5832 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5833 (*cur == '.') || (*cur == '-') ||
5834 (*cur == '_') || (*cur == ':') ||
5835 (IS_COMBINING(*cur)) ||
5836 (IS_EXTENDER(*cur)))
5837 cur++;
5838
5839 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5840
5841 ID = xmlStrndup(ids, cur - ids);
5842 attr = xmlGetID(doc, ID);
5843 if (attr != NULL) {
5844 elem = attr->parent;
5845 xmlXPathNodeSetAdd(ret, elem);
5846 }
5847 if (ID != NULL)
5848 xmlFree(ID);
5849
5850 while (IS_BLANK(*cur)) cur++;
5851 ids = cur;
5852 }
5853 return(ret);
5854}
5855
5856/**
Owen Taylor3473f882001-02-23 17:55:21 +00005857 * xmlXPathIdFunction:
5858 * @ctxt: the XPath Parser context
5859 * @nargs: the number of arguments
5860 *
5861 * Implement the id() XPath function
5862 * node-set id(object)
5863 * The id function selects elements by their unique ID
5864 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5865 * then the result is the union of the result of applying id to the
5866 * string value of each of the nodes in the argument node-set. When the
5867 * argument to id is of any other type, the argument is converted to a
5868 * string as if by a call to the string function; the string is split
5869 * into a whitespace-separated list of tokens (whitespace is any sequence
5870 * of characters matching the production S); the result is a node-set
5871 * containing the elements in the same document as the context node that
5872 * have a unique ID equal to any of the tokens in the list.
5873 */
5874void
5875xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005876 xmlChar *tokens;
5877 xmlNodeSetPtr ret;
5878 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005879
5880 CHECK_ARITY(1);
5881 obj = valuePop(ctxt);
5882 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00005883 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005884 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005885 int i;
5886
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005887 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005888
Daniel Veillard911f49a2001-04-07 15:39:35 +00005889 if (obj->nodesetval != NULL) {
5890 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005891 tokens =
5892 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5893 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5894 ret = xmlXPathNodeSetMerge(ret, ns);
5895 xmlXPathFreeNodeSet(ns);
5896 if (tokens != NULL)
5897 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005898 }
Owen Taylor3473f882001-02-23 17:55:21 +00005899 }
5900
5901 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005902 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005903 return;
5904 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005905 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005906
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005907 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5908 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005909
Owen Taylor3473f882001-02-23 17:55:21 +00005910 xmlXPathFreeObject(obj);
5911 return;
5912}
5913
5914/**
5915 * xmlXPathLocalNameFunction:
5916 * @ctxt: the XPath Parser context
5917 * @nargs: the number of arguments
5918 *
5919 * Implement the local-name() XPath function
5920 * string local-name(node-set?)
5921 * The local-name function returns a string containing the local part
5922 * of the name of the node in the argument node-set that is first in
5923 * document order. If the node-set is empty or the first node has no
5924 * name, an empty string is returned. If the argument is omitted it
5925 * defaults to the context node.
5926 */
5927void
5928xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5929 xmlXPathObjectPtr cur;
5930
5931 if (nargs == 0) {
5932 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5933 nargs = 1;
5934 }
5935
5936 CHECK_ARITY(1);
5937 if ((ctxt->value == NULL) ||
5938 ((ctxt->value->type != XPATH_NODESET) &&
5939 (ctxt->value->type != XPATH_XSLT_TREE)))
5940 XP_ERROR(XPATH_INVALID_TYPE);
5941 cur = valuePop(ctxt);
5942
Daniel Veillard911f49a2001-04-07 15:39:35 +00005943 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005944 valuePush(ctxt, xmlXPathNewCString(""));
5945 } else {
5946 int i = 0; /* Should be first in document order !!!!! */
5947 switch (cur->nodesetval->nodeTab[i]->type) {
5948 case XML_ELEMENT_NODE:
5949 case XML_ATTRIBUTE_NODE:
5950 case XML_PI_NODE:
5951 valuePush(ctxt,
5952 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5953 break;
5954 case XML_NAMESPACE_DECL:
5955 valuePush(ctxt, xmlXPathNewString(
5956 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5957 break;
5958 default:
5959 valuePush(ctxt, xmlXPathNewCString(""));
5960 }
5961 }
5962 xmlXPathFreeObject(cur);
5963}
5964
5965/**
5966 * xmlXPathNamespaceURIFunction:
5967 * @ctxt: the XPath Parser context
5968 * @nargs: the number of arguments
5969 *
5970 * Implement the namespace-uri() XPath function
5971 * string namespace-uri(node-set?)
5972 * The namespace-uri function returns a string containing the
5973 * namespace URI of the expanded name of the node in the argument
5974 * node-set that is first in document order. If the node-set is empty,
5975 * the first node has no name, or the expanded name has no namespace
5976 * URI, an empty string is returned. If the argument is omitted it
5977 * defaults to the context node.
5978 */
5979void
5980xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5981 xmlXPathObjectPtr cur;
5982
5983 if (nargs == 0) {
5984 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5985 nargs = 1;
5986 }
5987 CHECK_ARITY(1);
5988 if ((ctxt->value == NULL) ||
5989 ((ctxt->value->type != XPATH_NODESET) &&
5990 (ctxt->value->type != XPATH_XSLT_TREE)))
5991 XP_ERROR(XPATH_INVALID_TYPE);
5992 cur = valuePop(ctxt);
5993
Daniel Veillard911f49a2001-04-07 15:39:35 +00005994 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005995 valuePush(ctxt, xmlXPathNewCString(""));
5996 } else {
5997 int i = 0; /* Should be first in document order !!!!! */
5998 switch (cur->nodesetval->nodeTab[i]->type) {
5999 case XML_ELEMENT_NODE:
6000 case XML_ATTRIBUTE_NODE:
6001 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6002 valuePush(ctxt, xmlXPathNewCString(""));
6003 else
6004 valuePush(ctxt, xmlXPathNewString(
6005 cur->nodesetval->nodeTab[i]->ns->href));
6006 break;
6007 default:
6008 valuePush(ctxt, xmlXPathNewCString(""));
6009 }
6010 }
6011 xmlXPathFreeObject(cur);
6012}
6013
6014/**
6015 * xmlXPathNameFunction:
6016 * @ctxt: the XPath Parser context
6017 * @nargs: the number of arguments
6018 *
6019 * Implement the name() XPath function
6020 * string name(node-set?)
6021 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006022 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006023 * order. The QName must represent the name with respect to the namespace
6024 * declarations in effect on the node whose name is being represented.
6025 * Typically, this will be the form in which the name occurred in the XML
6026 * source. This need not be the case if there are namespace declarations
6027 * in effect on the node that associate multiple prefixes with the same
6028 * namespace. However, an implementation may include information about
6029 * the original prefix in its representation of nodes; in this case, an
6030 * implementation can ensure that the returned string is always the same
6031 * as the QName used in the XML source. If the argument it omitted it
6032 * defaults to the context node.
6033 * Libxml keep the original prefix so the "real qualified name" used is
6034 * returned.
6035 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006036static void
Daniel Veillard04383752001-07-08 14:27:15 +00006037xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6038{
Owen Taylor3473f882001-02-23 17:55:21 +00006039 xmlXPathObjectPtr cur;
6040
6041 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006042 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6043 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006044 }
6045
6046 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006047 if ((ctxt->value == NULL) ||
6048 ((ctxt->value->type != XPATH_NODESET) &&
6049 (ctxt->value->type != XPATH_XSLT_TREE)))
6050 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006051 cur = valuePop(ctxt);
6052
Daniel Veillard911f49a2001-04-07 15:39:35 +00006053 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006054 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006055 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006056 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006057
Daniel Veillard04383752001-07-08 14:27:15 +00006058 switch (cur->nodesetval->nodeTab[i]->type) {
6059 case XML_ELEMENT_NODE:
6060 case XML_ATTRIBUTE_NODE:
6061 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6062 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
6063 valuePush(ctxt,
6064 xmlXPathNewString(cur->nodesetval->
6065 nodeTab[i]->name));
6066
6067 else {
6068 char name[2000];
6069
6070 snprintf(name, sizeof(name), "%s:%s",
6071 (char *) cur->nodesetval->nodeTab[i]->ns->
6072 prefix,
6073 (char *) cur->nodesetval->nodeTab[i]->name);
6074 name[sizeof(name) - 1] = 0;
6075 valuePush(ctxt, xmlXPathNewCString(name));
6076 }
6077 break;
6078 default:
6079 valuePush(ctxt,
6080 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6081 xmlXPathLocalNameFunction(ctxt, 1);
6082 }
Owen Taylor3473f882001-02-23 17:55:21 +00006083 }
6084 xmlXPathFreeObject(cur);
6085}
6086
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006087
6088/**
Owen Taylor3473f882001-02-23 17:55:21 +00006089 * xmlXPathStringFunction:
6090 * @ctxt: the XPath Parser context
6091 * @nargs: the number of arguments
6092 *
6093 * Implement the string() XPath function
6094 * string string(object?)
6095 * he string function converts an object to a string as follows:
6096 * - A node-set is converted to a string by returning the value of
6097 * the node in the node-set that is first in document order.
6098 * If the node-set is empty, an empty string is returned.
6099 * - A number is converted to a string as follows
6100 * + NaN is converted to the string NaN
6101 * + positive zero is converted to the string 0
6102 * + negative zero is converted to the string 0
6103 * + positive infinity is converted to the string Infinity
6104 * + negative infinity is converted to the string -Infinity
6105 * + if the number is an integer, the number is represented in
6106 * decimal form as a Number with no decimal point and no leading
6107 * zeros, preceded by a minus sign (-) if the number is negative
6108 * + otherwise, the number is represented in decimal form as a
6109 * Number including a decimal point with at least one digit
6110 * before the decimal point and at least one digit after the
6111 * decimal point, preceded by a minus sign (-) if the number
6112 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006113 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006114 * before the decimal point; beyond the one required digit
6115 * after the decimal point there must be as many, but only as
6116 * many, more digits as are needed to uniquely distinguish the
6117 * number from all other IEEE 754 numeric values.
6118 * - The boolean false value is converted to the string false.
6119 * The boolean true value is converted to the string true.
6120 *
6121 * If the argument is omitted, it defaults to a node-set with the
6122 * context node as its only member.
6123 */
6124void
6125xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6126 xmlXPathObjectPtr cur;
6127
6128 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006129 valuePush(ctxt,
6130 xmlXPathWrapString(
6131 xmlXPathCastNodeToString(ctxt->context->node)));
6132 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006133 }
6134
6135 CHECK_ARITY(1);
6136 cur = valuePop(ctxt);
6137 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006138 cur = xmlXPathConvertString(cur);
6139 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006140}
6141
6142/**
6143 * xmlXPathStringLengthFunction:
6144 * @ctxt: the XPath Parser context
6145 * @nargs: the number of arguments
6146 *
6147 * Implement the string-length() XPath function
6148 * number string-length(string?)
6149 * The string-length returns the number of characters in the string
6150 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6151 * the context node converted to a string, in other words the value
6152 * of the context node.
6153 */
6154void
6155xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6156 xmlXPathObjectPtr cur;
6157
6158 if (nargs == 0) {
6159 if (ctxt->context->node == NULL) {
6160 valuePush(ctxt, xmlXPathNewFloat(0));
6161 } else {
6162 xmlChar *content;
6163
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006164 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006165 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006166 xmlFree(content);
6167 }
6168 return;
6169 }
6170 CHECK_ARITY(1);
6171 CAST_TO_STRING;
6172 CHECK_TYPE(XPATH_STRING);
6173 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006174 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006175 xmlXPathFreeObject(cur);
6176}
6177
6178/**
6179 * xmlXPathConcatFunction:
6180 * @ctxt: the XPath Parser context
6181 * @nargs: the number of arguments
6182 *
6183 * Implement the concat() XPath function
6184 * string concat(string, string, string*)
6185 * The concat function returns the concatenation of its arguments.
6186 */
6187void
6188xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6189 xmlXPathObjectPtr cur, newobj;
6190 xmlChar *tmp;
6191
6192 if (nargs < 2) {
6193 CHECK_ARITY(2);
6194 }
6195
6196 CAST_TO_STRING;
6197 cur = valuePop(ctxt);
6198 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6199 xmlXPathFreeObject(cur);
6200 return;
6201 }
6202 nargs--;
6203
6204 while (nargs > 0) {
6205 CAST_TO_STRING;
6206 newobj = valuePop(ctxt);
6207 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6208 xmlXPathFreeObject(newobj);
6209 xmlXPathFreeObject(cur);
6210 XP_ERROR(XPATH_INVALID_TYPE);
6211 }
6212 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6213 newobj->stringval = cur->stringval;
6214 cur->stringval = tmp;
6215
6216 xmlXPathFreeObject(newobj);
6217 nargs--;
6218 }
6219 valuePush(ctxt, cur);
6220}
6221
6222/**
6223 * xmlXPathContainsFunction:
6224 * @ctxt: the XPath Parser context
6225 * @nargs: the number of arguments
6226 *
6227 * Implement the contains() XPath function
6228 * boolean contains(string, string)
6229 * The contains function returns true if the first argument string
6230 * contains the second argument string, and otherwise returns false.
6231 */
6232void
6233xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6234 xmlXPathObjectPtr hay, needle;
6235
6236 CHECK_ARITY(2);
6237 CAST_TO_STRING;
6238 CHECK_TYPE(XPATH_STRING);
6239 needle = valuePop(ctxt);
6240 CAST_TO_STRING;
6241 hay = valuePop(ctxt);
6242 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6243 xmlXPathFreeObject(hay);
6244 xmlXPathFreeObject(needle);
6245 XP_ERROR(XPATH_INVALID_TYPE);
6246 }
6247 if (xmlStrstr(hay->stringval, needle->stringval))
6248 valuePush(ctxt, xmlXPathNewBoolean(1));
6249 else
6250 valuePush(ctxt, xmlXPathNewBoolean(0));
6251 xmlXPathFreeObject(hay);
6252 xmlXPathFreeObject(needle);
6253}
6254
6255/**
6256 * xmlXPathStartsWithFunction:
6257 * @ctxt: the XPath Parser context
6258 * @nargs: the number of arguments
6259 *
6260 * Implement the starts-with() XPath function
6261 * boolean starts-with(string, string)
6262 * The starts-with function returns true if the first argument string
6263 * starts with the second argument string, and otherwise returns false.
6264 */
6265void
6266xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6267 xmlXPathObjectPtr hay, needle;
6268 int n;
6269
6270 CHECK_ARITY(2);
6271 CAST_TO_STRING;
6272 CHECK_TYPE(XPATH_STRING);
6273 needle = valuePop(ctxt);
6274 CAST_TO_STRING;
6275 hay = valuePop(ctxt);
6276 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6277 xmlXPathFreeObject(hay);
6278 xmlXPathFreeObject(needle);
6279 XP_ERROR(XPATH_INVALID_TYPE);
6280 }
6281 n = xmlStrlen(needle->stringval);
6282 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6283 valuePush(ctxt, xmlXPathNewBoolean(0));
6284 else
6285 valuePush(ctxt, xmlXPathNewBoolean(1));
6286 xmlXPathFreeObject(hay);
6287 xmlXPathFreeObject(needle);
6288}
6289
6290/**
6291 * xmlXPathSubstringFunction:
6292 * @ctxt: the XPath Parser context
6293 * @nargs: the number of arguments
6294 *
6295 * Implement the substring() XPath function
6296 * string substring(string, number, number?)
6297 * The substring function returns the substring of the first argument
6298 * starting at the position specified in the second argument with
6299 * length specified in the third argument. For example,
6300 * substring("12345",2,3) returns "234". If the third argument is not
6301 * specified, it returns the substring starting at the position specified
6302 * in the second argument and continuing to the end of the string. For
6303 * example, substring("12345",2) returns "2345". More precisely, each
6304 * character in the string (see [3.6 Strings]) is considered to have a
6305 * numeric position: the position of the first character is 1, the position
6306 * of the second character is 2 and so on. The returned substring contains
6307 * those characters for which the position of the character is greater than
6308 * or equal to the second argument and, if the third argument is specified,
6309 * less than the sum of the second and third arguments; the comparisons
6310 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6311 * - substring("12345", 1.5, 2.6) returns "234"
6312 * - substring("12345", 0, 3) returns "12"
6313 * - substring("12345", 0 div 0, 3) returns ""
6314 * - substring("12345", 1, 0 div 0) returns ""
6315 * - substring("12345", -42, 1 div 0) returns "12345"
6316 * - substring("12345", -1 div 0, 1 div 0) returns ""
6317 */
6318void
6319xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6320 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006321 double le=0, in;
6322 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006323 xmlChar *ret;
6324
Owen Taylor3473f882001-02-23 17:55:21 +00006325 if (nargs < 2) {
6326 CHECK_ARITY(2);
6327 }
6328 if (nargs > 3) {
6329 CHECK_ARITY(3);
6330 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006331 /*
6332 * take care of possible last (position) argument
6333 */
Owen Taylor3473f882001-02-23 17:55:21 +00006334 if (nargs == 3) {
6335 CAST_TO_NUMBER;
6336 CHECK_TYPE(XPATH_NUMBER);
6337 len = valuePop(ctxt);
6338 le = len->floatval;
6339 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006340 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006341
Owen Taylor3473f882001-02-23 17:55:21 +00006342 CAST_TO_NUMBER;
6343 CHECK_TYPE(XPATH_NUMBER);
6344 start = valuePop(ctxt);
6345 in = start->floatval;
6346 xmlXPathFreeObject(start);
6347 CAST_TO_STRING;
6348 CHECK_TYPE(XPATH_STRING);
6349 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006350 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006351
Daniel Veillard97ac1312001-05-30 19:14:17 +00006352 /*
6353 * If last pos not present, calculate last position
6354 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006355 if (nargs != 3) {
6356 le = (double)m;
6357 if (in < 1.0)
6358 in = 1.0;
6359 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006360
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006361 /* Need to check for the special cases where either
6362 * the index is NaN, the length is NaN, or both
6363 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006364 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006365 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006366 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006367 * To meet the requirements of the spec, the arguments
6368 * must be converted to integer format before
6369 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006370 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006371 * First we go to integer form, rounding up
6372 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006373 */
6374 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006375 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006376
Daniel Veillard9e412302002-06-10 15:59:44 +00006377 if (xmlXPathIsInf(le) == 1) {
6378 l = m;
6379 if (i < 1)
6380 i = 1;
6381 }
6382 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6383 l = 0;
6384 else {
6385 l = (int) le;
6386 if (((double)l)+0.5 <= le) l++;
6387 }
6388
6389 /* Now we normalize inidices */
6390 i -= 1;
6391 l += i;
6392 if (i < 0)
6393 i = 0;
6394 if (l > m)
6395 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006396
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006397 /* number of chars to copy */
6398 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006399
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006400 ret = xmlUTF8Strsub(str->stringval, i, l);
6401 }
6402 else {
6403 ret = NULL;
6404 }
6405
Owen Taylor3473f882001-02-23 17:55:21 +00006406 if (ret == NULL)
6407 valuePush(ctxt, xmlXPathNewCString(""));
6408 else {
6409 valuePush(ctxt, xmlXPathNewString(ret));
6410 xmlFree(ret);
6411 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006412
Owen Taylor3473f882001-02-23 17:55:21 +00006413 xmlXPathFreeObject(str);
6414}
6415
6416/**
6417 * xmlXPathSubstringBeforeFunction:
6418 * @ctxt: the XPath Parser context
6419 * @nargs: the number of arguments
6420 *
6421 * Implement the substring-before() XPath function
6422 * string substring-before(string, string)
6423 * The substring-before function returns the substring of the first
6424 * argument string that precedes the first occurrence of the second
6425 * argument string in the first argument string, or the empty string
6426 * if the first argument string does not contain the second argument
6427 * string. For example, substring-before("1999/04/01","/") returns 1999.
6428 */
6429void
6430xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6431 xmlXPathObjectPtr str;
6432 xmlXPathObjectPtr find;
6433 xmlBufferPtr target;
6434 const xmlChar *point;
6435 int offset;
6436
6437 CHECK_ARITY(2);
6438 CAST_TO_STRING;
6439 find = valuePop(ctxt);
6440 CAST_TO_STRING;
6441 str = valuePop(ctxt);
6442
6443 target = xmlBufferCreate();
6444 if (target) {
6445 point = xmlStrstr(str->stringval, find->stringval);
6446 if (point) {
6447 offset = (int)(point - str->stringval);
6448 xmlBufferAdd(target, str->stringval, offset);
6449 }
6450 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6451 xmlBufferFree(target);
6452 }
6453
6454 xmlXPathFreeObject(str);
6455 xmlXPathFreeObject(find);
6456}
6457
6458/**
6459 * xmlXPathSubstringAfterFunction:
6460 * @ctxt: the XPath Parser context
6461 * @nargs: the number of arguments
6462 *
6463 * Implement the substring-after() XPath function
6464 * string substring-after(string, string)
6465 * The substring-after function returns the substring of the first
6466 * argument string that follows the first occurrence of the second
6467 * argument string in the first argument string, or the empty stringi
6468 * if the first argument string does not contain the second argument
6469 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6470 * and substring-after("1999/04/01","19") returns 99/04/01.
6471 */
6472void
6473xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6474 xmlXPathObjectPtr str;
6475 xmlXPathObjectPtr find;
6476 xmlBufferPtr target;
6477 const xmlChar *point;
6478 int offset;
6479
6480 CHECK_ARITY(2);
6481 CAST_TO_STRING;
6482 find = valuePop(ctxt);
6483 CAST_TO_STRING;
6484 str = valuePop(ctxt);
6485
6486 target = xmlBufferCreate();
6487 if (target) {
6488 point = xmlStrstr(str->stringval, find->stringval);
6489 if (point) {
6490 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6491 xmlBufferAdd(target, &str->stringval[offset],
6492 xmlStrlen(str->stringval) - offset);
6493 }
6494 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6495 xmlBufferFree(target);
6496 }
6497
6498 xmlXPathFreeObject(str);
6499 xmlXPathFreeObject(find);
6500}
6501
6502/**
6503 * xmlXPathNormalizeFunction:
6504 * @ctxt: the XPath Parser context
6505 * @nargs: the number of arguments
6506 *
6507 * Implement the normalize-space() XPath function
6508 * string normalize-space(string?)
6509 * The normalize-space function returns the argument string with white
6510 * space normalized by stripping leading and trailing whitespace
6511 * and replacing sequences of whitespace characters by a single
6512 * space. Whitespace characters are the same allowed by the S production
6513 * in XML. If the argument is omitted, it defaults to the context
6514 * node converted to a string, in other words the value of the context node.
6515 */
6516void
6517xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6518 xmlXPathObjectPtr obj = NULL;
6519 xmlChar *source = NULL;
6520 xmlBufferPtr target;
6521 xmlChar blank;
6522
6523 if (nargs == 0) {
6524 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006525 valuePush(ctxt,
6526 xmlXPathWrapString(
6527 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006528 nargs = 1;
6529 }
6530
6531 CHECK_ARITY(1);
6532 CAST_TO_STRING;
6533 CHECK_TYPE(XPATH_STRING);
6534 obj = valuePop(ctxt);
6535 source = obj->stringval;
6536
6537 target = xmlBufferCreate();
6538 if (target && source) {
6539
6540 /* Skip leading whitespaces */
6541 while (IS_BLANK(*source))
6542 source++;
6543
6544 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6545 blank = 0;
6546 while (*source) {
6547 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006548 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006549 } else {
6550 if (blank) {
6551 xmlBufferAdd(target, &blank, 1);
6552 blank = 0;
6553 }
6554 xmlBufferAdd(target, source, 1);
6555 }
6556 source++;
6557 }
6558
6559 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6560 xmlBufferFree(target);
6561 }
6562 xmlXPathFreeObject(obj);
6563}
6564
6565/**
6566 * xmlXPathTranslateFunction:
6567 * @ctxt: the XPath Parser context
6568 * @nargs: the number of arguments
6569 *
6570 * Implement the translate() XPath function
6571 * string translate(string, string, string)
6572 * The translate function returns the first argument string with
6573 * occurrences of characters in the second argument string replaced
6574 * by the character at the corresponding position in the third argument
6575 * string. For example, translate("bar","abc","ABC") returns the string
6576 * BAr. If there is a character in the second argument string with no
6577 * character at a corresponding position in the third argument string
6578 * (because the second argument string is longer than the third argument
6579 * string), then occurrences of that character in the first argument
6580 * string are removed. For example, translate("--aaa--","abc-","ABC")
6581 * returns "AAA". If a character occurs more than once in second
6582 * argument string, then the first occurrence determines the replacement
6583 * character. If the third argument string is longer than the second
6584 * argument string, then excess characters are ignored.
6585 */
6586void
6587xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006588 xmlXPathObjectPtr str;
6589 xmlXPathObjectPtr from;
6590 xmlXPathObjectPtr to;
6591 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006592 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006593 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006594 xmlChar *point;
6595 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006596
Daniel Veillarde043ee12001-04-16 14:08:07 +00006597 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006598
Daniel Veillarde043ee12001-04-16 14:08:07 +00006599 CAST_TO_STRING;
6600 to = valuePop(ctxt);
6601 CAST_TO_STRING;
6602 from = valuePop(ctxt);
6603 CAST_TO_STRING;
6604 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006605
Daniel Veillarde043ee12001-04-16 14:08:07 +00006606 target = xmlBufferCreate();
6607 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006608 max = xmlUTF8Strlen(to->stringval);
6609 for (cptr = str->stringval; (ch=*cptr); ) {
6610 offset = xmlUTF8Strloc(from->stringval, cptr);
6611 if (offset >= 0) {
6612 if (offset < max) {
6613 point = xmlUTF8Strpos(to->stringval, offset);
6614 if (point)
6615 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6616 }
6617 } else
6618 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6619
6620 /* Step to next character in input */
6621 cptr++;
6622 if ( ch & 0x80 ) {
6623 /* if not simple ascii, verify proper format */
6624 if ( (ch & 0xc0) != 0xc0 ) {
6625 xmlGenericError(xmlGenericErrorContext,
6626 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6627 break;
6628 }
6629 /* then skip over remaining bytes for this char */
6630 while ( (ch <<= 1) & 0x80 )
6631 if ( (*cptr++ & 0xc0) != 0x80 ) {
6632 xmlGenericError(xmlGenericErrorContext,
6633 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6634 break;
6635 }
6636 if (ch & 0x80) /* must have had error encountered */
6637 break;
6638 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006639 }
Owen Taylor3473f882001-02-23 17:55:21 +00006640 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006641 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6642 xmlBufferFree(target);
6643 xmlXPathFreeObject(str);
6644 xmlXPathFreeObject(from);
6645 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006646}
6647
6648/**
6649 * xmlXPathBooleanFunction:
6650 * @ctxt: the XPath Parser context
6651 * @nargs: the number of arguments
6652 *
6653 * Implement the boolean() XPath function
6654 * boolean boolean(object)
6655 * he boolean function converts its argument to a boolean as follows:
6656 * - a number is true if and only if it is neither positive or
6657 * negative zero nor NaN
6658 * - a node-set is true if and only if it is non-empty
6659 * - a string is true if and only if its length is non-zero
6660 */
6661void
6662xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6663 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006664
6665 CHECK_ARITY(1);
6666 cur = valuePop(ctxt);
6667 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006668 cur = xmlXPathConvertBoolean(cur);
6669 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006670}
6671
6672/**
6673 * xmlXPathNotFunction:
6674 * @ctxt: the XPath Parser context
6675 * @nargs: the number of arguments
6676 *
6677 * Implement the not() XPath function
6678 * boolean not(boolean)
6679 * The not function returns true if its argument is false,
6680 * and false otherwise.
6681 */
6682void
6683xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6684 CHECK_ARITY(1);
6685 CAST_TO_BOOLEAN;
6686 CHECK_TYPE(XPATH_BOOLEAN);
6687 ctxt->value->boolval = ! ctxt->value->boolval;
6688}
6689
6690/**
6691 * xmlXPathTrueFunction:
6692 * @ctxt: the XPath Parser context
6693 * @nargs: the number of arguments
6694 *
6695 * Implement the true() XPath function
6696 * boolean true()
6697 */
6698void
6699xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6700 CHECK_ARITY(0);
6701 valuePush(ctxt, xmlXPathNewBoolean(1));
6702}
6703
6704/**
6705 * xmlXPathFalseFunction:
6706 * @ctxt: the XPath Parser context
6707 * @nargs: the number of arguments
6708 *
6709 * Implement the false() XPath function
6710 * boolean false()
6711 */
6712void
6713xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6714 CHECK_ARITY(0);
6715 valuePush(ctxt, xmlXPathNewBoolean(0));
6716}
6717
6718/**
6719 * xmlXPathLangFunction:
6720 * @ctxt: the XPath Parser context
6721 * @nargs: the number of arguments
6722 *
6723 * Implement the lang() XPath function
6724 * boolean lang(string)
6725 * The lang function returns true or false depending on whether the
6726 * language of the context node as specified by xml:lang attributes
6727 * is the same as or is a sublanguage of the language specified by
6728 * the argument string. The language of the context node is determined
6729 * by the value of the xml:lang attribute on the context node, or, if
6730 * the context node has no xml:lang attribute, by the value of the
6731 * xml:lang attribute on the nearest ancestor of the context node that
6732 * has an xml:lang attribute. If there is no such attribute, then lang
6733 * returns false. If there is such an attribute, then lang returns
6734 * true if the attribute value is equal to the argument ignoring case,
6735 * or if there is some suffix starting with - such that the attribute
6736 * value is equal to the argument ignoring that suffix of the attribute
6737 * value and ignoring case.
6738 */
6739void
6740xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6741 xmlXPathObjectPtr val;
6742 const xmlChar *theLang;
6743 const xmlChar *lang;
6744 int ret = 0;
6745 int i;
6746
6747 CHECK_ARITY(1);
6748 CAST_TO_STRING;
6749 CHECK_TYPE(XPATH_STRING);
6750 val = valuePop(ctxt);
6751 lang = val->stringval;
6752 theLang = xmlNodeGetLang(ctxt->context->node);
6753 if ((theLang != NULL) && (lang != NULL)) {
6754 for (i = 0;lang[i] != 0;i++)
6755 if (toupper(lang[i]) != toupper(theLang[i]))
6756 goto not_equal;
6757 ret = 1;
6758 }
6759not_equal:
6760 xmlXPathFreeObject(val);
6761 valuePush(ctxt, xmlXPathNewBoolean(ret));
6762}
6763
6764/**
6765 * xmlXPathNumberFunction:
6766 * @ctxt: the XPath Parser context
6767 * @nargs: the number of arguments
6768 *
6769 * Implement the number() XPath function
6770 * number number(object?)
6771 */
6772void
6773xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6774 xmlXPathObjectPtr cur;
6775 double res;
6776
6777 if (nargs == 0) {
6778 if (ctxt->context->node == NULL) {
6779 valuePush(ctxt, xmlXPathNewFloat(0.0));
6780 } else {
6781 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6782
6783 res = xmlXPathStringEvalNumber(content);
6784 valuePush(ctxt, xmlXPathNewFloat(res));
6785 xmlFree(content);
6786 }
6787 return;
6788 }
6789
6790 CHECK_ARITY(1);
6791 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006792 cur = xmlXPathConvertNumber(cur);
6793 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006794}
6795
6796/**
6797 * xmlXPathSumFunction:
6798 * @ctxt: the XPath Parser context
6799 * @nargs: the number of arguments
6800 *
6801 * Implement the sum() XPath function
6802 * number sum(node-set)
6803 * The sum function returns the sum of the values of the nodes in
6804 * the argument node-set.
6805 */
6806void
6807xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6808 xmlXPathObjectPtr cur;
6809 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006810 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006811
6812 CHECK_ARITY(1);
6813 if ((ctxt->value == NULL) ||
6814 ((ctxt->value->type != XPATH_NODESET) &&
6815 (ctxt->value->type != XPATH_XSLT_TREE)))
6816 XP_ERROR(XPATH_INVALID_TYPE);
6817 cur = valuePop(ctxt);
6818
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006819 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006820 valuePush(ctxt, xmlXPathNewFloat(0.0));
6821 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006822 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6823 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006824 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006825 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006826 }
6827 xmlXPathFreeObject(cur);
6828}
6829
6830/**
6831 * xmlXPathFloorFunction:
6832 * @ctxt: the XPath Parser context
6833 * @nargs: the number of arguments
6834 *
6835 * Implement the floor() XPath function
6836 * number floor(number)
6837 * The floor function returns the largest (closest to positive infinity)
6838 * number that is not greater than the argument and that is an integer.
6839 */
6840void
6841xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006842 double f;
6843
Owen Taylor3473f882001-02-23 17:55:21 +00006844 CHECK_ARITY(1);
6845 CAST_TO_NUMBER;
6846 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006847
6848 f = (double)((int) ctxt->value->floatval);
6849 if (f != ctxt->value->floatval) {
6850 if (ctxt->value->floatval > 0)
6851 ctxt->value->floatval = f;
6852 else
6853 ctxt->value->floatval = f - 1;
6854 }
Owen Taylor3473f882001-02-23 17:55:21 +00006855}
6856
6857/**
6858 * xmlXPathCeilingFunction:
6859 * @ctxt: the XPath Parser context
6860 * @nargs: the number of arguments
6861 *
6862 * Implement the ceiling() XPath function
6863 * number ceiling(number)
6864 * The ceiling function returns the smallest (closest to negative infinity)
6865 * number that is not less than the argument and that is an integer.
6866 */
6867void
6868xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6869 double f;
6870
6871 CHECK_ARITY(1);
6872 CAST_TO_NUMBER;
6873 CHECK_TYPE(XPATH_NUMBER);
6874
6875#if 0
6876 ctxt->value->floatval = ceil(ctxt->value->floatval);
6877#else
6878 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006879 if (f != ctxt->value->floatval) {
6880 if (ctxt->value->floatval > 0)
6881 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006882 else {
6883 if (ctxt->value->floatval < 0 && f == 0)
6884 ctxt->value->floatval = xmlXPathNZERO;
6885 else
6886 ctxt->value->floatval = f;
6887 }
6888
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006889 }
Owen Taylor3473f882001-02-23 17:55:21 +00006890#endif
6891}
6892
6893/**
6894 * xmlXPathRoundFunction:
6895 * @ctxt: the XPath Parser context
6896 * @nargs: the number of arguments
6897 *
6898 * Implement the round() XPath function
6899 * number round(number)
6900 * The round function returns the number that is closest to the
6901 * argument and that is an integer. If there are two such numbers,
6902 * then the one that is even is returned.
6903 */
6904void
6905xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6906 double f;
6907
6908 CHECK_ARITY(1);
6909 CAST_TO_NUMBER;
6910 CHECK_TYPE(XPATH_NUMBER);
6911
Daniel Veillardcda96922001-08-21 10:56:31 +00006912 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6913 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6914 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006915 (ctxt->value->floatval == 0.0))
6916 return;
6917
Owen Taylor3473f882001-02-23 17:55:21 +00006918 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006919 if (ctxt->value->floatval < 0) {
6920 if (ctxt->value->floatval < f - 0.5)
6921 ctxt->value->floatval = f - 1;
6922 else
6923 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00006924 if (ctxt->value->floatval == 0)
6925 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006926 } else {
6927 if (ctxt->value->floatval < f + 0.5)
6928 ctxt->value->floatval = f;
6929 else
6930 ctxt->value->floatval = f + 1;
6931 }
Owen Taylor3473f882001-02-23 17:55:21 +00006932}
6933
6934/************************************************************************
6935 * *
6936 * The Parser *
6937 * *
6938 ************************************************************************/
6939
6940/*
6941 * a couple of forward declarations since we use a recursive call based
6942 * implementation.
6943 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006944static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006945static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006946static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006947static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00006948static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6949 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006950
6951/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006952 * xmlXPathCurrentChar:
6953 * @ctxt: the XPath parser context
6954 * @cur: pointer to the beginning of the char
6955 * @len: pointer to the length of the char read
6956 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006957 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006958 * bytes in the input buffer.
6959 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006960 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006961 */
6962
6963static int
6964xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6965 unsigned char c;
6966 unsigned int val;
6967 const xmlChar *cur;
6968
6969 if (ctxt == NULL)
6970 return(0);
6971 cur = ctxt->cur;
6972
6973 /*
6974 * We are supposed to handle UTF8, check it's valid
6975 * From rfc2044: encoding of the Unicode values on UTF-8:
6976 *
6977 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6978 * 0000 0000-0000 007F 0xxxxxxx
6979 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6980 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6981 *
6982 * Check for the 0x110000 limit too
6983 */
6984 c = *cur;
6985 if (c & 0x80) {
6986 if ((cur[1] & 0xc0) != 0x80)
6987 goto encoding_error;
6988 if ((c & 0xe0) == 0xe0) {
6989
6990 if ((cur[2] & 0xc0) != 0x80)
6991 goto encoding_error;
6992 if ((c & 0xf0) == 0xf0) {
6993 if (((c & 0xf8) != 0xf0) ||
6994 ((cur[3] & 0xc0) != 0x80))
6995 goto encoding_error;
6996 /* 4-byte code */
6997 *len = 4;
6998 val = (cur[0] & 0x7) << 18;
6999 val |= (cur[1] & 0x3f) << 12;
7000 val |= (cur[2] & 0x3f) << 6;
7001 val |= cur[3] & 0x3f;
7002 } else {
7003 /* 3-byte code */
7004 *len = 3;
7005 val = (cur[0] & 0xf) << 12;
7006 val |= (cur[1] & 0x3f) << 6;
7007 val |= cur[2] & 0x3f;
7008 }
7009 } else {
7010 /* 2-byte code */
7011 *len = 2;
7012 val = (cur[0] & 0x1f) << 6;
7013 val |= cur[1] & 0x3f;
7014 }
7015 if (!IS_CHAR(val)) {
7016 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7017 }
7018 return(val);
7019 } else {
7020 /* 1-byte code */
7021 *len = 1;
7022 return((int) *cur);
7023 }
7024encoding_error:
7025 /*
7026 * If we detect an UTF8 error that probably mean that the
7027 * input encoding didn't get properly advertized in the
7028 * declaration header. Report the error and switch the encoding
7029 * to ISO-Latin-1 (if you don't like this policy, just declare the
7030 * encoding !)
7031 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007032 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007033 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007034}
7035
7036/**
Owen Taylor3473f882001-02-23 17:55:21 +00007037 * xmlXPathParseNCName:
7038 * @ctxt: the XPath Parser context
7039 *
7040 * parse an XML namespace non qualified name.
7041 *
7042 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7043 *
7044 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7045 * CombiningChar | Extender
7046 *
7047 * Returns the namespace name or NULL
7048 */
7049
7050xmlChar *
7051xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007052 const xmlChar *in;
7053 xmlChar *ret;
7054 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007055
Daniel Veillard2156a562001-04-28 12:24:34 +00007056 /*
7057 * Accelerator for simple ASCII names
7058 */
7059 in = ctxt->cur;
7060 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7061 ((*in >= 0x41) && (*in <= 0x5A)) ||
7062 (*in == '_')) {
7063 in++;
7064 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7065 ((*in >= 0x41) && (*in <= 0x5A)) ||
7066 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007067 (*in == '_') || (*in == '.') ||
7068 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007069 in++;
7070 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7071 (*in == '[') || (*in == ']') || (*in == ':') ||
7072 (*in == '@') || (*in == '*')) {
7073 count = in - ctxt->cur;
7074 if (count == 0)
7075 return(NULL);
7076 ret = xmlStrndup(ctxt->cur, count);
7077 ctxt->cur = in;
7078 return(ret);
7079 }
7080 }
7081 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007082}
7083
Daniel Veillard2156a562001-04-28 12:24:34 +00007084
Owen Taylor3473f882001-02-23 17:55:21 +00007085/**
7086 * xmlXPathParseQName:
7087 * @ctxt: the XPath Parser context
7088 * @prefix: a xmlChar **
7089 *
7090 * parse an XML qualified name
7091 *
7092 * [NS 5] QName ::= (Prefix ':')? LocalPart
7093 *
7094 * [NS 6] Prefix ::= NCName
7095 *
7096 * [NS 7] LocalPart ::= NCName
7097 *
7098 * Returns the function returns the local part, and prefix is updated
7099 * to get the Prefix if any.
7100 */
7101
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007102static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007103xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7104 xmlChar *ret = NULL;
7105
7106 *prefix = NULL;
7107 ret = xmlXPathParseNCName(ctxt);
7108 if (CUR == ':') {
7109 *prefix = ret;
7110 NEXT;
7111 ret = xmlXPathParseNCName(ctxt);
7112 }
7113 return(ret);
7114}
7115
7116/**
7117 * xmlXPathParseName:
7118 * @ctxt: the XPath Parser context
7119 *
7120 * parse an XML name
7121 *
7122 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7123 * CombiningChar | Extender
7124 *
7125 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7126 *
7127 * Returns the namespace name or NULL
7128 */
7129
7130xmlChar *
7131xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007132 const xmlChar *in;
7133 xmlChar *ret;
7134 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007135
Daniel Veillard61d80a22001-04-27 17:13:01 +00007136 /*
7137 * Accelerator for simple ASCII names
7138 */
7139 in = ctxt->cur;
7140 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7141 ((*in >= 0x41) && (*in <= 0x5A)) ||
7142 (*in == '_') || (*in == ':')) {
7143 in++;
7144 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7145 ((*in >= 0x41) && (*in <= 0x5A)) ||
7146 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007147 (*in == '_') || (*in == '-') ||
7148 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007149 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007150 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007151 count = in - ctxt->cur;
7152 ret = xmlStrndup(ctxt->cur, count);
7153 ctxt->cur = in;
7154 return(ret);
7155 }
7156 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007157 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007158}
7159
Daniel Veillard61d80a22001-04-27 17:13:01 +00007160static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007161xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007162 xmlChar buf[XML_MAX_NAMELEN + 5];
7163 int len = 0, l;
7164 int c;
7165
7166 /*
7167 * Handler for more complex cases
7168 */
7169 c = CUR_CHAR(l);
7170 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007171 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7172 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007173 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007174 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007175 return(NULL);
7176 }
7177
7178 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7179 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7180 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007181 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007182 (IS_COMBINING(c)) ||
7183 (IS_EXTENDER(c)))) {
7184 COPY_BUF(l,buf,len,c);
7185 NEXTL(l);
7186 c = CUR_CHAR(l);
7187 if (len >= XML_MAX_NAMELEN) {
7188 /*
7189 * Okay someone managed to make a huge name, so he's ready to pay
7190 * for the processing speed.
7191 */
7192 xmlChar *buffer;
7193 int max = len * 2;
7194
7195 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7196 if (buffer == NULL) {
7197 XP_ERROR0(XPATH_MEMORY_ERROR);
7198 }
7199 memcpy(buffer, buf, len);
7200 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7201 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007202 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007203 (IS_COMBINING(c)) ||
7204 (IS_EXTENDER(c))) {
7205 if (len + 10 > max) {
7206 max *= 2;
7207 buffer = (xmlChar *) xmlRealloc(buffer,
7208 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007209 if (buffer == NULL) {
7210 XP_ERROR0(XPATH_MEMORY_ERROR);
7211 }
7212 }
7213 COPY_BUF(l,buffer,len,c);
7214 NEXTL(l);
7215 c = CUR_CHAR(l);
7216 }
7217 buffer[len] = 0;
7218 return(buffer);
7219 }
7220 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007221 if (len == 0)
7222 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007223 return(xmlStrndup(buf, len));
7224}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007225
7226#define MAX_FRAC 20
7227
7228static double my_pow10[MAX_FRAC] = {
7229 1.0, 10.0, 100.0, 1000.0, 10000.0,
7230 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7231 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7232 100000000000000.0,
7233 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7234 1000000000000000000.0, 10000000000000000000.0
7235};
7236
Owen Taylor3473f882001-02-23 17:55:21 +00007237/**
7238 * xmlXPathStringEvalNumber:
7239 * @str: A string to scan
7240 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007241 * [30a] Float ::= Number ('e' Digits?)?
7242 *
Owen Taylor3473f882001-02-23 17:55:21 +00007243 * [30] Number ::= Digits ('.' Digits?)?
7244 * | '.' Digits
7245 * [31] Digits ::= [0-9]+
7246 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007247 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007248 * In complement of the Number expression, this function also handles
7249 * negative values : '-' Number.
7250 *
7251 * Returns the double value.
7252 */
7253double
7254xmlXPathStringEvalNumber(const xmlChar *str) {
7255 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007256 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007257 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007258 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007259 int exponent = 0;
7260 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007261#ifdef __GNUC__
7262 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007263 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007264#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007265 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007266 while (IS_BLANK(*cur)) cur++;
7267 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7268 return(xmlXPathNAN);
7269 }
7270 if (*cur == '-') {
7271 isneg = 1;
7272 cur++;
7273 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007274
7275#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007276 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007277 * tmp/temp is a workaround against a gcc compiler bug
7278 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007279 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007280 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007281 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007282 ret = ret * 10;
7283 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007284 ok = 1;
7285 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007286 temp = (double) tmp;
7287 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007288 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007289#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007290 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007291 while ((*cur >= '0') && (*cur <= '9')) {
7292 ret = ret * 10 + (*cur - '0');
7293 ok = 1;
7294 cur++;
7295 }
7296#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007297
Owen Taylor3473f882001-02-23 17:55:21 +00007298 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007299 int v, frac = 0;
7300 double fraction = 0;
7301
Owen Taylor3473f882001-02-23 17:55:21 +00007302 cur++;
7303 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7304 return(xmlXPathNAN);
7305 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007306 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7307 v = (*cur - '0');
7308 fraction = fraction * 10 + v;
7309 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007310 cur++;
7311 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007312 fraction /= my_pow10[frac];
7313 ret = ret + fraction;
7314 while ((*cur >= '0') && (*cur <= '9'))
7315 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007316 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007317 if ((*cur == 'e') || (*cur == 'E')) {
7318 cur++;
7319 if (*cur == '-') {
7320 is_exponent_negative = 1;
7321 cur++;
7322 }
7323 while ((*cur >= '0') && (*cur <= '9')) {
7324 exponent = exponent * 10 + (*cur - '0');
7325 cur++;
7326 }
7327 }
Owen Taylor3473f882001-02-23 17:55:21 +00007328 while (IS_BLANK(*cur)) cur++;
7329 if (*cur != 0) return(xmlXPathNAN);
7330 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007331 if (is_exponent_negative) exponent = -exponent;
7332 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007333 return(ret);
7334}
7335
7336/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007337 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007338 * @ctxt: the XPath Parser context
7339 *
7340 * [30] Number ::= Digits ('.' Digits?)?
7341 * | '.' Digits
7342 * [31] Digits ::= [0-9]+
7343 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007344 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007345 *
7346 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007347static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007348xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7349{
Owen Taylor3473f882001-02-23 17:55:21 +00007350 double ret = 0.0;
7351 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007352 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007353 int exponent = 0;
7354 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007355#ifdef __GNUC__
7356 unsigned long tmp = 0;
7357 double temp;
7358#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007359
7360 CHECK_ERROR;
7361 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7362 XP_ERROR(XPATH_NUMBER_ERROR);
7363 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007364#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007365 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007366 * tmp/temp is a workaround against a gcc compiler bug
7367 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007368 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007369 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007370 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007371 ret = ret * 10;
7372 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007373 ok = 1;
7374 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007375 temp = (double) tmp;
7376 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007377 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007378#else
7379 ret = 0;
7380 while ((CUR >= '0') && (CUR <= '9')) {
7381 ret = ret * 10 + (CUR - '0');
7382 ok = 1;
7383 NEXT;
7384 }
7385#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007386 if (CUR == '.') {
7387 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007388 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7389 XP_ERROR(XPATH_NUMBER_ERROR);
7390 }
7391 while ((CUR >= '0') && (CUR <= '9')) {
7392 mult /= 10;
7393 ret = ret + (CUR - '0') * mult;
7394 NEXT;
7395 }
Owen Taylor3473f882001-02-23 17:55:21 +00007396 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007397 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007398 NEXT;
7399 if (CUR == '-') {
7400 is_exponent_negative = 1;
7401 NEXT;
7402 }
7403 while ((CUR >= '0') && (CUR <= '9')) {
7404 exponent = exponent * 10 + (CUR - '0');
7405 NEXT;
7406 }
7407 if (is_exponent_negative)
7408 exponent = -exponent;
7409 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007410 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007411 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007412 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007413}
7414
7415/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007416 * xmlXPathParseLiteral:
7417 * @ctxt: the XPath Parser context
7418 *
7419 * Parse a Literal
7420 *
7421 * [29] Literal ::= '"' [^"]* '"'
7422 * | "'" [^']* "'"
7423 *
7424 * Returns the value found or NULL in case of error
7425 */
7426static xmlChar *
7427xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7428 const xmlChar *q;
7429 xmlChar *ret = NULL;
7430
7431 if (CUR == '"') {
7432 NEXT;
7433 q = CUR_PTR;
7434 while ((IS_CHAR(CUR)) && (CUR != '"'))
7435 NEXT;
7436 if (!IS_CHAR(CUR)) {
7437 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7438 } else {
7439 ret = xmlStrndup(q, CUR_PTR - q);
7440 NEXT;
7441 }
7442 } else if (CUR == '\'') {
7443 NEXT;
7444 q = CUR_PTR;
7445 while ((IS_CHAR(CUR)) && (CUR != '\''))
7446 NEXT;
7447 if (!IS_CHAR(CUR)) {
7448 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7449 } else {
7450 ret = xmlStrndup(q, CUR_PTR - q);
7451 NEXT;
7452 }
7453 } else {
7454 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7455 }
7456 return(ret);
7457}
7458
7459/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007460 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007461 * @ctxt: the XPath Parser context
7462 *
7463 * Parse a Literal and push it on the stack.
7464 *
7465 * [29] Literal ::= '"' [^"]* '"'
7466 * | "'" [^']* "'"
7467 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007468 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007469 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007470static void
7471xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007472 const xmlChar *q;
7473 xmlChar *ret = NULL;
7474
7475 if (CUR == '"') {
7476 NEXT;
7477 q = CUR_PTR;
7478 while ((IS_CHAR(CUR)) && (CUR != '"'))
7479 NEXT;
7480 if (!IS_CHAR(CUR)) {
7481 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7482 } else {
7483 ret = xmlStrndup(q, CUR_PTR - q);
7484 NEXT;
7485 }
7486 } else if (CUR == '\'') {
7487 NEXT;
7488 q = CUR_PTR;
7489 while ((IS_CHAR(CUR)) && (CUR != '\''))
7490 NEXT;
7491 if (!IS_CHAR(CUR)) {
7492 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7493 } else {
7494 ret = xmlStrndup(q, CUR_PTR - q);
7495 NEXT;
7496 }
7497 } else {
7498 XP_ERROR(XPATH_START_LITERAL_ERROR);
7499 }
7500 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007501 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7502 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007503 xmlFree(ret);
7504}
7505
7506/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007507 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007508 * @ctxt: the XPath Parser context
7509 *
7510 * Parse a VariableReference, evaluate it and push it on the stack.
7511 *
7512 * The variable bindings consist of a mapping from variable names
7513 * to variable values. The value of a variable is an object, which
7514 * of any of the types that are possible for the value of an expression,
7515 * and may also be of additional types not specified here.
7516 *
7517 * Early evaluation is possible since:
7518 * The variable bindings [...] used to evaluate a subexpression are
7519 * always the same as those used to evaluate the containing expression.
7520 *
7521 * [36] VariableReference ::= '$' QName
7522 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007523static void
7524xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007525 xmlChar *name;
7526 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007527
7528 SKIP_BLANKS;
7529 if (CUR != '$') {
7530 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7531 }
7532 NEXT;
7533 name = xmlXPathParseQName(ctxt, &prefix);
7534 if (name == NULL) {
7535 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7536 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007537 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007538 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7539 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007540 SKIP_BLANKS;
7541}
7542
7543/**
7544 * xmlXPathIsNodeType:
7545 * @ctxt: the XPath Parser context
7546 * @name: a name string
7547 *
7548 * Is the name given a NodeType one.
7549 *
7550 * [38] NodeType ::= 'comment'
7551 * | 'text'
7552 * | 'processing-instruction'
7553 * | 'node'
7554 *
7555 * Returns 1 if true 0 otherwise
7556 */
7557int
7558xmlXPathIsNodeType(const xmlChar *name) {
7559 if (name == NULL)
7560 return(0);
7561
Daniel Veillard1971ee22002-01-31 20:29:19 +00007562 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007563 return(1);
7564 if (xmlStrEqual(name, BAD_CAST "text"))
7565 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007566 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007567 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007568 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007569 return(1);
7570 return(0);
7571}
7572
7573/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007574 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007575 * @ctxt: the XPath Parser context
7576 *
7577 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7578 * [17] Argument ::= Expr
7579 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007580 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007581 * pushed on the stack
7582 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007583static void
7584xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007585 xmlChar *name;
7586 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007587 int nbargs = 0;
7588
7589 name = xmlXPathParseQName(ctxt, &prefix);
7590 if (name == NULL) {
7591 XP_ERROR(XPATH_EXPR_ERROR);
7592 }
7593 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007594#ifdef DEBUG_EXPR
7595 if (prefix == NULL)
7596 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7597 name);
7598 else
7599 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7600 prefix, name);
7601#endif
7602
Owen Taylor3473f882001-02-23 17:55:21 +00007603 if (CUR != '(') {
7604 XP_ERROR(XPATH_EXPR_ERROR);
7605 }
7606 NEXT;
7607 SKIP_BLANKS;
7608
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007609 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007610 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007611 int op1 = ctxt->comp->last;
7612 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007613 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007614 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007615 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007616 nbargs++;
7617 if (CUR == ')') break;
7618 if (CUR != ',') {
7619 XP_ERROR(XPATH_EXPR_ERROR);
7620 }
7621 NEXT;
7622 SKIP_BLANKS;
7623 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007624 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7625 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007626 NEXT;
7627 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007628}
7629
7630/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007631 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007632 * @ctxt: the XPath Parser context
7633 *
7634 * [15] PrimaryExpr ::= VariableReference
7635 * | '(' Expr ')'
7636 * | Literal
7637 * | Number
7638 * | FunctionCall
7639 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007640 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007641 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007642static void
7643xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007644 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007645 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007646 else if (CUR == '(') {
7647 NEXT;
7648 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007649 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007650 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007651 if (CUR != ')') {
7652 XP_ERROR(XPATH_EXPR_ERROR);
7653 }
7654 NEXT;
7655 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007656 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007657 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007658 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007659 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007660 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007661 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007662 }
7663 SKIP_BLANKS;
7664}
7665
7666/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007667 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007668 * @ctxt: the XPath Parser context
7669 *
7670 * [20] FilterExpr ::= PrimaryExpr
7671 * | FilterExpr Predicate
7672 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007673 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007674 * Square brackets are used to filter expressions in the same way that
7675 * they are used in location paths. It is an error if the expression to
7676 * be filtered does not evaluate to a node-set. The context node list
7677 * used for evaluating the expression in square brackets is the node-set
7678 * to be filtered listed in document order.
7679 */
7680
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007681static void
7682xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7683 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007684 CHECK_ERROR;
7685 SKIP_BLANKS;
7686
7687 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007688 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007689 SKIP_BLANKS;
7690 }
7691
7692
7693}
7694
7695/**
7696 * xmlXPathScanName:
7697 * @ctxt: the XPath Parser context
7698 *
7699 * Trickery: parse an XML name but without consuming the input flow
7700 * Needed to avoid insanity in the parser state.
7701 *
7702 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7703 * CombiningChar | Extender
7704 *
7705 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7706 *
7707 * [6] Names ::= Name (S Name)*
7708 *
7709 * Returns the Name parsed or NULL
7710 */
7711
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007712static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007713xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7714 xmlChar buf[XML_MAX_NAMELEN];
7715 int len = 0;
7716
7717 SKIP_BLANKS;
7718 if (!IS_LETTER(CUR) && (CUR != '_') &&
7719 (CUR != ':')) {
7720 return(NULL);
7721 }
7722
7723 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7724 (NXT(len) == '.') || (NXT(len) == '-') ||
7725 (NXT(len) == '_') || (NXT(len) == ':') ||
7726 (IS_COMBINING(NXT(len))) ||
7727 (IS_EXTENDER(NXT(len)))) {
7728 buf[len] = NXT(len);
7729 len++;
7730 if (len >= XML_MAX_NAMELEN) {
7731 xmlGenericError(xmlGenericErrorContext,
7732 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7733 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7734 (NXT(len) == '.') || (NXT(len) == '-') ||
7735 (NXT(len) == '_') || (NXT(len) == ':') ||
7736 (IS_COMBINING(NXT(len))) ||
7737 (IS_EXTENDER(NXT(len))))
7738 len++;
7739 break;
7740 }
7741 }
7742 return(xmlStrndup(buf, len));
7743}
7744
7745/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007746 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007747 * @ctxt: the XPath Parser context
7748 *
7749 * [19] PathExpr ::= LocationPath
7750 * | FilterExpr
7751 * | FilterExpr '/' RelativeLocationPath
7752 * | FilterExpr '//' RelativeLocationPath
7753 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007754 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007755 * The / operator and // operators combine an arbitrary expression
7756 * and a relative location path. It is an error if the expression
7757 * does not evaluate to a node-set.
7758 * The / operator does composition in the same way as when / is
7759 * used in a location path. As in location paths, // is short for
7760 * /descendant-or-self::node()/.
7761 */
7762
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007763static void
7764xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007765 int lc = 1; /* Should we branch to LocationPath ? */
7766 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7767
7768 SKIP_BLANKS;
7769 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007770 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007771 lc = 0;
7772 } else if (CUR == '*') {
7773 /* relative or absolute location path */
7774 lc = 1;
7775 } else if (CUR == '/') {
7776 /* relative or absolute location path */
7777 lc = 1;
7778 } else if (CUR == '@') {
7779 /* relative abbreviated attribute location path */
7780 lc = 1;
7781 } else if (CUR == '.') {
7782 /* relative abbreviated attribute location path */
7783 lc = 1;
7784 } else {
7785 /*
7786 * Problem is finding if we have a name here whether it's:
7787 * - a nodetype
7788 * - a function call in which case it's followed by '('
7789 * - an axis in which case it's followed by ':'
7790 * - a element name
7791 * We do an a priori analysis here rather than having to
7792 * maintain parsed token content through the recursive function
7793 * calls. This looks uglier but makes the code quite easier to
7794 * read/write/debug.
7795 */
7796 SKIP_BLANKS;
7797 name = xmlXPathScanName(ctxt);
7798 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7799#ifdef DEBUG_STEP
7800 xmlGenericError(xmlGenericErrorContext,
7801 "PathExpr: Axis\n");
7802#endif
7803 lc = 1;
7804 xmlFree(name);
7805 } else if (name != NULL) {
7806 int len =xmlStrlen(name);
7807 int blank = 0;
7808
7809
7810 while (NXT(len) != 0) {
7811 if (NXT(len) == '/') {
7812 /* element name */
7813#ifdef DEBUG_STEP
7814 xmlGenericError(xmlGenericErrorContext,
7815 "PathExpr: AbbrRelLocation\n");
7816#endif
7817 lc = 1;
7818 break;
7819 } else if (IS_BLANK(NXT(len))) {
7820 /* skip to next */
7821 blank = 1;
7822 } else if (NXT(len) == ':') {
7823#ifdef DEBUG_STEP
7824 xmlGenericError(xmlGenericErrorContext,
7825 "PathExpr: AbbrRelLocation\n");
7826#endif
7827 lc = 1;
7828 break;
7829 } else if ((NXT(len) == '(')) {
7830 /* Note Type or Function */
7831 if (xmlXPathIsNodeType(name)) {
7832#ifdef DEBUG_STEP
7833 xmlGenericError(xmlGenericErrorContext,
7834 "PathExpr: Type search\n");
7835#endif
7836 lc = 1;
7837 } else {
7838#ifdef DEBUG_STEP
7839 xmlGenericError(xmlGenericErrorContext,
7840 "PathExpr: function call\n");
7841#endif
7842 lc = 0;
7843 }
7844 break;
7845 } else if ((NXT(len) == '[')) {
7846 /* element name */
7847#ifdef DEBUG_STEP
7848 xmlGenericError(xmlGenericErrorContext,
7849 "PathExpr: AbbrRelLocation\n");
7850#endif
7851 lc = 1;
7852 break;
7853 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7854 (NXT(len) == '=')) {
7855 lc = 1;
7856 break;
7857 } else {
7858 lc = 1;
7859 break;
7860 }
7861 len++;
7862 }
7863 if (NXT(len) == 0) {
7864#ifdef DEBUG_STEP
7865 xmlGenericError(xmlGenericErrorContext,
7866 "PathExpr: AbbrRelLocation\n");
7867#endif
7868 /* element name */
7869 lc = 1;
7870 }
7871 xmlFree(name);
7872 } else {
7873 /* make sure all cases are covered explicitely */
7874 XP_ERROR(XPATH_EXPR_ERROR);
7875 }
7876 }
7877
7878 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007879 if (CUR == '/') {
7880 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7881 } else {
7882 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007883 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007884 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007885 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007886 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007887 CHECK_ERROR;
7888 if ((CUR == '/') && (NXT(1) == '/')) {
7889 SKIP(2);
7890 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007891
7892 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7893 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7894 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7895
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007896 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007897 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007898 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007899 }
7900 }
7901 SKIP_BLANKS;
7902}
7903
7904/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007905 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007906 * @ctxt: the XPath Parser context
7907 *
7908 * [18] UnionExpr ::= PathExpr
7909 * | UnionExpr '|' PathExpr
7910 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007911 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007912 */
7913
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007914static void
7915xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7916 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007917 CHECK_ERROR;
7918 SKIP_BLANKS;
7919 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007920 int op1 = ctxt->comp->last;
7921 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007922
7923 NEXT;
7924 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007925 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007926
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007927 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7928
Owen Taylor3473f882001-02-23 17:55:21 +00007929 SKIP_BLANKS;
7930 }
Owen Taylor3473f882001-02-23 17:55:21 +00007931}
7932
7933/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007934 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007935 * @ctxt: the XPath Parser context
7936 *
7937 * [27] UnaryExpr ::= UnionExpr
7938 * | '-' UnaryExpr
7939 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007940 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007941 */
7942
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007943static void
7944xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007945 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007946 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007947
7948 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007949 while (CUR == '-') {
7950 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007951 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007952 NEXT;
7953 SKIP_BLANKS;
7954 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007955
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007956 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007957 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007958 if (found) {
7959 if (minus)
7960 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7961 else
7962 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007963 }
7964}
7965
7966/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007967 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007968 * @ctxt: the XPath Parser context
7969 *
7970 * [26] MultiplicativeExpr ::= UnaryExpr
7971 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7972 * | MultiplicativeExpr 'div' UnaryExpr
7973 * | MultiplicativeExpr 'mod' UnaryExpr
7974 * [34] MultiplyOperator ::= '*'
7975 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007976 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007977 */
7978
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007979static void
7980xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7981 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007982 CHECK_ERROR;
7983 SKIP_BLANKS;
7984 while ((CUR == '*') ||
7985 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7986 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7987 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007988 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007989
7990 if (CUR == '*') {
7991 op = 0;
7992 NEXT;
7993 } else if (CUR == 'd') {
7994 op = 1;
7995 SKIP(3);
7996 } else if (CUR == 'm') {
7997 op = 2;
7998 SKIP(3);
7999 }
8000 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008001 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008002 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008003 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008004 SKIP_BLANKS;
8005 }
8006}
8007
8008/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008009 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008010 * @ctxt: the XPath Parser context
8011 *
8012 * [25] AdditiveExpr ::= MultiplicativeExpr
8013 * | AdditiveExpr '+' MultiplicativeExpr
8014 * | AdditiveExpr '-' MultiplicativeExpr
8015 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008016 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008017 */
8018
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008019static void
8020xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008021
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008022 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008023 CHECK_ERROR;
8024 SKIP_BLANKS;
8025 while ((CUR == '+') || (CUR == '-')) {
8026 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008027 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008028
8029 if (CUR == '+') plus = 1;
8030 else plus = 0;
8031 NEXT;
8032 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008033 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008034 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008035 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008036 SKIP_BLANKS;
8037 }
8038}
8039
8040/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008041 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008042 * @ctxt: the XPath Parser context
8043 *
8044 * [24] RelationalExpr ::= AdditiveExpr
8045 * | RelationalExpr '<' AdditiveExpr
8046 * | RelationalExpr '>' AdditiveExpr
8047 * | RelationalExpr '<=' AdditiveExpr
8048 * | RelationalExpr '>=' AdditiveExpr
8049 *
8050 * A <= B > C is allowed ? Answer from James, yes with
8051 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8052 * which is basically what got implemented.
8053 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008054 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008055 * on the stack
8056 */
8057
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008058static void
8059xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8060 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008061 CHECK_ERROR;
8062 SKIP_BLANKS;
8063 while ((CUR == '<') ||
8064 (CUR == '>') ||
8065 ((CUR == '<') && (NXT(1) == '=')) ||
8066 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008067 int inf, strict;
8068 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008069
8070 if (CUR == '<') inf = 1;
8071 else inf = 0;
8072 if (NXT(1) == '=') strict = 0;
8073 else strict = 1;
8074 NEXT;
8075 if (!strict) NEXT;
8076 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008077 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008078 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008079 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008080 SKIP_BLANKS;
8081 }
8082}
8083
8084/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008085 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008086 * @ctxt: the XPath Parser context
8087 *
8088 * [23] EqualityExpr ::= RelationalExpr
8089 * | EqualityExpr '=' RelationalExpr
8090 * | EqualityExpr '!=' RelationalExpr
8091 *
8092 * A != B != C is allowed ? Answer from James, yes with
8093 * (RelationalExpr = RelationalExpr) = RelationalExpr
8094 * (RelationalExpr != RelationalExpr) != RelationalExpr
8095 * which is basically what got implemented.
8096 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008097 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008098 *
8099 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008100static void
8101xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8102 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008103 CHECK_ERROR;
8104 SKIP_BLANKS;
8105 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008106 int eq;
8107 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008108
8109 if (CUR == '=') eq = 1;
8110 else eq = 0;
8111 NEXT;
8112 if (!eq) NEXT;
8113 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008114 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008115 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008116 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008117 SKIP_BLANKS;
8118 }
8119}
8120
8121/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008122 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008123 * @ctxt: the XPath Parser context
8124 *
8125 * [22] AndExpr ::= EqualityExpr
8126 * | AndExpr 'and' EqualityExpr
8127 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008128 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008129 *
8130 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008131static void
8132xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8133 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008134 CHECK_ERROR;
8135 SKIP_BLANKS;
8136 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008137 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008138 SKIP(3);
8139 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008140 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008141 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008142 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008143 SKIP_BLANKS;
8144 }
8145}
8146
8147/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008148 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008149 * @ctxt: the XPath Parser context
8150 *
8151 * [14] Expr ::= OrExpr
8152 * [21] OrExpr ::= AndExpr
8153 * | OrExpr 'or' AndExpr
8154 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008155 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008156 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008157static void
8158xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8159 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008160 CHECK_ERROR;
8161 SKIP_BLANKS;
8162 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008163 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008164 SKIP(2);
8165 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008166 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008167 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008168 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8169 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008170 SKIP_BLANKS;
8171 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008172 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8173 /* more ops could be optimized too */
8174 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8175 }
Owen Taylor3473f882001-02-23 17:55:21 +00008176}
8177
8178/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008179 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008180 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008181 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008182 *
8183 * [8] Predicate ::= '[' PredicateExpr ']'
8184 * [9] PredicateExpr ::= Expr
8185 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008186 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008187 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008188static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008189xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008190 int op1 = ctxt->comp->last;
8191
8192 SKIP_BLANKS;
8193 if (CUR != '[') {
8194 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8195 }
8196 NEXT;
8197 SKIP_BLANKS;
8198
8199 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008200 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008201 CHECK_ERROR;
8202
8203 if (CUR != ']') {
8204 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8205 }
8206
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008207 if (filter)
8208 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8209 else
8210 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008211
8212 NEXT;
8213 SKIP_BLANKS;
8214}
8215
8216/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008217 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008218 * @ctxt: the XPath Parser context
8219 * @test: pointer to a xmlXPathTestVal
8220 * @type: pointer to a xmlXPathTypeVal
8221 * @prefix: placeholder for a possible name prefix
8222 *
8223 * [7] NodeTest ::= NameTest
8224 * | NodeType '(' ')'
8225 * | 'processing-instruction' '(' Literal ')'
8226 *
8227 * [37] NameTest ::= '*'
8228 * | NCName ':' '*'
8229 * | QName
8230 * [38] NodeType ::= 'comment'
8231 * | 'text'
8232 * | 'processing-instruction'
8233 * | 'node'
8234 *
8235 * Returns the name found and update @test, @type and @prefix appropriately
8236 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008237static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008238xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8239 xmlXPathTypeVal *type, const xmlChar **prefix,
8240 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008241 int blanks;
8242
8243 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8244 STRANGE;
8245 return(NULL);
8246 }
8247 *type = 0;
8248 *test = 0;
8249 *prefix = NULL;
8250 SKIP_BLANKS;
8251
8252 if ((name == NULL) && (CUR == '*')) {
8253 /*
8254 * All elements
8255 */
8256 NEXT;
8257 *test = NODE_TEST_ALL;
8258 return(NULL);
8259 }
8260
8261 if (name == NULL)
8262 name = xmlXPathParseNCName(ctxt);
8263 if (name == NULL) {
8264 XP_ERROR0(XPATH_EXPR_ERROR);
8265 }
8266
8267 blanks = IS_BLANK(CUR);
8268 SKIP_BLANKS;
8269 if (CUR == '(') {
8270 NEXT;
8271 /*
8272 * NodeType or PI search
8273 */
8274 if (xmlStrEqual(name, BAD_CAST "comment"))
8275 *type = NODE_TYPE_COMMENT;
8276 else if (xmlStrEqual(name, BAD_CAST "node"))
8277 *type = NODE_TYPE_NODE;
8278 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8279 *type = NODE_TYPE_PI;
8280 else if (xmlStrEqual(name, BAD_CAST "text"))
8281 *type = NODE_TYPE_TEXT;
8282 else {
8283 if (name != NULL)
8284 xmlFree(name);
8285 XP_ERROR0(XPATH_EXPR_ERROR);
8286 }
8287
8288 *test = NODE_TEST_TYPE;
8289
8290 SKIP_BLANKS;
8291 if (*type == NODE_TYPE_PI) {
8292 /*
8293 * Specific case: search a PI by name.
8294 */
Owen Taylor3473f882001-02-23 17:55:21 +00008295 if (name != NULL)
8296 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008297 name = NULL;
8298 if (CUR != ')') {
8299 name = xmlXPathParseLiteral(ctxt);
8300 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008301 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008302 SKIP_BLANKS;
8303 }
Owen Taylor3473f882001-02-23 17:55:21 +00008304 }
8305 if (CUR != ')') {
8306 if (name != NULL)
8307 xmlFree(name);
8308 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8309 }
8310 NEXT;
8311 return(name);
8312 }
8313 *test = NODE_TEST_NAME;
8314 if ((!blanks) && (CUR == ':')) {
8315 NEXT;
8316
8317 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008318 * Since currently the parser context don't have a
8319 * namespace list associated:
8320 * The namespace name for this prefix can be computed
8321 * only at evaluation time. The compilation is done
8322 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008323 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008324#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008325 *prefix = xmlXPathNsLookup(ctxt->context, name);
8326 if (name != NULL)
8327 xmlFree(name);
8328 if (*prefix == NULL) {
8329 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8330 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008331#else
8332 *prefix = name;
8333#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008334
8335 if (CUR == '*') {
8336 /*
8337 * All elements
8338 */
8339 NEXT;
8340 *test = NODE_TEST_ALL;
8341 return(NULL);
8342 }
8343
8344 name = xmlXPathParseNCName(ctxt);
8345 if (name == NULL) {
8346 XP_ERROR0(XPATH_EXPR_ERROR);
8347 }
8348 }
8349 return(name);
8350}
8351
8352/**
8353 * xmlXPathIsAxisName:
8354 * @name: a preparsed name token
8355 *
8356 * [6] AxisName ::= 'ancestor'
8357 * | 'ancestor-or-self'
8358 * | 'attribute'
8359 * | 'child'
8360 * | 'descendant'
8361 * | 'descendant-or-self'
8362 * | 'following'
8363 * | 'following-sibling'
8364 * | 'namespace'
8365 * | 'parent'
8366 * | 'preceding'
8367 * | 'preceding-sibling'
8368 * | 'self'
8369 *
8370 * Returns the axis or 0
8371 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008372static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008373xmlXPathIsAxisName(const xmlChar *name) {
8374 xmlXPathAxisVal ret = 0;
8375 switch (name[0]) {
8376 case 'a':
8377 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8378 ret = AXIS_ANCESTOR;
8379 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8380 ret = AXIS_ANCESTOR_OR_SELF;
8381 if (xmlStrEqual(name, BAD_CAST "attribute"))
8382 ret = AXIS_ATTRIBUTE;
8383 break;
8384 case 'c':
8385 if (xmlStrEqual(name, BAD_CAST "child"))
8386 ret = AXIS_CHILD;
8387 break;
8388 case 'd':
8389 if (xmlStrEqual(name, BAD_CAST "descendant"))
8390 ret = AXIS_DESCENDANT;
8391 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8392 ret = AXIS_DESCENDANT_OR_SELF;
8393 break;
8394 case 'f':
8395 if (xmlStrEqual(name, BAD_CAST "following"))
8396 ret = AXIS_FOLLOWING;
8397 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8398 ret = AXIS_FOLLOWING_SIBLING;
8399 break;
8400 case 'n':
8401 if (xmlStrEqual(name, BAD_CAST "namespace"))
8402 ret = AXIS_NAMESPACE;
8403 break;
8404 case 'p':
8405 if (xmlStrEqual(name, BAD_CAST "parent"))
8406 ret = AXIS_PARENT;
8407 if (xmlStrEqual(name, BAD_CAST "preceding"))
8408 ret = AXIS_PRECEDING;
8409 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8410 ret = AXIS_PRECEDING_SIBLING;
8411 break;
8412 case 's':
8413 if (xmlStrEqual(name, BAD_CAST "self"))
8414 ret = AXIS_SELF;
8415 break;
8416 }
8417 return(ret);
8418}
8419
8420/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008421 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008422 * @ctxt: the XPath Parser context
8423 *
8424 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8425 * | AbbreviatedStep
8426 *
8427 * [12] AbbreviatedStep ::= '.' | '..'
8428 *
8429 * [5] AxisSpecifier ::= AxisName '::'
8430 * | AbbreviatedAxisSpecifier
8431 *
8432 * [13] AbbreviatedAxisSpecifier ::= '@'?
8433 *
8434 * Modified for XPtr range support as:
8435 *
8436 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8437 * | AbbreviatedStep
8438 * | 'range-to' '(' Expr ')' Predicate*
8439 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008440 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008441 * A location step of . is short for self::node(). This is
8442 * particularly useful in conjunction with //. For example, the
8443 * location path .//para is short for
8444 * self::node()/descendant-or-self::node()/child::para
8445 * and so will select all para descendant elements of the context
8446 * node.
8447 * Similarly, a location step of .. is short for parent::node().
8448 * For example, ../title is short for parent::node()/child::title
8449 * and so will select the title children of the parent of the context
8450 * node.
8451 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008452static void
8453xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008454#ifdef LIBXML_XPTR_ENABLED
8455 int rangeto = 0;
8456 int op2 = -1;
8457#endif
8458
Owen Taylor3473f882001-02-23 17:55:21 +00008459 SKIP_BLANKS;
8460 if ((CUR == '.') && (NXT(1) == '.')) {
8461 SKIP(2);
8462 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008463 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8464 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008465 } else if (CUR == '.') {
8466 NEXT;
8467 SKIP_BLANKS;
8468 } else {
8469 xmlChar *name = NULL;
8470 const xmlChar *prefix = NULL;
8471 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008472 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008473 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008474 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008475
8476 /*
8477 * The modification needed for XPointer change to the production
8478 */
8479#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008480 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008481 name = xmlXPathParseNCName(ctxt);
8482 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008483 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008484 xmlFree(name);
8485 SKIP_BLANKS;
8486 if (CUR != '(') {
8487 XP_ERROR(XPATH_EXPR_ERROR);
8488 }
8489 NEXT;
8490 SKIP_BLANKS;
8491
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008492 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008493 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008494 CHECK_ERROR;
8495
8496 SKIP_BLANKS;
8497 if (CUR != ')') {
8498 XP_ERROR(XPATH_EXPR_ERROR);
8499 }
8500 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008501 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008502 goto eval_predicates;
8503 }
8504 }
8505#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008506 if (CUR == '*') {
8507 axis = AXIS_CHILD;
8508 } else {
8509 if (name == NULL)
8510 name = xmlXPathParseNCName(ctxt);
8511 if (name != NULL) {
8512 axis = xmlXPathIsAxisName(name);
8513 if (axis != 0) {
8514 SKIP_BLANKS;
8515 if ((CUR == ':') && (NXT(1) == ':')) {
8516 SKIP(2);
8517 xmlFree(name);
8518 name = NULL;
8519 } else {
8520 /* an element name can conflict with an axis one :-\ */
8521 axis = AXIS_CHILD;
8522 }
Owen Taylor3473f882001-02-23 17:55:21 +00008523 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008524 axis = AXIS_CHILD;
8525 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008526 } else if (CUR == '@') {
8527 NEXT;
8528 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008529 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008530 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008531 }
Owen Taylor3473f882001-02-23 17:55:21 +00008532 }
8533
8534 CHECK_ERROR;
8535
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008536 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008537 if (test == 0)
8538 return;
8539
8540#ifdef DEBUG_STEP
8541 xmlGenericError(xmlGenericErrorContext,
8542 "Basis : computing new set\n");
8543#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008544
Owen Taylor3473f882001-02-23 17:55:21 +00008545#ifdef DEBUG_STEP
8546 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008547 if (ctxt->value == NULL)
8548 xmlGenericError(xmlGenericErrorContext, "no value\n");
8549 else if (ctxt->value->nodesetval == NULL)
8550 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8551 else
8552 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008553#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008554
8555eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008556 op1 = ctxt->comp->last;
8557 ctxt->comp->last = -1;
8558
Owen Taylor3473f882001-02-23 17:55:21 +00008559 SKIP_BLANKS;
8560 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008561 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008562 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008563
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008564#ifdef LIBXML_XPTR_ENABLED
8565 if (rangeto) {
8566 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8567 } else
8568#endif
8569 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8570 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008571
Owen Taylor3473f882001-02-23 17:55:21 +00008572 }
8573#ifdef DEBUG_STEP
8574 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008575 if (ctxt->value == NULL)
8576 xmlGenericError(xmlGenericErrorContext, "no value\n");
8577 else if (ctxt->value->nodesetval == NULL)
8578 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8579 else
8580 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8581 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008582#endif
8583}
8584
8585/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008586 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008587 * @ctxt: the XPath Parser context
8588 *
8589 * [3] RelativeLocationPath ::= Step
8590 * | RelativeLocationPath '/' Step
8591 * | AbbreviatedRelativeLocationPath
8592 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8593 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008594 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008595 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008596static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008597xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008598(xmlXPathParserContextPtr ctxt) {
8599 SKIP_BLANKS;
8600 if ((CUR == '/') && (NXT(1) == '/')) {
8601 SKIP(2);
8602 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008603 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8604 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008605 } else if (CUR == '/') {
8606 NEXT;
8607 SKIP_BLANKS;
8608 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008609 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008610 SKIP_BLANKS;
8611 while (CUR == '/') {
8612 if ((CUR == '/') && (NXT(1) == '/')) {
8613 SKIP(2);
8614 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008615 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008616 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008617 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008618 } else if (CUR == '/') {
8619 NEXT;
8620 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008621 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008622 }
8623 SKIP_BLANKS;
8624 }
8625}
8626
8627/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008628 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008629 * @ctxt: the XPath Parser context
8630 *
8631 * [1] LocationPath ::= RelativeLocationPath
8632 * | AbsoluteLocationPath
8633 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8634 * | AbbreviatedAbsoluteLocationPath
8635 * [10] AbbreviatedAbsoluteLocationPath ::=
8636 * '//' RelativeLocationPath
8637 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008638 * Compile a location path
8639 *
Owen Taylor3473f882001-02-23 17:55:21 +00008640 * // is short for /descendant-or-self::node()/. For example,
8641 * //para is short for /descendant-or-self::node()/child::para and
8642 * so will select any para element in the document (even a para element
8643 * that is a document element will be selected by //para since the
8644 * document element node is a child of the root node); div//para is
8645 * short for div/descendant-or-self::node()/child::para and so will
8646 * select all para descendants of div children.
8647 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008648static void
8649xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008650 SKIP_BLANKS;
8651 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008652 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008653 } else {
8654 while (CUR == '/') {
8655 if ((CUR == '/') && (NXT(1) == '/')) {
8656 SKIP(2);
8657 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008658 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8659 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008660 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008661 } else if (CUR == '/') {
8662 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008663 SKIP_BLANKS;
8664 if ((CUR != 0 ) &&
8665 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8666 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008667 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008668 }
8669 }
8670 }
8671}
8672
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008673/************************************************************************
8674 * *
8675 * XPath precompiled expression evaluation *
8676 * *
8677 ************************************************************************/
8678
Daniel Veillardf06307e2001-07-03 10:35:50 +00008679static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008680xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8681
8682/**
8683 * xmlXPathNodeCollectAndTest:
8684 * @ctxt: the XPath Parser context
8685 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008686 * @first: pointer to the first element in document order
8687 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008688 *
8689 * This is the function implementing a step: based on the current list
8690 * of nodes, it builds up a new list, looking at all nodes under that
8691 * axis and selecting them it also do the predicate filtering
8692 *
8693 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008694 *
8695 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008696 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008697static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008698xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008699 xmlXPathStepOpPtr op,
8700 xmlNodePtr * first, xmlNodePtr * last)
8701{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008702 xmlXPathAxisVal axis = op->value;
8703 xmlXPathTestVal test = op->value2;
8704 xmlXPathTypeVal type = op->value3;
8705 const xmlChar *prefix = op->value4;
8706 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008707 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008708
8709#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008710 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008711#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008712 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008713 xmlNodeSetPtr ret, list;
8714 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008715 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008716 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008717 xmlNodePtr cur = NULL;
8718 xmlXPathObjectPtr obj;
8719 xmlNodeSetPtr nodelist;
8720 xmlNodePtr tmp;
8721
Daniel Veillardf06307e2001-07-03 10:35:50 +00008722 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008723 obj = valuePop(ctxt);
8724 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008725 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008726 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008727 URI = xmlXPathNsLookup(ctxt->context, prefix);
8728 if (URI == NULL)
8729 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008730 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008731#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008732 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008733#endif
8734 switch (axis) {
8735 case AXIS_ANCESTOR:
8736#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008737 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008738#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008739 first = NULL;
8740 next = xmlXPathNextAncestor;
8741 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008742 case AXIS_ANCESTOR_OR_SELF:
8743#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008744 xmlGenericError(xmlGenericErrorContext,
8745 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008746#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008747 first = NULL;
8748 next = xmlXPathNextAncestorOrSelf;
8749 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008750 case AXIS_ATTRIBUTE:
8751#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008752 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008753#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008754 first = NULL;
8755 last = NULL;
8756 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008757 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008758 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008759 case AXIS_CHILD:
8760#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008761 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008762#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008763 last = NULL;
8764 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008765 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008766 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008767 case AXIS_DESCENDANT:
8768#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008769 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008770#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008771 last = NULL;
8772 next = xmlXPathNextDescendant;
8773 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008774 case AXIS_DESCENDANT_OR_SELF:
8775#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008776 xmlGenericError(xmlGenericErrorContext,
8777 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008778#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008779 last = NULL;
8780 next = xmlXPathNextDescendantOrSelf;
8781 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008782 case AXIS_FOLLOWING:
8783#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008784 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008785#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008786 last = NULL;
8787 next = xmlXPathNextFollowing;
8788 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008789 case AXIS_FOLLOWING_SIBLING:
8790#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008791 xmlGenericError(xmlGenericErrorContext,
8792 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008793#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008794 last = NULL;
8795 next = xmlXPathNextFollowingSibling;
8796 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008797 case AXIS_NAMESPACE:
8798#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008799 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008800#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008801 first = NULL;
8802 last = NULL;
8803 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008804 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008805 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008806 case AXIS_PARENT:
8807#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008808 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008809#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008810 first = NULL;
8811 next = xmlXPathNextParent;
8812 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008813 case AXIS_PRECEDING:
8814#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008815 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008816#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008817 first = NULL;
8818 next = xmlXPathNextPrecedingInternal;
8819 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008820 case AXIS_PRECEDING_SIBLING:
8821#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008822 xmlGenericError(xmlGenericErrorContext,
8823 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008824#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008825 first = NULL;
8826 next = xmlXPathNextPrecedingSibling;
8827 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008828 case AXIS_SELF:
8829#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008830 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008831#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008832 first = NULL;
8833 last = NULL;
8834 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008835 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008836 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008837 }
8838 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008839 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008840
8841 nodelist = obj->nodesetval;
8842 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008843 xmlXPathFreeObject(obj);
8844 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8845 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008846 }
8847 addNode = xmlXPathNodeSetAddUnique;
8848 ret = NULL;
8849#ifdef DEBUG_STEP
8850 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008851 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008852 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008853 case NODE_TEST_NONE:
8854 xmlGenericError(xmlGenericErrorContext,
8855 " searching for none !!!\n");
8856 break;
8857 case NODE_TEST_TYPE:
8858 xmlGenericError(xmlGenericErrorContext,
8859 " searching for type %d\n", type);
8860 break;
8861 case NODE_TEST_PI:
8862 xmlGenericError(xmlGenericErrorContext,
8863 " searching for PI !!!\n");
8864 break;
8865 case NODE_TEST_ALL:
8866 xmlGenericError(xmlGenericErrorContext,
8867 " searching for *\n");
8868 break;
8869 case NODE_TEST_NS:
8870 xmlGenericError(xmlGenericErrorContext,
8871 " searching for namespace %s\n",
8872 prefix);
8873 break;
8874 case NODE_TEST_NAME:
8875 xmlGenericError(xmlGenericErrorContext,
8876 " searching for name %s\n", name);
8877 if (prefix != NULL)
8878 xmlGenericError(xmlGenericErrorContext,
8879 " with namespace %s\n", prefix);
8880 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008881 }
8882 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8883#endif
8884 /*
8885 * 2.3 Node Tests
8886 * - For the attribute axis, the principal node type is attribute.
8887 * - For the namespace axis, the principal node type is namespace.
8888 * - For other axes, the principal node type is element.
8889 *
8890 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008891 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008892 * select all element children of the context node
8893 */
8894 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008895 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008896 ctxt->context->node = nodelist->nodeTab[i];
8897
Daniel Veillardf06307e2001-07-03 10:35:50 +00008898 cur = NULL;
8899 list = xmlXPathNodeSetCreate(NULL);
8900 do {
8901 cur = next(ctxt, cur);
8902 if (cur == NULL)
8903 break;
8904 if ((first != NULL) && (*first == cur))
8905 break;
8906 if (((t % 256) == 0) &&
8907 (first != NULL) && (*first != NULL) &&
8908 (xmlXPathCmpNodes(*first, cur) >= 0))
8909 break;
8910 if ((last != NULL) && (*last == cur))
8911 break;
8912 if (((t % 256) == 0) &&
8913 (last != NULL) && (*last != NULL) &&
8914 (xmlXPathCmpNodes(cur, *last) >= 0))
8915 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008916 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008918 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8919#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008920 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008921 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008922 ctxt->context->node = tmp;
8923 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008924 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008925 if ((cur->type == type) ||
8926 ((type == NODE_TYPE_NODE) &&
8927 ((cur->type == XML_DOCUMENT_NODE) ||
8928 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8929 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008930 (cur->type == XML_NAMESPACE_DECL) ||
8931 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008932 (cur->type == XML_PI_NODE) ||
8933 (cur->type == XML_COMMENT_NODE) ||
8934 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008935 (cur->type == XML_TEXT_NODE))) ||
8936 ((type == NODE_TYPE_TEXT) &&
8937 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008938#ifdef DEBUG_STEP
8939 n++;
8940#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008941 addNode(list, cur);
8942 }
8943 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008944 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008945 if (cur->type == XML_PI_NODE) {
8946 if ((name != NULL) &&
8947 (!xmlStrEqual(name, cur->name)))
8948 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008949#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008950 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008951#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008952 addNode(list, cur);
8953 }
8954 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008955 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008956 if (axis == AXIS_ATTRIBUTE) {
8957 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008958#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008959 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008960#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008961 addNode(list, cur);
8962 }
8963 } else if (axis == AXIS_NAMESPACE) {
8964 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008965#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008966 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008967#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008968 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8969 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008970 }
8971 } else {
8972 if (cur->type == XML_ELEMENT_NODE) {
8973 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008974#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008976#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008977 addNode(list, cur);
8978 } else if ((cur->ns != NULL) &&
8979 (xmlStrEqual(URI, cur->ns->href))) {
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 }
8986 }
8987 break;
8988 case NODE_TEST_NS:{
8989 TODO;
8990 break;
8991 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008992 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008993 switch (cur->type) {
8994 case XML_ELEMENT_NODE:
8995 if (xmlStrEqual(name, cur->name)) {
8996 if (prefix == NULL) {
8997 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008998#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008999 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009000#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009001 addNode(list, cur);
9002 }
9003 } else {
9004 if ((cur->ns != NULL) &&
9005 (xmlStrEqual(URI,
9006 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009007#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009008 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009009#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009010 addNode(list, cur);
9011 }
9012 }
9013 }
9014 break;
9015 case XML_ATTRIBUTE_NODE:{
9016 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009017
Daniel Veillardf06307e2001-07-03 10:35:50 +00009018 if (xmlStrEqual(name, attr->name)) {
9019 if (prefix == NULL) {
9020 if ((attr->ns == NULL) ||
9021 (attr->ns->prefix == NULL)) {
9022#ifdef DEBUG_STEP
9023 n++;
9024#endif
9025 addNode(list,
9026 (xmlNodePtr) attr);
9027 }
9028 } else {
9029 if ((attr->ns != NULL) &&
9030 (xmlStrEqual(URI,
9031 attr->ns->
9032 href))) {
9033#ifdef DEBUG_STEP
9034 n++;
9035#endif
9036 addNode(list,
9037 (xmlNodePtr) attr);
9038 }
9039 }
9040 }
9041 break;
9042 }
9043 case XML_NAMESPACE_DECL:
9044 if (cur->type == XML_NAMESPACE_DECL) {
9045 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009046
Daniel Veillardf06307e2001-07-03 10:35:50 +00009047 if ((ns->prefix != NULL) && (name != NULL)
9048 && (xmlStrEqual(ns->prefix, name))) {
9049#ifdef DEBUG_STEP
9050 n++;
9051#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009052 xmlXPathNodeSetAddNs(list,
9053 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009054 }
9055 }
9056 break;
9057 default:
9058 break;
9059 }
9060 break;
9061 break;
9062 }
9063 } while (cur != NULL);
9064
9065 /*
9066 * If there is some predicate filtering do it now
9067 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009068 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009069 xmlXPathObjectPtr obj2;
9070
9071 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9072 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9073 CHECK_TYPE0(XPATH_NODESET);
9074 obj2 = valuePop(ctxt);
9075 list = obj2->nodesetval;
9076 obj2->nodesetval = NULL;
9077 xmlXPathFreeObject(obj2);
9078 }
9079 if (ret == NULL) {
9080 ret = list;
9081 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009082 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009083 xmlXPathFreeNodeSet(list);
9084 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009085 }
9086 ctxt->context->node = tmp;
9087#ifdef DEBUG_STEP
9088 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 "\nExamined %d nodes, found %d nodes at that step\n",
9090 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009092 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009093 if ((obj->boolval) && (obj->user != NULL)) {
9094 ctxt->value->boolval = 1;
9095 ctxt->value->user = obj->user;
9096 obj->user = NULL;
9097 obj->boolval = 0;
9098 }
9099 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 return(t);
9101}
9102
9103/**
9104 * xmlXPathNodeCollectAndTestNth:
9105 * @ctxt: the XPath Parser context
9106 * @op: the XPath precompiled step operation
9107 * @indx: the index to collect
9108 * @first: pointer to the first element in document order
9109 * @last: pointer to the last element in document order
9110 *
9111 * This is the function implementing a step: based on the current list
9112 * of nodes, it builds up a new list, looking at all nodes under that
9113 * axis and selecting them it also do the predicate filtering
9114 *
9115 * Pushes the new NodeSet resulting from the search.
9116 * Returns the number of node traversed
9117 */
9118static int
9119xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9120 xmlXPathStepOpPtr op, int indx,
9121 xmlNodePtr * first, xmlNodePtr * last)
9122{
9123 xmlXPathAxisVal axis = op->value;
9124 xmlXPathTestVal test = op->value2;
9125 xmlXPathTypeVal type = op->value3;
9126 const xmlChar *prefix = op->value4;
9127 const xmlChar *name = op->value5;
9128 const xmlChar *URI = NULL;
9129 int n = 0, t = 0;
9130
9131 int i;
9132 xmlNodeSetPtr list;
9133 xmlXPathTraversalFunction next = NULL;
9134 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9135 xmlNodePtr cur = NULL;
9136 xmlXPathObjectPtr obj;
9137 xmlNodeSetPtr nodelist;
9138 xmlNodePtr tmp;
9139
9140 CHECK_TYPE0(XPATH_NODESET);
9141 obj = valuePop(ctxt);
9142 addNode = xmlXPathNodeSetAdd;
9143 if (prefix != NULL) {
9144 URI = xmlXPathNsLookup(ctxt->context, prefix);
9145 if (URI == NULL)
9146 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9147 }
9148#ifdef DEBUG_STEP_NTH
9149 xmlGenericError(xmlGenericErrorContext, "new step : ");
9150 if (first != NULL) {
9151 if (*first != NULL)
9152 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9153 (*first)->name);
9154 else
9155 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9156 }
9157 if (last != NULL) {
9158 if (*last != NULL)
9159 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9160 (*last)->name);
9161 else
9162 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9163 }
9164#endif
9165 switch (axis) {
9166 case AXIS_ANCESTOR:
9167#ifdef DEBUG_STEP_NTH
9168 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9169#endif
9170 first = NULL;
9171 next = xmlXPathNextAncestor;
9172 break;
9173 case AXIS_ANCESTOR_OR_SELF:
9174#ifdef DEBUG_STEP_NTH
9175 xmlGenericError(xmlGenericErrorContext,
9176 "axis 'ancestors-or-self' ");
9177#endif
9178 first = NULL;
9179 next = xmlXPathNextAncestorOrSelf;
9180 break;
9181 case AXIS_ATTRIBUTE:
9182#ifdef DEBUG_STEP_NTH
9183 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9184#endif
9185 first = NULL;
9186 last = NULL;
9187 next = xmlXPathNextAttribute;
9188 break;
9189 case AXIS_CHILD:
9190#ifdef DEBUG_STEP_NTH
9191 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9192#endif
9193 last = NULL;
9194 next = xmlXPathNextChild;
9195 break;
9196 case AXIS_DESCENDANT:
9197#ifdef DEBUG_STEP_NTH
9198 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9199#endif
9200 last = NULL;
9201 next = xmlXPathNextDescendant;
9202 break;
9203 case AXIS_DESCENDANT_OR_SELF:
9204#ifdef DEBUG_STEP_NTH
9205 xmlGenericError(xmlGenericErrorContext,
9206 "axis 'descendant-or-self' ");
9207#endif
9208 last = NULL;
9209 next = xmlXPathNextDescendantOrSelf;
9210 break;
9211 case AXIS_FOLLOWING:
9212#ifdef DEBUG_STEP_NTH
9213 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9214#endif
9215 last = NULL;
9216 next = xmlXPathNextFollowing;
9217 break;
9218 case AXIS_FOLLOWING_SIBLING:
9219#ifdef DEBUG_STEP_NTH
9220 xmlGenericError(xmlGenericErrorContext,
9221 "axis 'following-siblings' ");
9222#endif
9223 last = NULL;
9224 next = xmlXPathNextFollowingSibling;
9225 break;
9226 case AXIS_NAMESPACE:
9227#ifdef DEBUG_STEP_NTH
9228 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9229#endif
9230 last = NULL;
9231 first = NULL;
9232 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9233 break;
9234 case AXIS_PARENT:
9235#ifdef DEBUG_STEP_NTH
9236 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9237#endif
9238 first = NULL;
9239 next = xmlXPathNextParent;
9240 break;
9241 case AXIS_PRECEDING:
9242#ifdef DEBUG_STEP_NTH
9243 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9244#endif
9245 first = NULL;
9246 next = xmlXPathNextPrecedingInternal;
9247 break;
9248 case AXIS_PRECEDING_SIBLING:
9249#ifdef DEBUG_STEP_NTH
9250 xmlGenericError(xmlGenericErrorContext,
9251 "axis 'preceding-sibling' ");
9252#endif
9253 first = NULL;
9254 next = xmlXPathNextPrecedingSibling;
9255 break;
9256 case AXIS_SELF:
9257#ifdef DEBUG_STEP_NTH
9258 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9259#endif
9260 first = NULL;
9261 last = NULL;
9262 next = xmlXPathNextSelf;
9263 break;
9264 }
9265 if (next == NULL)
9266 return(0);
9267
9268 nodelist = obj->nodesetval;
9269 if (nodelist == NULL) {
9270 xmlXPathFreeObject(obj);
9271 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9272 return(0);
9273 }
9274 addNode = xmlXPathNodeSetAddUnique;
9275#ifdef DEBUG_STEP_NTH
9276 xmlGenericError(xmlGenericErrorContext,
9277 " context contains %d nodes\n", nodelist->nodeNr);
9278 switch (test) {
9279 case NODE_TEST_NONE:
9280 xmlGenericError(xmlGenericErrorContext,
9281 " searching for none !!!\n");
9282 break;
9283 case NODE_TEST_TYPE:
9284 xmlGenericError(xmlGenericErrorContext,
9285 " searching for type %d\n", type);
9286 break;
9287 case NODE_TEST_PI:
9288 xmlGenericError(xmlGenericErrorContext,
9289 " searching for PI !!!\n");
9290 break;
9291 case NODE_TEST_ALL:
9292 xmlGenericError(xmlGenericErrorContext,
9293 " searching for *\n");
9294 break;
9295 case NODE_TEST_NS:
9296 xmlGenericError(xmlGenericErrorContext,
9297 " searching for namespace %s\n",
9298 prefix);
9299 break;
9300 case NODE_TEST_NAME:
9301 xmlGenericError(xmlGenericErrorContext,
9302 " searching for name %s\n", name);
9303 if (prefix != NULL)
9304 xmlGenericError(xmlGenericErrorContext,
9305 " with namespace %s\n", prefix);
9306 break;
9307 }
9308 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9309#endif
9310 /*
9311 * 2.3 Node Tests
9312 * - For the attribute axis, the principal node type is attribute.
9313 * - For the namespace axis, the principal node type is namespace.
9314 * - For other axes, the principal node type is element.
9315 *
9316 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009317 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009318 * select all element children of the context node
9319 */
9320 tmp = ctxt->context->node;
9321 list = xmlXPathNodeSetCreate(NULL);
9322 for (i = 0; i < nodelist->nodeNr; i++) {
9323 ctxt->context->node = nodelist->nodeTab[i];
9324
9325 cur = NULL;
9326 n = 0;
9327 do {
9328 cur = next(ctxt, cur);
9329 if (cur == NULL)
9330 break;
9331 if ((first != NULL) && (*first == cur))
9332 break;
9333 if (((t % 256) == 0) &&
9334 (first != NULL) && (*first != NULL) &&
9335 (xmlXPathCmpNodes(*first, cur) >= 0))
9336 break;
9337 if ((last != NULL) && (*last == cur))
9338 break;
9339 if (((t % 256) == 0) &&
9340 (last != NULL) && (*last != NULL) &&
9341 (xmlXPathCmpNodes(cur, *last) >= 0))
9342 break;
9343 t++;
9344 switch (test) {
9345 case NODE_TEST_NONE:
9346 ctxt->context->node = tmp;
9347 STRANGE return(0);
9348 case NODE_TEST_TYPE:
9349 if ((cur->type == type) ||
9350 ((type == NODE_TYPE_NODE) &&
9351 ((cur->type == XML_DOCUMENT_NODE) ||
9352 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9353 (cur->type == XML_ELEMENT_NODE) ||
9354 (cur->type == XML_PI_NODE) ||
9355 (cur->type == XML_COMMENT_NODE) ||
9356 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009357 (cur->type == XML_TEXT_NODE))) ||
9358 ((type == NODE_TYPE_TEXT) &&
9359 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009360 n++;
9361 if (n == indx)
9362 addNode(list, cur);
9363 }
9364 break;
9365 case NODE_TEST_PI:
9366 if (cur->type == XML_PI_NODE) {
9367 if ((name != NULL) &&
9368 (!xmlStrEqual(name, cur->name)))
9369 break;
9370 n++;
9371 if (n == indx)
9372 addNode(list, cur);
9373 }
9374 break;
9375 case NODE_TEST_ALL:
9376 if (axis == AXIS_ATTRIBUTE) {
9377 if (cur->type == XML_ATTRIBUTE_NODE) {
9378 n++;
9379 if (n == indx)
9380 addNode(list, cur);
9381 }
9382 } else if (axis == AXIS_NAMESPACE) {
9383 if (cur->type == XML_NAMESPACE_DECL) {
9384 n++;
9385 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009386 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9387 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009388 }
9389 } else {
9390 if (cur->type == XML_ELEMENT_NODE) {
9391 if (prefix == NULL) {
9392 n++;
9393 if (n == indx)
9394 addNode(list, cur);
9395 } else if ((cur->ns != NULL) &&
9396 (xmlStrEqual(URI, cur->ns->href))) {
9397 n++;
9398 if (n == indx)
9399 addNode(list, cur);
9400 }
9401 }
9402 }
9403 break;
9404 case NODE_TEST_NS:{
9405 TODO;
9406 break;
9407 }
9408 case NODE_TEST_NAME:
9409 switch (cur->type) {
9410 case XML_ELEMENT_NODE:
9411 if (xmlStrEqual(name, cur->name)) {
9412 if (prefix == NULL) {
9413 if (cur->ns == NULL) {
9414 n++;
9415 if (n == indx)
9416 addNode(list, cur);
9417 }
9418 } else {
9419 if ((cur->ns != NULL) &&
9420 (xmlStrEqual(URI,
9421 cur->ns->href))) {
9422 n++;
9423 if (n == indx)
9424 addNode(list, cur);
9425 }
9426 }
9427 }
9428 break;
9429 case XML_ATTRIBUTE_NODE:{
9430 xmlAttrPtr attr = (xmlAttrPtr) cur;
9431
9432 if (xmlStrEqual(name, attr->name)) {
9433 if (prefix == NULL) {
9434 if ((attr->ns == NULL) ||
9435 (attr->ns->prefix == NULL)) {
9436 n++;
9437 if (n == indx)
9438 addNode(list, cur);
9439 }
9440 } else {
9441 if ((attr->ns != NULL) &&
9442 (xmlStrEqual(URI,
9443 attr->ns->
9444 href))) {
9445 n++;
9446 if (n == indx)
9447 addNode(list, cur);
9448 }
9449 }
9450 }
9451 break;
9452 }
9453 case XML_NAMESPACE_DECL:
9454 if (cur->type == XML_NAMESPACE_DECL) {
9455 xmlNsPtr ns = (xmlNsPtr) cur;
9456
9457 if ((ns->prefix != NULL) && (name != NULL)
9458 && (xmlStrEqual(ns->prefix, name))) {
9459 n++;
9460 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009461 xmlXPathNodeSetAddNs(list,
9462 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009463 }
9464 }
9465 break;
9466 default:
9467 break;
9468 }
9469 break;
9470 break;
9471 }
9472 } while (n < indx);
9473 }
9474 ctxt->context->node = tmp;
9475#ifdef DEBUG_STEP_NTH
9476 xmlGenericError(xmlGenericErrorContext,
9477 "\nExamined %d nodes, found %d nodes at that step\n",
9478 t, list->nodeNr);
9479#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009480 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009481 if ((obj->boolval) && (obj->user != NULL)) {
9482 ctxt->value->boolval = 1;
9483 ctxt->value->user = obj->user;
9484 obj->user = NULL;
9485 obj->boolval = 0;
9486 }
9487 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009488 return(t);
9489}
9490
9491/**
9492 * xmlXPathCompOpEvalFirst:
9493 * @ctxt: the XPath parser context with the compiled expression
9494 * @op: an XPath compiled operation
9495 * @first: the first elem found so far
9496 *
9497 * Evaluate the Precompiled XPath operation searching only the first
9498 * element in document order
9499 *
9500 * Returns the number of examined objects.
9501 */
9502static int
9503xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9504 xmlXPathStepOpPtr op, xmlNodePtr * first)
9505{
9506 int total = 0, cur;
9507 xmlXPathCompExprPtr comp;
9508 xmlXPathObjectPtr arg1, arg2;
9509
Daniel Veillard556c6682001-10-06 09:59:51 +00009510 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009511 comp = ctxt->comp;
9512 switch (op->op) {
9513 case XPATH_OP_END:
9514 return (0);
9515 case XPATH_OP_UNION:
9516 total =
9517 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9518 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009519 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009520 if ((ctxt->value != NULL)
9521 && (ctxt->value->type == XPATH_NODESET)
9522 && (ctxt->value->nodesetval != NULL)
9523 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9524 /*
9525 * limit tree traversing to first node in the result
9526 */
9527 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9528 *first = ctxt->value->nodesetval->nodeTab[0];
9529 }
9530 cur =
9531 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9532 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009533 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009534 CHECK_TYPE0(XPATH_NODESET);
9535 arg2 = valuePop(ctxt);
9536
9537 CHECK_TYPE0(XPATH_NODESET);
9538 arg1 = valuePop(ctxt);
9539
9540 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9541 arg2->nodesetval);
9542 valuePush(ctxt, arg1);
9543 xmlXPathFreeObject(arg2);
9544 /* optimizer */
9545 if (total > cur)
9546 xmlXPathCompSwap(op);
9547 return (total + cur);
9548 case XPATH_OP_ROOT:
9549 xmlXPathRoot(ctxt);
9550 return (0);
9551 case XPATH_OP_NODE:
9552 if (op->ch1 != -1)
9553 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009554 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009555 if (op->ch2 != -1)
9556 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009557 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009558 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9559 return (total);
9560 case XPATH_OP_RESET:
9561 if (op->ch1 != -1)
9562 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009563 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009564 if (op->ch2 != -1)
9565 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009566 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009567 ctxt->context->node = NULL;
9568 return (total);
9569 case XPATH_OP_COLLECT:{
9570 if (op->ch1 == -1)
9571 return (total);
9572
9573 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009574 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009575
9576 /*
9577 * Optimization for [n] selection where n is a number
9578 */
9579 if ((op->ch2 != -1) &&
9580 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9581 (comp->steps[op->ch2].ch1 == -1) &&
9582 (comp->steps[op->ch2].ch2 != -1) &&
9583 (comp->steps[comp->steps[op->ch2].ch2].op ==
9584 XPATH_OP_VALUE)) {
9585 xmlXPathObjectPtr val;
9586
9587 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9588 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9589 int indx = (int) val->floatval;
9590
9591 if (val->floatval == (float) indx) {
9592 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9593 first, NULL);
9594 return (total);
9595 }
9596 }
9597 }
9598 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9599 return (total);
9600 }
9601 case XPATH_OP_VALUE:
9602 valuePush(ctxt,
9603 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9604 return (0);
9605 case XPATH_OP_SORT:
9606 if (op->ch1 != -1)
9607 total +=
9608 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9609 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009610 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009611 if ((ctxt->value != NULL)
9612 && (ctxt->value->type == XPATH_NODESET)
9613 && (ctxt->value->nodesetval != NULL))
9614 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9615 return (total);
9616 default:
9617 return (xmlXPathCompOpEval(ctxt, op));
9618 }
9619}
9620
9621/**
9622 * xmlXPathCompOpEvalLast:
9623 * @ctxt: the XPath parser context with the compiled expression
9624 * @op: an XPath compiled operation
9625 * @last: the last elem found so far
9626 *
9627 * Evaluate the Precompiled XPath operation searching only the last
9628 * element in document order
9629 *
9630 * Returns the number of node traversed
9631 */
9632static int
9633xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9634 xmlNodePtr * last)
9635{
9636 int total = 0, cur;
9637 xmlXPathCompExprPtr comp;
9638 xmlXPathObjectPtr arg1, arg2;
9639
Daniel Veillard556c6682001-10-06 09:59:51 +00009640 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009641 comp = ctxt->comp;
9642 switch (op->op) {
9643 case XPATH_OP_END:
9644 return (0);
9645 case XPATH_OP_UNION:
9646 total =
9647 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009648 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009649 if ((ctxt->value != NULL)
9650 && (ctxt->value->type == XPATH_NODESET)
9651 && (ctxt->value->nodesetval != NULL)
9652 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9653 /*
9654 * limit tree traversing to first node in the result
9655 */
9656 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9657 *last =
9658 ctxt->value->nodesetval->nodeTab[ctxt->value->
9659 nodesetval->nodeNr -
9660 1];
9661 }
9662 cur =
9663 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009664 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009665 if ((ctxt->value != NULL)
9666 && (ctxt->value->type == XPATH_NODESET)
9667 && (ctxt->value->nodesetval != NULL)
9668 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9669 }
9670 CHECK_TYPE0(XPATH_NODESET);
9671 arg2 = valuePop(ctxt);
9672
9673 CHECK_TYPE0(XPATH_NODESET);
9674 arg1 = valuePop(ctxt);
9675
9676 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9677 arg2->nodesetval);
9678 valuePush(ctxt, arg1);
9679 xmlXPathFreeObject(arg2);
9680 /* optimizer */
9681 if (total > cur)
9682 xmlXPathCompSwap(op);
9683 return (total + cur);
9684 case XPATH_OP_ROOT:
9685 xmlXPathRoot(ctxt);
9686 return (0);
9687 case XPATH_OP_NODE:
9688 if (op->ch1 != -1)
9689 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009690 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009691 if (op->ch2 != -1)
9692 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009693 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009694 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9695 return (total);
9696 case XPATH_OP_RESET:
9697 if (op->ch1 != -1)
9698 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009699 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009700 if (op->ch2 != -1)
9701 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009702 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009703 ctxt->context->node = NULL;
9704 return (total);
9705 case XPATH_OP_COLLECT:{
9706 if (op->ch1 == -1)
9707 return (0);
9708
9709 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009710 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009711
9712 /*
9713 * Optimization for [n] selection where n is a number
9714 */
9715 if ((op->ch2 != -1) &&
9716 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9717 (comp->steps[op->ch2].ch1 == -1) &&
9718 (comp->steps[op->ch2].ch2 != -1) &&
9719 (comp->steps[comp->steps[op->ch2].ch2].op ==
9720 XPATH_OP_VALUE)) {
9721 xmlXPathObjectPtr val;
9722
9723 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9724 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9725 int indx = (int) val->floatval;
9726
9727 if (val->floatval == (float) indx) {
9728 total +=
9729 xmlXPathNodeCollectAndTestNth(ctxt, op,
9730 indx, NULL,
9731 last);
9732 return (total);
9733 }
9734 }
9735 }
9736 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9737 return (total);
9738 }
9739 case XPATH_OP_VALUE:
9740 valuePush(ctxt,
9741 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9742 return (0);
9743 case XPATH_OP_SORT:
9744 if (op->ch1 != -1)
9745 total +=
9746 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9747 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009748 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009749 if ((ctxt->value != NULL)
9750 && (ctxt->value->type == XPATH_NODESET)
9751 && (ctxt->value->nodesetval != NULL))
9752 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9753 return (total);
9754 default:
9755 return (xmlXPathCompOpEval(ctxt, op));
9756 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009757}
9758
Owen Taylor3473f882001-02-23 17:55:21 +00009759/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009760 * xmlXPathCompOpEval:
9761 * @ctxt: the XPath parser context with the compiled expression
9762 * @op: an XPath compiled operation
9763 *
9764 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009765 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009766 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009767static int
9768xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9769{
9770 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009771 int equal, ret;
9772 xmlXPathCompExprPtr comp;
9773 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009774 xmlNodePtr bak;
9775 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009776 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009777 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009778
Daniel Veillard556c6682001-10-06 09:59:51 +00009779 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009780 comp = ctxt->comp;
9781 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009782 case XPATH_OP_END:
9783 return (0);
9784 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009785 bakd = ctxt->context->doc;
9786 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009787 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009788 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009789 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009790 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009791 xmlXPathBooleanFunction(ctxt, 1);
9792 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9793 return (total);
9794 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009795 ctxt->context->doc = bakd;
9796 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009797 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009798 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009799 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009800 if (ctxt->error) {
9801 xmlXPathFreeObject(arg2);
9802 return(0);
9803 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009804 xmlXPathBooleanFunction(ctxt, 1);
9805 arg1 = valuePop(ctxt);
9806 arg1->boolval &= arg2->boolval;
9807 valuePush(ctxt, arg1);
9808 xmlXPathFreeObject(arg2);
9809 return (total);
9810 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009811 bakd = ctxt->context->doc;
9812 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009813 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009814 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009815 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009816 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009817 xmlXPathBooleanFunction(ctxt, 1);
9818 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9819 return (total);
9820 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009821 ctxt->context->doc = bakd;
9822 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009823 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009824 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009825 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009826 if (ctxt->error) {
9827 xmlXPathFreeObject(arg2);
9828 return(0);
9829 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009830 xmlXPathBooleanFunction(ctxt, 1);
9831 arg1 = valuePop(ctxt);
9832 arg1->boolval |= arg2->boolval;
9833 valuePush(ctxt, arg1);
9834 xmlXPathFreeObject(arg2);
9835 return (total);
9836 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009837 bakd = ctxt->context->doc;
9838 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009839 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009840 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009841 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009842 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009843 ctxt->context->doc = bakd;
9844 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009845 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009846 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009847 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009848 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009849 if (op->value)
9850 equal = xmlXPathEqualValues(ctxt);
9851 else
9852 equal = xmlXPathNotEqualValues(ctxt);
9853 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009854 return (total);
9855 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009856 bakd = ctxt->context->doc;
9857 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009858 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009859 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009860 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009861 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009862 ctxt->context->doc = bakd;
9863 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009864 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009865 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009866 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009867 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009868 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9869 valuePush(ctxt, xmlXPathNewBoolean(ret));
9870 return (total);
9871 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009872 bakd = ctxt->context->doc;
9873 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009874 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009875 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009876 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009877 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009878 if (op->ch2 != -1) {
9879 ctxt->context->doc = bakd;
9880 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009881 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009882 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009883 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009884 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009885 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009886 if (op->value == 0)
9887 xmlXPathSubValues(ctxt);
9888 else if (op->value == 1)
9889 xmlXPathAddValues(ctxt);
9890 else if (op->value == 2)
9891 xmlXPathValueFlipSign(ctxt);
9892 else if (op->value == 3) {
9893 CAST_TO_NUMBER;
9894 CHECK_TYPE0(XPATH_NUMBER);
9895 }
9896 return (total);
9897 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009898 bakd = ctxt->context->doc;
9899 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009900 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009901 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009902 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009903 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009904 ctxt->context->doc = bakd;
9905 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009906 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009907 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009908 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009909 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009910 if (op->value == 0)
9911 xmlXPathMultValues(ctxt);
9912 else if (op->value == 1)
9913 xmlXPathDivValues(ctxt);
9914 else if (op->value == 2)
9915 xmlXPathModValues(ctxt);
9916 return (total);
9917 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009918 bakd = ctxt->context->doc;
9919 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009920 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009921 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009923 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009924 ctxt->context->doc = bakd;
9925 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009926 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009927 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009928 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009929 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009930 CHECK_TYPE0(XPATH_NODESET);
9931 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009932
Daniel Veillardf06307e2001-07-03 10:35:50 +00009933 CHECK_TYPE0(XPATH_NODESET);
9934 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009935
Daniel Veillardf06307e2001-07-03 10:35:50 +00009936 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9937 arg2->nodesetval);
9938 valuePush(ctxt, arg1);
9939 xmlXPathFreeObject(arg2);
9940 return (total);
9941 case XPATH_OP_ROOT:
9942 xmlXPathRoot(ctxt);
9943 return (total);
9944 case XPATH_OP_NODE:
9945 if (op->ch1 != -1)
9946 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009947 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 if (op->ch2 != -1)
9949 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009950 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009951 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9952 return (total);
9953 case XPATH_OP_RESET:
9954 if (op->ch1 != -1)
9955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009956 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009957 if (op->ch2 != -1)
9958 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009959 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009960 ctxt->context->node = NULL;
9961 return (total);
9962 case XPATH_OP_COLLECT:{
9963 if (op->ch1 == -1)
9964 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009965
Daniel Veillardf06307e2001-07-03 10:35:50 +00009966 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009967 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009968
Daniel Veillardf06307e2001-07-03 10:35:50 +00009969 /*
9970 * Optimization for [n] selection where n is a number
9971 */
9972 if ((op->ch2 != -1) &&
9973 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9974 (comp->steps[op->ch2].ch1 == -1) &&
9975 (comp->steps[op->ch2].ch2 != -1) &&
9976 (comp->steps[comp->steps[op->ch2].ch2].op ==
9977 XPATH_OP_VALUE)) {
9978 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009979
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9981 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9982 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009983
Daniel Veillardf06307e2001-07-03 10:35:50 +00009984 if (val->floatval == (float) indx) {
9985 total +=
9986 xmlXPathNodeCollectAndTestNth(ctxt, op,
9987 indx, NULL,
9988 NULL);
9989 return (total);
9990 }
9991 }
9992 }
9993 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9994 return (total);
9995 }
9996 case XPATH_OP_VALUE:
9997 valuePush(ctxt,
9998 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9999 return (total);
10000 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010001 xmlXPathObjectPtr val;
10002
Daniel Veillardf06307e2001-07-03 10:35:50 +000010003 if (op->ch1 != -1)
10004 total +=
10005 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010006 if (op->value5 == NULL) {
10007 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10008 if (val == NULL) {
10009 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10010 return(0);
10011 }
10012 valuePush(ctxt, val);
10013 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010014 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010015
Daniel Veillardf06307e2001-07-03 10:35:50 +000010016 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10017 if (URI == NULL) {
10018 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010019 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010020 op->value4, op->value5);
10021 return (total);
10022 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010023 val = xmlXPathVariableLookupNS(ctxt->context,
10024 op->value4, URI);
10025 if (val == NULL) {
10026 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10027 return(0);
10028 }
10029 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010030 }
10031 return (total);
10032 }
10033 case XPATH_OP_FUNCTION:{
10034 xmlXPathFunction func;
10035 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010036 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010037
10038 if (op->ch1 != -1)
10039 total +=
10040 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010041 if (ctxt->valueNr < op->value) {
10042 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010043 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010044 ctxt->error = XPATH_INVALID_OPERAND;
10045 return (total);
10046 }
10047 for (i = 0; i < op->value; i++)
10048 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10049 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010050 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010051 ctxt->error = XPATH_INVALID_OPERAND;
10052 return (total);
10053 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010054 if (op->cache != NULL)
10055 func = (xmlXPathFunction) op->cache;
10056 else {
10057 const xmlChar *URI = NULL;
10058
10059 if (op->value5 == NULL)
10060 func =
10061 xmlXPathFunctionLookup(ctxt->context,
10062 op->value4);
10063 else {
10064 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10065 if (URI == NULL) {
10066 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010067 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010068 op->value4, op->value5);
10069 return (total);
10070 }
10071 func = xmlXPathFunctionLookupNS(ctxt->context,
10072 op->value4, URI);
10073 }
10074 if (func == NULL) {
10075 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010076 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010077 op->value4);
10078 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079 }
10080 op->cache = (void *) func;
10081 op->cacheURI = (void *) URI;
10082 }
10083 oldFunc = ctxt->context->function;
10084 oldFuncURI = ctxt->context->functionURI;
10085 ctxt->context->function = op->value4;
10086 ctxt->context->functionURI = op->cacheURI;
10087 func(ctxt, op->value);
10088 ctxt->context->function = oldFunc;
10089 ctxt->context->functionURI = oldFuncURI;
10090 return (total);
10091 }
10092 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010093 bakd = ctxt->context->doc;
10094 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010095 if (op->ch1 != -1)
10096 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010097 ctxt->context->doc = bakd;
10098 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010099 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010100 if (op->ch2 != -1)
10101 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010102 ctxt->context->doc = bakd;
10103 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010104 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010105 return (total);
10106 case XPATH_OP_PREDICATE:
10107 case XPATH_OP_FILTER:{
10108 xmlXPathObjectPtr res;
10109 xmlXPathObjectPtr obj, tmp;
10110 xmlNodeSetPtr newset = NULL;
10111 xmlNodeSetPtr oldset;
10112 xmlNodePtr oldnode;
10113 int i;
10114
10115 /*
10116 * Optimization for ()[1] selection i.e. the first elem
10117 */
10118 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10119 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10120 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10121 xmlXPathObjectPtr val;
10122
10123 val = comp->steps[op->ch2].value4;
10124 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10125 (val->floatval == 1.0)) {
10126 xmlNodePtr first = NULL;
10127
10128 total +=
10129 xmlXPathCompOpEvalFirst(ctxt,
10130 &comp->steps[op->ch1],
10131 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010132 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010133 /*
10134 * The nodeset should be in document order,
10135 * Keep only the first value
10136 */
10137 if ((ctxt->value != NULL) &&
10138 (ctxt->value->type == XPATH_NODESET) &&
10139 (ctxt->value->nodesetval != NULL) &&
10140 (ctxt->value->nodesetval->nodeNr > 1))
10141 ctxt->value->nodesetval->nodeNr = 1;
10142 return (total);
10143 }
10144 }
10145 /*
10146 * Optimization for ()[last()] selection i.e. the last elem
10147 */
10148 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10149 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10150 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10151 int f = comp->steps[op->ch2].ch1;
10152
10153 if ((f != -1) &&
10154 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10155 (comp->steps[f].value5 == NULL) &&
10156 (comp->steps[f].value == 0) &&
10157 (comp->steps[f].value4 != NULL) &&
10158 (xmlStrEqual
10159 (comp->steps[f].value4, BAD_CAST "last"))) {
10160 xmlNodePtr last = NULL;
10161
10162 total +=
10163 xmlXPathCompOpEvalLast(ctxt,
10164 &comp->steps[op->ch1],
10165 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010166 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010167 /*
10168 * The nodeset should be in document order,
10169 * Keep only the last value
10170 */
10171 if ((ctxt->value != NULL) &&
10172 (ctxt->value->type == XPATH_NODESET) &&
10173 (ctxt->value->nodesetval != NULL) &&
10174 (ctxt->value->nodesetval->nodeTab != NULL) &&
10175 (ctxt->value->nodesetval->nodeNr > 1)) {
10176 ctxt->value->nodesetval->nodeTab[0] =
10177 ctxt->value->nodesetval->nodeTab[ctxt->
10178 value->
10179 nodesetval->
10180 nodeNr -
10181 1];
10182 ctxt->value->nodesetval->nodeNr = 1;
10183 }
10184 return (total);
10185 }
10186 }
10187
10188 if (op->ch1 != -1)
10189 total +=
10190 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010191 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010192 if (op->ch2 == -1)
10193 return (total);
10194 if (ctxt->value == NULL)
10195 return (total);
10196
10197 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010198
10199#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010200 /*
10201 * Hum are we filtering the result of an XPointer expression
10202 */
10203 if (ctxt->value->type == XPATH_LOCATIONSET) {
10204 xmlLocationSetPtr newlocset = NULL;
10205 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010206
Daniel Veillardf06307e2001-07-03 10:35:50 +000010207 /*
10208 * Extract the old locset, and then evaluate the result of the
10209 * expression for all the element in the locset. use it to grow
10210 * up a new locset.
10211 */
10212 CHECK_TYPE0(XPATH_LOCATIONSET);
10213 obj = valuePop(ctxt);
10214 oldlocset = obj->user;
10215 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010216
Daniel Veillardf06307e2001-07-03 10:35:50 +000010217 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10218 ctxt->context->contextSize = 0;
10219 ctxt->context->proximityPosition = 0;
10220 if (op->ch2 != -1)
10221 total +=
10222 xmlXPathCompOpEval(ctxt,
10223 &comp->steps[op->ch2]);
10224 res = valuePop(ctxt);
10225 if (res != NULL)
10226 xmlXPathFreeObject(res);
10227 valuePush(ctxt, obj);
10228 CHECK_ERROR0;
10229 return (total);
10230 }
10231 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010232
Daniel Veillardf06307e2001-07-03 10:35:50 +000010233 for (i = 0; i < oldlocset->locNr; i++) {
10234 /*
10235 * Run the evaluation with a node list made of a
10236 * single item in the nodelocset.
10237 */
10238 ctxt->context->node = oldlocset->locTab[i]->user;
10239 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10240 valuePush(ctxt, tmp);
10241 ctxt->context->contextSize = oldlocset->locNr;
10242 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010243
Daniel Veillardf06307e2001-07-03 10:35:50 +000010244 if (op->ch2 != -1)
10245 total +=
10246 xmlXPathCompOpEval(ctxt,
10247 &comp->steps[op->ch2]);
10248 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010249
Daniel Veillardf06307e2001-07-03 10:35:50 +000010250 /*
10251 * The result of the evaluation need to be tested to
10252 * decided whether the filter succeeded or not
10253 */
10254 res = valuePop(ctxt);
10255 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10256 xmlXPtrLocationSetAdd(newlocset,
10257 xmlXPathObjectCopy
10258 (oldlocset->locTab[i]));
10259 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010260
Daniel Veillardf06307e2001-07-03 10:35:50 +000010261 /*
10262 * Cleanup
10263 */
10264 if (res != NULL)
10265 xmlXPathFreeObject(res);
10266 if (ctxt->value == tmp) {
10267 res = valuePop(ctxt);
10268 xmlXPathFreeObject(res);
10269 }
10270
10271 ctxt->context->node = NULL;
10272 }
10273
10274 /*
10275 * The result is used as the new evaluation locset.
10276 */
10277 xmlXPathFreeObject(obj);
10278 ctxt->context->node = NULL;
10279 ctxt->context->contextSize = -1;
10280 ctxt->context->proximityPosition = -1;
10281 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10282 ctxt->context->node = oldnode;
10283 return (total);
10284 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010285#endif /* LIBXML_XPTR_ENABLED */
10286
Daniel Veillardf06307e2001-07-03 10:35:50 +000010287 /*
10288 * Extract the old set, and then evaluate the result of the
10289 * expression for all the element in the set. use it to grow
10290 * up a new set.
10291 */
10292 CHECK_TYPE0(XPATH_NODESET);
10293 obj = valuePop(ctxt);
10294 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010295
Daniel Veillardf06307e2001-07-03 10:35:50 +000010296 oldnode = ctxt->context->node;
10297 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010298
Daniel Veillardf06307e2001-07-03 10:35:50 +000010299 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10300 ctxt->context->contextSize = 0;
10301 ctxt->context->proximityPosition = 0;
10302 if (op->ch2 != -1)
10303 total +=
10304 xmlXPathCompOpEval(ctxt,
10305 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010306 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010307 res = valuePop(ctxt);
10308 if (res != NULL)
10309 xmlXPathFreeObject(res);
10310 valuePush(ctxt, obj);
10311 ctxt->context->node = oldnode;
10312 CHECK_ERROR0;
10313 } else {
10314 /*
10315 * Initialize the new set.
10316 */
10317 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010318
Daniel Veillardf06307e2001-07-03 10:35:50 +000010319 for (i = 0; i < oldset->nodeNr; i++) {
10320 /*
10321 * Run the evaluation with a node list made of
10322 * a single item in the nodeset.
10323 */
10324 ctxt->context->node = oldset->nodeTab[i];
10325 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10326 valuePush(ctxt, tmp);
10327 ctxt->context->contextSize = oldset->nodeNr;
10328 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010329
Daniel Veillardf06307e2001-07-03 10:35:50 +000010330 if (op->ch2 != -1)
10331 total +=
10332 xmlXPathCompOpEval(ctxt,
10333 &comp->steps[op->ch2]);
10334 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010335
Daniel Veillardf06307e2001-07-03 10:35:50 +000010336 /*
10337 * The result of the evaluation need to be tested to
10338 * decided whether the filter succeeded or not
10339 */
10340 res = valuePop(ctxt);
10341 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10342 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10343 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010344
Daniel Veillardf06307e2001-07-03 10:35:50 +000010345 /*
10346 * Cleanup
10347 */
10348 if (res != NULL)
10349 xmlXPathFreeObject(res);
10350 if (ctxt->value == tmp) {
10351 res = valuePop(ctxt);
10352 xmlXPathFreeObject(res);
10353 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010354
Daniel Veillardf06307e2001-07-03 10:35:50 +000010355 ctxt->context->node = NULL;
10356 }
10357
10358 /*
10359 * The result is used as the new evaluation set.
10360 */
10361 xmlXPathFreeObject(obj);
10362 ctxt->context->node = NULL;
10363 ctxt->context->contextSize = -1;
10364 ctxt->context->proximityPosition = -1;
10365 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10366 }
10367 ctxt->context->node = oldnode;
10368 return (total);
10369 }
10370 case XPATH_OP_SORT:
10371 if (op->ch1 != -1)
10372 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010373 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010374 if ((ctxt->value != NULL) &&
10375 (ctxt->value->type == XPATH_NODESET) &&
10376 (ctxt->value->nodesetval != NULL))
10377 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10378 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010379#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010380 case XPATH_OP_RANGETO:{
10381 xmlXPathObjectPtr range;
10382 xmlXPathObjectPtr res, obj;
10383 xmlXPathObjectPtr tmp;
10384 xmlLocationSetPtr newset = NULL;
10385 xmlNodeSetPtr oldset;
10386 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010387
Daniel Veillardf06307e2001-07-03 10:35:50 +000010388 if (op->ch1 != -1)
10389 total +=
10390 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10391 if (op->ch2 == -1)
10392 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010393
Daniel Veillardf06307e2001-07-03 10:35:50 +000010394 CHECK_TYPE0(XPATH_NODESET);
10395 obj = valuePop(ctxt);
10396 oldset = obj->nodesetval;
10397 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010398
Daniel Veillardf06307e2001-07-03 10:35:50 +000010399 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010400
Daniel Veillardf06307e2001-07-03 10:35:50 +000010401 if (oldset != NULL) {
10402 for (i = 0; i < oldset->nodeNr; i++) {
10403 /*
10404 * Run the evaluation with a node list made of a single item
10405 * in the nodeset.
10406 */
10407 ctxt->context->node = oldset->nodeTab[i];
10408 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10409 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010410
Daniel Veillardf06307e2001-07-03 10:35:50 +000010411 if (op->ch2 != -1)
10412 total +=
10413 xmlXPathCompOpEval(ctxt,
10414 &comp->steps[op->ch2]);
10415 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010416
Daniel Veillardf06307e2001-07-03 10:35:50 +000010417 /*
10418 * The result of the evaluation need to be tested to
10419 * decided whether the filter succeeded or not
10420 */
10421 res = valuePop(ctxt);
10422 range =
10423 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10424 res);
10425 if (range != NULL) {
10426 xmlXPtrLocationSetAdd(newset, range);
10427 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010428
Daniel Veillardf06307e2001-07-03 10:35:50 +000010429 /*
10430 * Cleanup
10431 */
10432 if (res != NULL)
10433 xmlXPathFreeObject(res);
10434 if (ctxt->value == tmp) {
10435 res = valuePop(ctxt);
10436 xmlXPathFreeObject(res);
10437 }
10438
10439 ctxt->context->node = NULL;
10440 }
10441 }
10442
10443 /*
10444 * The result is used as the new evaluation set.
10445 */
10446 xmlXPathFreeObject(obj);
10447 ctxt->context->node = NULL;
10448 ctxt->context->contextSize = -1;
10449 ctxt->context->proximityPosition = -1;
10450 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10451 return (total);
10452 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010453#endif /* LIBXML_XPTR_ENABLED */
10454 }
10455 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010456 "XPath: unknown precompiled operation %d\n", op->op);
10457 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010458}
10459
10460/**
10461 * xmlXPathRunEval:
10462 * @ctxt: the XPath parser context with the compiled expression
10463 *
10464 * Evaluate the Precompiled XPath expression in the given context.
10465 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010466static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010467xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10468 xmlXPathCompExprPtr comp;
10469
10470 if ((ctxt == NULL) || (ctxt->comp == NULL))
10471 return;
10472
10473 if (ctxt->valueTab == NULL) {
10474 /* Allocate the value stack */
10475 ctxt->valueTab = (xmlXPathObjectPtr *)
10476 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10477 if (ctxt->valueTab == NULL) {
10478 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010479 }
10480 ctxt->valueNr = 0;
10481 ctxt->valueMax = 10;
10482 ctxt->value = NULL;
10483 }
10484 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010485 if(comp->last < 0) {
10486 xmlGenericError(xmlGenericErrorContext,
10487 "xmlXPathRunEval: last is less than zero\n");
10488 return;
10489 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010490 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10491}
10492
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010493/************************************************************************
10494 * *
10495 * Public interfaces *
10496 * *
10497 ************************************************************************/
10498
10499/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010500 * xmlXPathEvalPredicate:
10501 * @ctxt: the XPath context
10502 * @res: the Predicate Expression evaluation result
10503 *
10504 * Evaluate a predicate result for the current node.
10505 * A PredicateExpr is evaluated by evaluating the Expr and converting
10506 * the result to a boolean. If the result is a number, the result will
10507 * be converted to true if the number is equal to the position of the
10508 * context node in the context node list (as returned by the position
10509 * function) and will be converted to false otherwise; if the result
10510 * is not a number, then the result will be converted as if by a call
10511 * to the boolean function.
10512 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010513 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010514 */
10515int
10516xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10517 if (res == NULL) return(0);
10518 switch (res->type) {
10519 case XPATH_BOOLEAN:
10520 return(res->boolval);
10521 case XPATH_NUMBER:
10522 return(res->floatval == ctxt->proximityPosition);
10523 case XPATH_NODESET:
10524 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010525 if (res->nodesetval == NULL)
10526 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010527 return(res->nodesetval->nodeNr != 0);
10528 case XPATH_STRING:
10529 return((res->stringval != NULL) &&
10530 (xmlStrlen(res->stringval) != 0));
10531 default:
10532 STRANGE
10533 }
10534 return(0);
10535}
10536
10537/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010538 * xmlXPathEvaluatePredicateResult:
10539 * @ctxt: the XPath Parser context
10540 * @res: the Predicate Expression evaluation result
10541 *
10542 * Evaluate a predicate result for the current node.
10543 * A PredicateExpr is evaluated by evaluating the Expr and converting
10544 * the result to a boolean. If the result is a number, the result will
10545 * be converted to true if the number is equal to the position of the
10546 * context node in the context node list (as returned by the position
10547 * function) and will be converted to false otherwise; if the result
10548 * is not a number, then the result will be converted as if by a call
10549 * to the boolean function.
10550 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010551 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010552 */
10553int
10554xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10555 xmlXPathObjectPtr res) {
10556 if (res == NULL) return(0);
10557 switch (res->type) {
10558 case XPATH_BOOLEAN:
10559 return(res->boolval);
10560 case XPATH_NUMBER:
10561 return(res->floatval == ctxt->context->proximityPosition);
10562 case XPATH_NODESET:
10563 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010564 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010565 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010566 return(res->nodesetval->nodeNr != 0);
10567 case XPATH_STRING:
10568 return((res->stringval != NULL) &&
10569 (xmlStrlen(res->stringval) != 0));
10570 default:
10571 STRANGE
10572 }
10573 return(0);
10574}
10575
10576/**
10577 * xmlXPathCompile:
10578 * @str: the XPath expression
10579 *
10580 * Compile an XPath expression
10581 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010582 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010583 * the caller has to free the object.
10584 */
10585xmlXPathCompExprPtr
10586xmlXPathCompile(const xmlChar *str) {
10587 xmlXPathParserContextPtr ctxt;
10588 xmlXPathCompExprPtr comp;
10589
10590 xmlXPathInit();
10591
10592 ctxt = xmlXPathNewParserContext(str, NULL);
10593 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010594
Daniel Veillard40af6492001-04-22 08:50:55 +000010595 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010596 /*
10597 * aleksey: in some cases this line prints *second* error message
10598 * (see bug #78858) and probably this should be fixed.
10599 * However, we are not sure that all error messages are printed
10600 * out in other places. It's not critical so we leave it as-is for now
10601 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010602 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10603 comp = NULL;
10604 } else {
10605 comp = ctxt->comp;
10606 ctxt->comp = NULL;
10607 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010608 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010609 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010610 comp->expr = xmlStrdup(str);
10611#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010612 comp->string = xmlStrdup(str);
10613 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010614#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010615 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010616 return(comp);
10617}
10618
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010619/**
10620 * xmlXPathCompiledEval:
10621 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010622 * @ctx: the XPath context
10623 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010624 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010625 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010626 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010627 * the caller has to free the object.
10628 */
10629xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010630xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010631 xmlXPathParserContextPtr ctxt;
10632 xmlXPathObjectPtr res, tmp, init = NULL;
10633 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010634#ifndef LIBXML_THREAD_ENABLED
10635 static int reentance = 0;
10636#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010637
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010638 if ((comp == NULL) || (ctx == NULL))
10639 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010640 xmlXPathInit();
10641
10642 CHECK_CONTEXT(ctx)
10643
Daniel Veillard81463942001-10-16 12:34:39 +000010644#ifndef LIBXML_THREAD_ENABLED
10645 reentance++;
10646 if (reentance > 1)
10647 xmlXPathDisableOptimizer = 1;
10648#endif
10649
Daniel Veillardf06307e2001-07-03 10:35:50 +000010650#ifdef DEBUG_EVAL_COUNTS
10651 comp->nb++;
10652 if ((comp->string != NULL) && (comp->nb > 100)) {
10653 fprintf(stderr, "100 x %s\n", comp->string);
10654 comp->nb = 0;
10655 }
10656#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010657 ctxt = xmlXPathCompParserContext(comp, ctx);
10658 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010659
10660 if (ctxt->value == NULL) {
10661 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010662 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010663 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010664 } else {
10665 res = valuePop(ctxt);
10666 }
10667
Daniel Veillardf06307e2001-07-03 10:35:50 +000010668
Owen Taylor3473f882001-02-23 17:55:21 +000010669 do {
10670 tmp = valuePop(ctxt);
10671 if (tmp != NULL) {
10672 if (tmp != init)
10673 stack++;
10674 xmlXPathFreeObject(tmp);
10675 }
10676 } while (tmp != NULL);
10677 if ((stack != 0) && (res != NULL)) {
10678 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010679 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010680 stack);
10681 }
10682 if (ctxt->error != XPATH_EXPRESSION_OK) {
10683 xmlXPathFreeObject(res);
10684 res = NULL;
10685 }
10686
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010687
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010688 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010689 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010690#ifndef LIBXML_THREAD_ENABLED
10691 reentance--;
10692#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010693 return(res);
10694}
10695
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010696/**
10697 * xmlXPathEvalExpr:
10698 * @ctxt: the XPath Parser context
10699 *
10700 * Parse and evaluate an XPath expression in the given context,
10701 * then push the result on the context stack
10702 */
10703void
10704xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10705 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010706 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010707 xmlXPathRunEval(ctxt);
10708}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010709
10710/**
10711 * xmlXPathEval:
10712 * @str: the XPath expression
10713 * @ctx: the XPath context
10714 *
10715 * Evaluate the XPath Location Path in the given context.
10716 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010717 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010718 * the caller has to free the object.
10719 */
10720xmlXPathObjectPtr
10721xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10722 xmlXPathParserContextPtr ctxt;
10723 xmlXPathObjectPtr res, tmp, init = NULL;
10724 int stack = 0;
10725
10726 xmlXPathInit();
10727
10728 CHECK_CONTEXT(ctx)
10729
10730 ctxt = xmlXPathNewParserContext(str, ctx);
10731 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010732
10733 if (ctxt->value == NULL) {
10734 xmlGenericError(xmlGenericErrorContext,
10735 "xmlXPathEval: evaluation failed\n");
10736 res = NULL;
10737 } else if (*ctxt->cur != 0) {
10738 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10739 res = NULL;
10740 } else {
10741 res = valuePop(ctxt);
10742 }
10743
10744 do {
10745 tmp = valuePop(ctxt);
10746 if (tmp != NULL) {
10747 if (tmp != init)
10748 stack++;
10749 xmlXPathFreeObject(tmp);
10750 }
10751 } while (tmp != NULL);
10752 if ((stack != 0) && (res != NULL)) {
10753 xmlGenericError(xmlGenericErrorContext,
10754 "xmlXPathEval: %d object left on the stack\n",
10755 stack);
10756 }
10757 if (ctxt->error != XPATH_EXPRESSION_OK) {
10758 xmlXPathFreeObject(res);
10759 res = NULL;
10760 }
10761
Owen Taylor3473f882001-02-23 17:55:21 +000010762 xmlXPathFreeParserContext(ctxt);
10763 return(res);
10764}
10765
10766/**
10767 * xmlXPathEvalExpression:
10768 * @str: the XPath expression
10769 * @ctxt: the XPath context
10770 *
10771 * Evaluate the XPath expression in the given context.
10772 *
10773 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10774 * the caller has to free the object.
10775 */
10776xmlXPathObjectPtr
10777xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10778 xmlXPathParserContextPtr pctxt;
10779 xmlXPathObjectPtr res, tmp;
10780 int stack = 0;
10781
10782 xmlXPathInit();
10783
10784 CHECK_CONTEXT(ctxt)
10785
10786 pctxt = xmlXPathNewParserContext(str, ctxt);
10787 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010788
10789 if (*pctxt->cur != 0) {
10790 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10791 res = NULL;
10792 } else {
10793 res = valuePop(pctxt);
10794 }
10795 do {
10796 tmp = valuePop(pctxt);
10797 if (tmp != NULL) {
10798 xmlXPathFreeObject(tmp);
10799 stack++;
10800 }
10801 } while (tmp != NULL);
10802 if ((stack != 0) && (res != NULL)) {
10803 xmlGenericError(xmlGenericErrorContext,
10804 "xmlXPathEvalExpression: %d object left on the stack\n",
10805 stack);
10806 }
10807 xmlXPathFreeParserContext(pctxt);
10808 return(res);
10809}
10810
Daniel Veillard42766c02002-08-22 20:52:17 +000010811/************************************************************************
10812 * *
10813 * Extra functions not pertaining to the XPath spec *
10814 * *
10815 ************************************************************************/
10816/**
10817 * xmlXPathEscapeUriFunction:
10818 * @ctxt: the XPath Parser context
10819 * @nargs: the number of arguments
10820 *
10821 * Implement the escape-uri() XPath function
10822 * string escape-uri(string $str, bool $escape-reserved)
10823 *
10824 * This function applies the URI escaping rules defined in section 2 of [RFC
10825 * 2396] to the string supplied as $uri-part, which typically represents all
10826 * or part of a URI. The effect of the function is to replace any special
10827 * character in the string by an escape sequence of the form %xx%yy...,
10828 * where xxyy... is the hexadecimal representation of the octets used to
10829 * represent the character in UTF-8.
10830 *
10831 * The set of characters that are escaped depends on the setting of the
10832 * boolean argument $escape-reserved.
10833 *
10834 * If $escape-reserved is true, all characters are escaped other than lower
10835 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10836 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10837 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10838 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10839 * A-F).
10840 *
10841 * If $escape-reserved is false, the behavior differs in that characters
10842 * referred to in [RFC 2396] as reserved characters are not escaped. These
10843 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10844 *
10845 * [RFC 2396] does not define whether escaped URIs should use lower case or
10846 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10847 * compared using string comparison functions, this function must always use
10848 * the upper-case letters A-F.
10849 *
10850 * Generally, $escape-reserved should be set to true when escaping a string
10851 * that is to form a single part of a URI, and to false when escaping an
10852 * entire URI or URI reference.
10853 *
10854 * In the case of non-ascii characters, the string is encoded according to
10855 * utf-8 and then converted according to RFC 2396.
10856 *
10857 * Examples
10858 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10859 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10860 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10861 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10862 *
10863 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010864static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010865xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10866 xmlXPathObjectPtr str;
10867 int escape_reserved;
10868 xmlBufferPtr target;
10869 xmlChar *cptr;
10870 xmlChar escape[4];
10871
10872 CHECK_ARITY(2);
10873
10874 escape_reserved = xmlXPathPopBoolean(ctxt);
10875
10876 CAST_TO_STRING;
10877 str = valuePop(ctxt);
10878
10879 target = xmlBufferCreate();
10880
10881 escape[0] = '%';
10882 escape[3] = 0;
10883
10884 if (target) {
10885 for (cptr = str->stringval; *cptr; cptr++) {
10886 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10887 (*cptr >= 'a' && *cptr <= 'z') ||
10888 (*cptr >= '0' && *cptr <= '9') ||
10889 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10890 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10891 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10892 (*cptr == '%' &&
10893 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10894 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10895 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10896 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10897 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10898 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10899 (!escape_reserved &&
10900 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10901 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10902 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10903 *cptr == ','))) {
10904 xmlBufferAdd(target, cptr, 1);
10905 } else {
10906 if ((*cptr >> 4) < 10)
10907 escape[1] = '0' + (*cptr >> 4);
10908 else
10909 escape[1] = 'A' - 10 + (*cptr >> 4);
10910 if ((*cptr & 0xF) < 10)
10911 escape[2] = '0' + (*cptr & 0xF);
10912 else
10913 escape[2] = 'A' - 10 + (*cptr & 0xF);
10914
10915 xmlBufferAdd(target, &escape[0], 3);
10916 }
10917 }
10918 }
10919 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10920 xmlBufferFree(target);
10921 xmlXPathFreeObject(str);
10922}
10923
Owen Taylor3473f882001-02-23 17:55:21 +000010924/**
10925 * xmlXPathRegisterAllFunctions:
10926 * @ctxt: the XPath context
10927 *
10928 * Registers all default XPath functions in this context
10929 */
10930void
10931xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10932{
10933 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10934 xmlXPathBooleanFunction);
10935 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10936 xmlXPathCeilingFunction);
10937 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10938 xmlXPathCountFunction);
10939 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10940 xmlXPathConcatFunction);
10941 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10942 xmlXPathContainsFunction);
10943 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10944 xmlXPathIdFunction);
10945 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10946 xmlXPathFalseFunction);
10947 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10948 xmlXPathFloorFunction);
10949 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10950 xmlXPathLastFunction);
10951 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10952 xmlXPathLangFunction);
10953 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10954 xmlXPathLocalNameFunction);
10955 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10956 xmlXPathNotFunction);
10957 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10958 xmlXPathNameFunction);
10959 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10960 xmlXPathNamespaceURIFunction);
10961 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10962 xmlXPathNormalizeFunction);
10963 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10964 xmlXPathNumberFunction);
10965 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10966 xmlXPathPositionFunction);
10967 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10968 xmlXPathRoundFunction);
10969 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10970 xmlXPathStringFunction);
10971 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10972 xmlXPathStringLengthFunction);
10973 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10974 xmlXPathStartsWithFunction);
10975 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10976 xmlXPathSubstringFunction);
10977 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10978 xmlXPathSubstringBeforeFunction);
10979 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10980 xmlXPathSubstringAfterFunction);
10981 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10982 xmlXPathSumFunction);
10983 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10984 xmlXPathTrueFunction);
10985 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10986 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000010987
10988 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
10989 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
10990 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000010991}
10992
10993#endif /* LIBXML_XPATH_ENABLED */