blob: fc39cf7f5be8047d050d1f7cc748abab68fa801b [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 Veillard01c13b52002-12-10 15:19:08 +00003808 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003809 * @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/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004196 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004197 * @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/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004251 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004252 * @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/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004307 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004308 * @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:
Owen Taylor3473f882001-02-23 17:55:21 +00007545 * @name: a name string
7546 *
7547 * Is the name given a NodeType one.
7548 *
7549 * [38] NodeType ::= 'comment'
7550 * | 'text'
7551 * | 'processing-instruction'
7552 * | 'node'
7553 *
7554 * Returns 1 if true 0 otherwise
7555 */
7556int
7557xmlXPathIsNodeType(const xmlChar *name) {
7558 if (name == NULL)
7559 return(0);
7560
Daniel Veillard1971ee22002-01-31 20:29:19 +00007561 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007562 return(1);
7563 if (xmlStrEqual(name, BAD_CAST "text"))
7564 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007565 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007566 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007567 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007568 return(1);
7569 return(0);
7570}
7571
7572/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007573 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007574 * @ctxt: the XPath Parser context
7575 *
7576 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7577 * [17] Argument ::= Expr
7578 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007579 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007580 * pushed on the stack
7581 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007582static void
7583xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007584 xmlChar *name;
7585 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007586 int nbargs = 0;
7587
7588 name = xmlXPathParseQName(ctxt, &prefix);
7589 if (name == NULL) {
7590 XP_ERROR(XPATH_EXPR_ERROR);
7591 }
7592 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007593#ifdef DEBUG_EXPR
7594 if (prefix == NULL)
7595 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7596 name);
7597 else
7598 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7599 prefix, name);
7600#endif
7601
Owen Taylor3473f882001-02-23 17:55:21 +00007602 if (CUR != '(') {
7603 XP_ERROR(XPATH_EXPR_ERROR);
7604 }
7605 NEXT;
7606 SKIP_BLANKS;
7607
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007608 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007609 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007610 int op1 = ctxt->comp->last;
7611 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007612 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007613 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007614 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007615 nbargs++;
7616 if (CUR == ')') break;
7617 if (CUR != ',') {
7618 XP_ERROR(XPATH_EXPR_ERROR);
7619 }
7620 NEXT;
7621 SKIP_BLANKS;
7622 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007623 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7624 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007625 NEXT;
7626 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007627}
7628
7629/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007630 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007631 * @ctxt: the XPath Parser context
7632 *
7633 * [15] PrimaryExpr ::= VariableReference
7634 * | '(' Expr ')'
7635 * | Literal
7636 * | Number
7637 * | FunctionCall
7638 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007639 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007640 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007641static void
7642xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007643 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007644 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007645 else if (CUR == '(') {
7646 NEXT;
7647 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007648 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007649 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007650 if (CUR != ')') {
7651 XP_ERROR(XPATH_EXPR_ERROR);
7652 }
7653 NEXT;
7654 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007655 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007656 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007657 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007658 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007659 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007660 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007661 }
7662 SKIP_BLANKS;
7663}
7664
7665/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007666 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007667 * @ctxt: the XPath Parser context
7668 *
7669 * [20] FilterExpr ::= PrimaryExpr
7670 * | FilterExpr Predicate
7671 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007672 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007673 * Square brackets are used to filter expressions in the same way that
7674 * they are used in location paths. It is an error if the expression to
7675 * be filtered does not evaluate to a node-set. The context node list
7676 * used for evaluating the expression in square brackets is the node-set
7677 * to be filtered listed in document order.
7678 */
7679
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007680static void
7681xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7682 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007683 CHECK_ERROR;
7684 SKIP_BLANKS;
7685
7686 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007687 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007688 SKIP_BLANKS;
7689 }
7690
7691
7692}
7693
7694/**
7695 * xmlXPathScanName:
7696 * @ctxt: the XPath Parser context
7697 *
7698 * Trickery: parse an XML name but without consuming the input flow
7699 * Needed to avoid insanity in the parser state.
7700 *
7701 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7702 * CombiningChar | Extender
7703 *
7704 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7705 *
7706 * [6] Names ::= Name (S Name)*
7707 *
7708 * Returns the Name parsed or NULL
7709 */
7710
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007711static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007712xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7713 xmlChar buf[XML_MAX_NAMELEN];
7714 int len = 0;
7715
7716 SKIP_BLANKS;
7717 if (!IS_LETTER(CUR) && (CUR != '_') &&
7718 (CUR != ':')) {
7719 return(NULL);
7720 }
7721
7722 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7723 (NXT(len) == '.') || (NXT(len) == '-') ||
7724 (NXT(len) == '_') || (NXT(len) == ':') ||
7725 (IS_COMBINING(NXT(len))) ||
7726 (IS_EXTENDER(NXT(len)))) {
7727 buf[len] = NXT(len);
7728 len++;
7729 if (len >= XML_MAX_NAMELEN) {
7730 xmlGenericError(xmlGenericErrorContext,
7731 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7732 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7733 (NXT(len) == '.') || (NXT(len) == '-') ||
7734 (NXT(len) == '_') || (NXT(len) == ':') ||
7735 (IS_COMBINING(NXT(len))) ||
7736 (IS_EXTENDER(NXT(len))))
7737 len++;
7738 break;
7739 }
7740 }
7741 return(xmlStrndup(buf, len));
7742}
7743
7744/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007745 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007746 * @ctxt: the XPath Parser context
7747 *
7748 * [19] PathExpr ::= LocationPath
7749 * | FilterExpr
7750 * | FilterExpr '/' RelativeLocationPath
7751 * | FilterExpr '//' RelativeLocationPath
7752 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007753 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007754 * The / operator and // operators combine an arbitrary expression
7755 * and a relative location path. It is an error if the expression
7756 * does not evaluate to a node-set.
7757 * The / operator does composition in the same way as when / is
7758 * used in a location path. As in location paths, // is short for
7759 * /descendant-or-self::node()/.
7760 */
7761
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007762static void
7763xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007764 int lc = 1; /* Should we branch to LocationPath ? */
7765 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7766
7767 SKIP_BLANKS;
7768 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007769 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007770 lc = 0;
7771 } else if (CUR == '*') {
7772 /* relative or absolute location path */
7773 lc = 1;
7774 } else if (CUR == '/') {
7775 /* relative or absolute location path */
7776 lc = 1;
7777 } else if (CUR == '@') {
7778 /* relative abbreviated attribute location path */
7779 lc = 1;
7780 } else if (CUR == '.') {
7781 /* relative abbreviated attribute location path */
7782 lc = 1;
7783 } else {
7784 /*
7785 * Problem is finding if we have a name here whether it's:
7786 * - a nodetype
7787 * - a function call in which case it's followed by '('
7788 * - an axis in which case it's followed by ':'
7789 * - a element name
7790 * We do an a priori analysis here rather than having to
7791 * maintain parsed token content through the recursive function
7792 * calls. This looks uglier but makes the code quite easier to
7793 * read/write/debug.
7794 */
7795 SKIP_BLANKS;
7796 name = xmlXPathScanName(ctxt);
7797 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7798#ifdef DEBUG_STEP
7799 xmlGenericError(xmlGenericErrorContext,
7800 "PathExpr: Axis\n");
7801#endif
7802 lc = 1;
7803 xmlFree(name);
7804 } else if (name != NULL) {
7805 int len =xmlStrlen(name);
7806 int blank = 0;
7807
7808
7809 while (NXT(len) != 0) {
7810 if (NXT(len) == '/') {
7811 /* element name */
7812#ifdef DEBUG_STEP
7813 xmlGenericError(xmlGenericErrorContext,
7814 "PathExpr: AbbrRelLocation\n");
7815#endif
7816 lc = 1;
7817 break;
7818 } else if (IS_BLANK(NXT(len))) {
7819 /* skip to next */
7820 blank = 1;
7821 } else if (NXT(len) == ':') {
7822#ifdef DEBUG_STEP
7823 xmlGenericError(xmlGenericErrorContext,
7824 "PathExpr: AbbrRelLocation\n");
7825#endif
7826 lc = 1;
7827 break;
7828 } else if ((NXT(len) == '(')) {
7829 /* Note Type or Function */
7830 if (xmlXPathIsNodeType(name)) {
7831#ifdef DEBUG_STEP
7832 xmlGenericError(xmlGenericErrorContext,
7833 "PathExpr: Type search\n");
7834#endif
7835 lc = 1;
7836 } else {
7837#ifdef DEBUG_STEP
7838 xmlGenericError(xmlGenericErrorContext,
7839 "PathExpr: function call\n");
7840#endif
7841 lc = 0;
7842 }
7843 break;
7844 } else if ((NXT(len) == '[')) {
7845 /* element name */
7846#ifdef DEBUG_STEP
7847 xmlGenericError(xmlGenericErrorContext,
7848 "PathExpr: AbbrRelLocation\n");
7849#endif
7850 lc = 1;
7851 break;
7852 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7853 (NXT(len) == '=')) {
7854 lc = 1;
7855 break;
7856 } else {
7857 lc = 1;
7858 break;
7859 }
7860 len++;
7861 }
7862 if (NXT(len) == 0) {
7863#ifdef DEBUG_STEP
7864 xmlGenericError(xmlGenericErrorContext,
7865 "PathExpr: AbbrRelLocation\n");
7866#endif
7867 /* element name */
7868 lc = 1;
7869 }
7870 xmlFree(name);
7871 } else {
7872 /* make sure all cases are covered explicitely */
7873 XP_ERROR(XPATH_EXPR_ERROR);
7874 }
7875 }
7876
7877 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007878 if (CUR == '/') {
7879 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7880 } else {
7881 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007882 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007883 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007884 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007885 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007886 CHECK_ERROR;
7887 if ((CUR == '/') && (NXT(1) == '/')) {
7888 SKIP(2);
7889 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007890
7891 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7892 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7893 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7894
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007895 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007896 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007897 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007898 }
7899 }
7900 SKIP_BLANKS;
7901}
7902
7903/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007904 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007905 * @ctxt: the XPath Parser context
7906 *
7907 * [18] UnionExpr ::= PathExpr
7908 * | UnionExpr '|' PathExpr
7909 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007910 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007911 */
7912
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007913static void
7914xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7915 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007916 CHECK_ERROR;
7917 SKIP_BLANKS;
7918 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007919 int op1 = ctxt->comp->last;
7920 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007921
7922 NEXT;
7923 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007924 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007925
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007926 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7927
Owen Taylor3473f882001-02-23 17:55:21 +00007928 SKIP_BLANKS;
7929 }
Owen Taylor3473f882001-02-23 17:55:21 +00007930}
7931
7932/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007933 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007934 * @ctxt: the XPath Parser context
7935 *
7936 * [27] UnaryExpr ::= UnionExpr
7937 * | '-' UnaryExpr
7938 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007939 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007940 */
7941
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007942static void
7943xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007944 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007945 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007946
7947 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007948 while (CUR == '-') {
7949 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007950 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007951 NEXT;
7952 SKIP_BLANKS;
7953 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007954
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007955 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007956 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007957 if (found) {
7958 if (minus)
7959 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7960 else
7961 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007962 }
7963}
7964
7965/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007966 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007967 * @ctxt: the XPath Parser context
7968 *
7969 * [26] MultiplicativeExpr ::= UnaryExpr
7970 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7971 * | MultiplicativeExpr 'div' UnaryExpr
7972 * | MultiplicativeExpr 'mod' UnaryExpr
7973 * [34] MultiplyOperator ::= '*'
7974 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007975 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007976 */
7977
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007978static void
7979xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7980 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007981 CHECK_ERROR;
7982 SKIP_BLANKS;
7983 while ((CUR == '*') ||
7984 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7985 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7986 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007987 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007988
7989 if (CUR == '*') {
7990 op = 0;
7991 NEXT;
7992 } else if (CUR == 'd') {
7993 op = 1;
7994 SKIP(3);
7995 } else if (CUR == 'm') {
7996 op = 2;
7997 SKIP(3);
7998 }
7999 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008000 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008001 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008002 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008003 SKIP_BLANKS;
8004 }
8005}
8006
8007/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008008 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008009 * @ctxt: the XPath Parser context
8010 *
8011 * [25] AdditiveExpr ::= MultiplicativeExpr
8012 * | AdditiveExpr '+' MultiplicativeExpr
8013 * | AdditiveExpr '-' MultiplicativeExpr
8014 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008015 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008016 */
8017
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008018static void
8019xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008020
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008021 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008022 CHECK_ERROR;
8023 SKIP_BLANKS;
8024 while ((CUR == '+') || (CUR == '-')) {
8025 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008026 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008027
8028 if (CUR == '+') plus = 1;
8029 else plus = 0;
8030 NEXT;
8031 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008032 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008033 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008034 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008035 SKIP_BLANKS;
8036 }
8037}
8038
8039/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008040 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008041 * @ctxt: the XPath Parser context
8042 *
8043 * [24] RelationalExpr ::= AdditiveExpr
8044 * | RelationalExpr '<' AdditiveExpr
8045 * | RelationalExpr '>' AdditiveExpr
8046 * | RelationalExpr '<=' AdditiveExpr
8047 * | RelationalExpr '>=' AdditiveExpr
8048 *
8049 * A <= B > C is allowed ? Answer from James, yes with
8050 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8051 * which is basically what got implemented.
8052 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008053 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008054 * on the stack
8055 */
8056
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008057static void
8058xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8059 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008060 CHECK_ERROR;
8061 SKIP_BLANKS;
8062 while ((CUR == '<') ||
8063 (CUR == '>') ||
8064 ((CUR == '<') && (NXT(1) == '=')) ||
8065 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008066 int inf, strict;
8067 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008068
8069 if (CUR == '<') inf = 1;
8070 else inf = 0;
8071 if (NXT(1) == '=') strict = 0;
8072 else strict = 1;
8073 NEXT;
8074 if (!strict) NEXT;
8075 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008076 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008077 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008078 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008079 SKIP_BLANKS;
8080 }
8081}
8082
8083/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008084 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008085 * @ctxt: the XPath Parser context
8086 *
8087 * [23] EqualityExpr ::= RelationalExpr
8088 * | EqualityExpr '=' RelationalExpr
8089 * | EqualityExpr '!=' RelationalExpr
8090 *
8091 * A != B != C is allowed ? Answer from James, yes with
8092 * (RelationalExpr = RelationalExpr) = RelationalExpr
8093 * (RelationalExpr != RelationalExpr) != RelationalExpr
8094 * which is basically what got implemented.
8095 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008096 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008097 *
8098 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008099static void
8100xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8101 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008102 CHECK_ERROR;
8103 SKIP_BLANKS;
8104 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008105 int eq;
8106 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008107
8108 if (CUR == '=') eq = 1;
8109 else eq = 0;
8110 NEXT;
8111 if (!eq) NEXT;
8112 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008113 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008114 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008115 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008116 SKIP_BLANKS;
8117 }
8118}
8119
8120/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008121 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008122 * @ctxt: the XPath Parser context
8123 *
8124 * [22] AndExpr ::= EqualityExpr
8125 * | AndExpr 'and' EqualityExpr
8126 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008127 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008128 *
8129 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008130static void
8131xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8132 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008133 CHECK_ERROR;
8134 SKIP_BLANKS;
8135 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008136 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008137 SKIP(3);
8138 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008139 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008140 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008141 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008142 SKIP_BLANKS;
8143 }
8144}
8145
8146/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008147 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008148 * @ctxt: the XPath Parser context
8149 *
8150 * [14] Expr ::= OrExpr
8151 * [21] OrExpr ::= AndExpr
8152 * | OrExpr 'or' AndExpr
8153 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008154 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008155 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008156static void
8157xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8158 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008159 CHECK_ERROR;
8160 SKIP_BLANKS;
8161 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008162 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008163 SKIP(2);
8164 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008165 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008166 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008167 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8168 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008169 SKIP_BLANKS;
8170 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008171 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8172 /* more ops could be optimized too */
8173 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8174 }
Owen Taylor3473f882001-02-23 17:55:21 +00008175}
8176
8177/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008178 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008179 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008180 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008181 *
8182 * [8] Predicate ::= '[' PredicateExpr ']'
8183 * [9] PredicateExpr ::= Expr
8184 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008185 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008186 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008187static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008188xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008189 int op1 = ctxt->comp->last;
8190
8191 SKIP_BLANKS;
8192 if (CUR != '[') {
8193 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8194 }
8195 NEXT;
8196 SKIP_BLANKS;
8197
8198 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008199 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008200 CHECK_ERROR;
8201
8202 if (CUR != ']') {
8203 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8204 }
8205
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008206 if (filter)
8207 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8208 else
8209 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008210
8211 NEXT;
8212 SKIP_BLANKS;
8213}
8214
8215/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008216 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008217 * @ctxt: the XPath Parser context
8218 * @test: pointer to a xmlXPathTestVal
8219 * @type: pointer to a xmlXPathTypeVal
8220 * @prefix: placeholder for a possible name prefix
8221 *
8222 * [7] NodeTest ::= NameTest
8223 * | NodeType '(' ')'
8224 * | 'processing-instruction' '(' Literal ')'
8225 *
8226 * [37] NameTest ::= '*'
8227 * | NCName ':' '*'
8228 * | QName
8229 * [38] NodeType ::= 'comment'
8230 * | 'text'
8231 * | 'processing-instruction'
8232 * | 'node'
8233 *
8234 * Returns the name found and update @test, @type and @prefix appropriately
8235 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008236static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008237xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8238 xmlXPathTypeVal *type, const xmlChar **prefix,
8239 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008240 int blanks;
8241
8242 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8243 STRANGE;
8244 return(NULL);
8245 }
8246 *type = 0;
8247 *test = 0;
8248 *prefix = NULL;
8249 SKIP_BLANKS;
8250
8251 if ((name == NULL) && (CUR == '*')) {
8252 /*
8253 * All elements
8254 */
8255 NEXT;
8256 *test = NODE_TEST_ALL;
8257 return(NULL);
8258 }
8259
8260 if (name == NULL)
8261 name = xmlXPathParseNCName(ctxt);
8262 if (name == NULL) {
8263 XP_ERROR0(XPATH_EXPR_ERROR);
8264 }
8265
8266 blanks = IS_BLANK(CUR);
8267 SKIP_BLANKS;
8268 if (CUR == '(') {
8269 NEXT;
8270 /*
8271 * NodeType or PI search
8272 */
8273 if (xmlStrEqual(name, BAD_CAST "comment"))
8274 *type = NODE_TYPE_COMMENT;
8275 else if (xmlStrEqual(name, BAD_CAST "node"))
8276 *type = NODE_TYPE_NODE;
8277 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8278 *type = NODE_TYPE_PI;
8279 else if (xmlStrEqual(name, BAD_CAST "text"))
8280 *type = NODE_TYPE_TEXT;
8281 else {
8282 if (name != NULL)
8283 xmlFree(name);
8284 XP_ERROR0(XPATH_EXPR_ERROR);
8285 }
8286
8287 *test = NODE_TEST_TYPE;
8288
8289 SKIP_BLANKS;
8290 if (*type == NODE_TYPE_PI) {
8291 /*
8292 * Specific case: search a PI by name.
8293 */
Owen Taylor3473f882001-02-23 17:55:21 +00008294 if (name != NULL)
8295 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008296 name = NULL;
8297 if (CUR != ')') {
8298 name = xmlXPathParseLiteral(ctxt);
8299 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008300 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008301 SKIP_BLANKS;
8302 }
Owen Taylor3473f882001-02-23 17:55:21 +00008303 }
8304 if (CUR != ')') {
8305 if (name != NULL)
8306 xmlFree(name);
8307 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8308 }
8309 NEXT;
8310 return(name);
8311 }
8312 *test = NODE_TEST_NAME;
8313 if ((!blanks) && (CUR == ':')) {
8314 NEXT;
8315
8316 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008317 * Since currently the parser context don't have a
8318 * namespace list associated:
8319 * The namespace name for this prefix can be computed
8320 * only at evaluation time. The compilation is done
8321 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008322 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008323#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008324 *prefix = xmlXPathNsLookup(ctxt->context, name);
8325 if (name != NULL)
8326 xmlFree(name);
8327 if (*prefix == NULL) {
8328 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8329 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008330#else
8331 *prefix = name;
8332#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008333
8334 if (CUR == '*') {
8335 /*
8336 * All elements
8337 */
8338 NEXT;
8339 *test = NODE_TEST_ALL;
8340 return(NULL);
8341 }
8342
8343 name = xmlXPathParseNCName(ctxt);
8344 if (name == NULL) {
8345 XP_ERROR0(XPATH_EXPR_ERROR);
8346 }
8347 }
8348 return(name);
8349}
8350
8351/**
8352 * xmlXPathIsAxisName:
8353 * @name: a preparsed name token
8354 *
8355 * [6] AxisName ::= 'ancestor'
8356 * | 'ancestor-or-self'
8357 * | 'attribute'
8358 * | 'child'
8359 * | 'descendant'
8360 * | 'descendant-or-self'
8361 * | 'following'
8362 * | 'following-sibling'
8363 * | 'namespace'
8364 * | 'parent'
8365 * | 'preceding'
8366 * | 'preceding-sibling'
8367 * | 'self'
8368 *
8369 * Returns the axis or 0
8370 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008371static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008372xmlXPathIsAxisName(const xmlChar *name) {
8373 xmlXPathAxisVal ret = 0;
8374 switch (name[0]) {
8375 case 'a':
8376 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8377 ret = AXIS_ANCESTOR;
8378 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8379 ret = AXIS_ANCESTOR_OR_SELF;
8380 if (xmlStrEqual(name, BAD_CAST "attribute"))
8381 ret = AXIS_ATTRIBUTE;
8382 break;
8383 case 'c':
8384 if (xmlStrEqual(name, BAD_CAST "child"))
8385 ret = AXIS_CHILD;
8386 break;
8387 case 'd':
8388 if (xmlStrEqual(name, BAD_CAST "descendant"))
8389 ret = AXIS_DESCENDANT;
8390 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8391 ret = AXIS_DESCENDANT_OR_SELF;
8392 break;
8393 case 'f':
8394 if (xmlStrEqual(name, BAD_CAST "following"))
8395 ret = AXIS_FOLLOWING;
8396 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8397 ret = AXIS_FOLLOWING_SIBLING;
8398 break;
8399 case 'n':
8400 if (xmlStrEqual(name, BAD_CAST "namespace"))
8401 ret = AXIS_NAMESPACE;
8402 break;
8403 case 'p':
8404 if (xmlStrEqual(name, BAD_CAST "parent"))
8405 ret = AXIS_PARENT;
8406 if (xmlStrEqual(name, BAD_CAST "preceding"))
8407 ret = AXIS_PRECEDING;
8408 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8409 ret = AXIS_PRECEDING_SIBLING;
8410 break;
8411 case 's':
8412 if (xmlStrEqual(name, BAD_CAST "self"))
8413 ret = AXIS_SELF;
8414 break;
8415 }
8416 return(ret);
8417}
8418
8419/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008420 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008421 * @ctxt: the XPath Parser context
8422 *
8423 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8424 * | AbbreviatedStep
8425 *
8426 * [12] AbbreviatedStep ::= '.' | '..'
8427 *
8428 * [5] AxisSpecifier ::= AxisName '::'
8429 * | AbbreviatedAxisSpecifier
8430 *
8431 * [13] AbbreviatedAxisSpecifier ::= '@'?
8432 *
8433 * Modified for XPtr range support as:
8434 *
8435 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8436 * | AbbreviatedStep
8437 * | 'range-to' '(' Expr ')' Predicate*
8438 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008439 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008440 * A location step of . is short for self::node(). This is
8441 * particularly useful in conjunction with //. For example, the
8442 * location path .//para is short for
8443 * self::node()/descendant-or-self::node()/child::para
8444 * and so will select all para descendant elements of the context
8445 * node.
8446 * Similarly, a location step of .. is short for parent::node().
8447 * For example, ../title is short for parent::node()/child::title
8448 * and so will select the title children of the parent of the context
8449 * node.
8450 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008451static void
8452xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008453#ifdef LIBXML_XPTR_ENABLED
8454 int rangeto = 0;
8455 int op2 = -1;
8456#endif
8457
Owen Taylor3473f882001-02-23 17:55:21 +00008458 SKIP_BLANKS;
8459 if ((CUR == '.') && (NXT(1) == '.')) {
8460 SKIP(2);
8461 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008462 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8463 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008464 } else if (CUR == '.') {
8465 NEXT;
8466 SKIP_BLANKS;
8467 } else {
8468 xmlChar *name = NULL;
8469 const xmlChar *prefix = NULL;
8470 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008471 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008472 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008473 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008474
8475 /*
8476 * The modification needed for XPointer change to the production
8477 */
8478#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008479 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008480 name = xmlXPathParseNCName(ctxt);
8481 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008482 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008483 xmlFree(name);
8484 SKIP_BLANKS;
8485 if (CUR != '(') {
8486 XP_ERROR(XPATH_EXPR_ERROR);
8487 }
8488 NEXT;
8489 SKIP_BLANKS;
8490
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008491 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008492 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008493 CHECK_ERROR;
8494
8495 SKIP_BLANKS;
8496 if (CUR != ')') {
8497 XP_ERROR(XPATH_EXPR_ERROR);
8498 }
8499 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008500 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008501 goto eval_predicates;
8502 }
8503 }
8504#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008505 if (CUR == '*') {
8506 axis = AXIS_CHILD;
8507 } else {
8508 if (name == NULL)
8509 name = xmlXPathParseNCName(ctxt);
8510 if (name != NULL) {
8511 axis = xmlXPathIsAxisName(name);
8512 if (axis != 0) {
8513 SKIP_BLANKS;
8514 if ((CUR == ':') && (NXT(1) == ':')) {
8515 SKIP(2);
8516 xmlFree(name);
8517 name = NULL;
8518 } else {
8519 /* an element name can conflict with an axis one :-\ */
8520 axis = AXIS_CHILD;
8521 }
Owen Taylor3473f882001-02-23 17:55:21 +00008522 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008523 axis = AXIS_CHILD;
8524 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008525 } else if (CUR == '@') {
8526 NEXT;
8527 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008528 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008529 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008530 }
Owen Taylor3473f882001-02-23 17:55:21 +00008531 }
8532
8533 CHECK_ERROR;
8534
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008535 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008536 if (test == 0)
8537 return;
8538
8539#ifdef DEBUG_STEP
8540 xmlGenericError(xmlGenericErrorContext,
8541 "Basis : computing new set\n");
8542#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008543
Owen Taylor3473f882001-02-23 17:55:21 +00008544#ifdef DEBUG_STEP
8545 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008546 if (ctxt->value == NULL)
8547 xmlGenericError(xmlGenericErrorContext, "no value\n");
8548 else if (ctxt->value->nodesetval == NULL)
8549 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8550 else
8551 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008552#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008553
8554eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008555 op1 = ctxt->comp->last;
8556 ctxt->comp->last = -1;
8557
Owen Taylor3473f882001-02-23 17:55:21 +00008558 SKIP_BLANKS;
8559 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008560 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008561 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008562
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008563#ifdef LIBXML_XPTR_ENABLED
8564 if (rangeto) {
8565 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8566 } else
8567#endif
8568 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8569 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008570
Owen Taylor3473f882001-02-23 17:55:21 +00008571 }
8572#ifdef DEBUG_STEP
8573 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008574 if (ctxt->value == NULL)
8575 xmlGenericError(xmlGenericErrorContext, "no value\n");
8576 else if (ctxt->value->nodesetval == NULL)
8577 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8578 else
8579 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8580 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008581#endif
8582}
8583
8584/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008585 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008586 * @ctxt: the XPath Parser context
8587 *
8588 * [3] RelativeLocationPath ::= Step
8589 * | RelativeLocationPath '/' Step
8590 * | AbbreviatedRelativeLocationPath
8591 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8592 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008593 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008594 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008595static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008596xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008597(xmlXPathParserContextPtr ctxt) {
8598 SKIP_BLANKS;
8599 if ((CUR == '/') && (NXT(1) == '/')) {
8600 SKIP(2);
8601 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008602 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8603 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008604 } else if (CUR == '/') {
8605 NEXT;
8606 SKIP_BLANKS;
8607 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008608 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008609 SKIP_BLANKS;
8610 while (CUR == '/') {
8611 if ((CUR == '/') && (NXT(1) == '/')) {
8612 SKIP(2);
8613 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008614 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008615 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008616 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008617 } else if (CUR == '/') {
8618 NEXT;
8619 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008620 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008621 }
8622 SKIP_BLANKS;
8623 }
8624}
8625
8626/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008627 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008628 * @ctxt: the XPath Parser context
8629 *
8630 * [1] LocationPath ::= RelativeLocationPath
8631 * | AbsoluteLocationPath
8632 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8633 * | AbbreviatedAbsoluteLocationPath
8634 * [10] AbbreviatedAbsoluteLocationPath ::=
8635 * '//' RelativeLocationPath
8636 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008637 * Compile a location path
8638 *
Owen Taylor3473f882001-02-23 17:55:21 +00008639 * // is short for /descendant-or-self::node()/. For example,
8640 * //para is short for /descendant-or-self::node()/child::para and
8641 * so will select any para element in the document (even a para element
8642 * that is a document element will be selected by //para since the
8643 * document element node is a child of the root node); div//para is
8644 * short for div/descendant-or-self::node()/child::para and so will
8645 * select all para descendants of div children.
8646 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008647static void
8648xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008649 SKIP_BLANKS;
8650 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008651 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008652 } else {
8653 while (CUR == '/') {
8654 if ((CUR == '/') && (NXT(1) == '/')) {
8655 SKIP(2);
8656 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008657 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8658 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008659 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008660 } else if (CUR == '/') {
8661 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008662 SKIP_BLANKS;
8663 if ((CUR != 0 ) &&
8664 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8665 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008666 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008667 }
8668 }
8669 }
8670}
8671
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008672/************************************************************************
8673 * *
8674 * XPath precompiled expression evaluation *
8675 * *
8676 ************************************************************************/
8677
Daniel Veillardf06307e2001-07-03 10:35:50 +00008678static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008679xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8680
8681/**
8682 * xmlXPathNodeCollectAndTest:
8683 * @ctxt: the XPath Parser context
8684 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008685 * @first: pointer to the first element in document order
8686 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008687 *
8688 * This is the function implementing a step: based on the current list
8689 * of nodes, it builds up a new list, looking at all nodes under that
8690 * axis and selecting them it also do the predicate filtering
8691 *
8692 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008693 *
8694 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008695 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008696static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008697xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008698 xmlXPathStepOpPtr op,
8699 xmlNodePtr * first, xmlNodePtr * last)
8700{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008701 xmlXPathAxisVal axis = op->value;
8702 xmlXPathTestVal test = op->value2;
8703 xmlXPathTypeVal type = op->value3;
8704 const xmlChar *prefix = op->value4;
8705 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008706 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008707
8708#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008709 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008710#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008711 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008712 xmlNodeSetPtr ret, list;
8713 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008714 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008715 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008716 xmlNodePtr cur = NULL;
8717 xmlXPathObjectPtr obj;
8718 xmlNodeSetPtr nodelist;
8719 xmlNodePtr tmp;
8720
Daniel Veillardf06307e2001-07-03 10:35:50 +00008721 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008722 obj = valuePop(ctxt);
8723 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008724 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008725 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008726 URI = xmlXPathNsLookup(ctxt->context, prefix);
8727 if (URI == NULL)
8728 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008729 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008730#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008731 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008732#endif
8733 switch (axis) {
8734 case AXIS_ANCESTOR:
8735#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008736 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008737#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008738 first = NULL;
8739 next = xmlXPathNextAncestor;
8740 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008741 case AXIS_ANCESTOR_OR_SELF:
8742#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008743 xmlGenericError(xmlGenericErrorContext,
8744 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008745#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008746 first = NULL;
8747 next = xmlXPathNextAncestorOrSelf;
8748 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008749 case AXIS_ATTRIBUTE:
8750#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008751 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008752#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008753 first = NULL;
8754 last = NULL;
8755 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008756 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008757 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008758 case AXIS_CHILD:
8759#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008760 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008761#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008762 last = NULL;
8763 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008764 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008765 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008766 case AXIS_DESCENDANT:
8767#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008768 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008769#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008770 last = NULL;
8771 next = xmlXPathNextDescendant;
8772 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008773 case AXIS_DESCENDANT_OR_SELF:
8774#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008775 xmlGenericError(xmlGenericErrorContext,
8776 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008777#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008778 last = NULL;
8779 next = xmlXPathNextDescendantOrSelf;
8780 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008781 case AXIS_FOLLOWING:
8782#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008783 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008784#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008785 last = NULL;
8786 next = xmlXPathNextFollowing;
8787 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008788 case AXIS_FOLLOWING_SIBLING:
8789#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008790 xmlGenericError(xmlGenericErrorContext,
8791 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008792#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008793 last = NULL;
8794 next = xmlXPathNextFollowingSibling;
8795 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008796 case AXIS_NAMESPACE:
8797#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008798 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008799#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008800 first = NULL;
8801 last = NULL;
8802 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008803 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008804 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008805 case AXIS_PARENT:
8806#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008807 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008808#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008809 first = NULL;
8810 next = xmlXPathNextParent;
8811 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008812 case AXIS_PRECEDING:
8813#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008814 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008815#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008816 first = NULL;
8817 next = xmlXPathNextPrecedingInternal;
8818 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008819 case AXIS_PRECEDING_SIBLING:
8820#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008821 xmlGenericError(xmlGenericErrorContext,
8822 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008823#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008824 first = NULL;
8825 next = xmlXPathNextPrecedingSibling;
8826 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008827 case AXIS_SELF:
8828#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008829 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008830#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008831 first = NULL;
8832 last = NULL;
8833 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008834 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008835 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008836 }
8837 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008838 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008839
8840 nodelist = obj->nodesetval;
8841 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008842 xmlXPathFreeObject(obj);
8843 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8844 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008845 }
8846 addNode = xmlXPathNodeSetAddUnique;
8847 ret = NULL;
8848#ifdef DEBUG_STEP
8849 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008850 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008851 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008852 case NODE_TEST_NONE:
8853 xmlGenericError(xmlGenericErrorContext,
8854 " searching for none !!!\n");
8855 break;
8856 case NODE_TEST_TYPE:
8857 xmlGenericError(xmlGenericErrorContext,
8858 " searching for type %d\n", type);
8859 break;
8860 case NODE_TEST_PI:
8861 xmlGenericError(xmlGenericErrorContext,
8862 " searching for PI !!!\n");
8863 break;
8864 case NODE_TEST_ALL:
8865 xmlGenericError(xmlGenericErrorContext,
8866 " searching for *\n");
8867 break;
8868 case NODE_TEST_NS:
8869 xmlGenericError(xmlGenericErrorContext,
8870 " searching for namespace %s\n",
8871 prefix);
8872 break;
8873 case NODE_TEST_NAME:
8874 xmlGenericError(xmlGenericErrorContext,
8875 " searching for name %s\n", name);
8876 if (prefix != NULL)
8877 xmlGenericError(xmlGenericErrorContext,
8878 " with namespace %s\n", prefix);
8879 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008880 }
8881 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8882#endif
8883 /*
8884 * 2.3 Node Tests
8885 * - For the attribute axis, the principal node type is attribute.
8886 * - For the namespace axis, the principal node type is namespace.
8887 * - For other axes, the principal node type is element.
8888 *
8889 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008890 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008891 * select all element children of the context node
8892 */
8893 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008894 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008895 ctxt->context->node = nodelist->nodeTab[i];
8896
Daniel Veillardf06307e2001-07-03 10:35:50 +00008897 cur = NULL;
8898 list = xmlXPathNodeSetCreate(NULL);
8899 do {
8900 cur = next(ctxt, cur);
8901 if (cur == NULL)
8902 break;
8903 if ((first != NULL) && (*first == cur))
8904 break;
8905 if (((t % 256) == 0) &&
8906 (first != NULL) && (*first != NULL) &&
8907 (xmlXPathCmpNodes(*first, cur) >= 0))
8908 break;
8909 if ((last != NULL) && (*last == cur))
8910 break;
8911 if (((t % 256) == 0) &&
8912 (last != NULL) && (*last != NULL) &&
8913 (xmlXPathCmpNodes(cur, *last) >= 0))
8914 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008915 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008916#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008917 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8918#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008919 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008920 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008921 ctxt->context->node = tmp;
8922 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008924 if ((cur->type == type) ||
8925 ((type == NODE_TYPE_NODE) &&
8926 ((cur->type == XML_DOCUMENT_NODE) ||
8927 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8928 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00008929 (cur->type == XML_NAMESPACE_DECL) ||
8930 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00008931 (cur->type == XML_PI_NODE) ||
8932 (cur->type == XML_COMMENT_NODE) ||
8933 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008934 (cur->type == XML_TEXT_NODE))) ||
8935 ((type == NODE_TYPE_TEXT) &&
8936 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008937#ifdef DEBUG_STEP
8938 n++;
8939#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008940 addNode(list, cur);
8941 }
8942 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008943 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008944 if (cur->type == XML_PI_NODE) {
8945 if ((name != NULL) &&
8946 (!xmlStrEqual(name, cur->name)))
8947 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008948#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008949 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008950#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008951 addNode(list, cur);
8952 }
8953 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008954 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 if (axis == AXIS_ATTRIBUTE) {
8956 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008957#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008958 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008959#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008960 addNode(list, cur);
8961 }
8962 } else if (axis == AXIS_NAMESPACE) {
8963 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008964#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008965 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008966#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008967 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8968 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 }
8970 } else {
8971 if (cur->type == XML_ELEMENT_NODE) {
8972 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008975#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976 addNode(list, cur);
8977 } else if ((cur->ns != NULL) &&
8978 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008979#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008981#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982 addNode(list, cur);
8983 }
8984 }
8985 }
8986 break;
8987 case NODE_TEST_NS:{
8988 TODO;
8989 break;
8990 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008991 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992 switch (cur->type) {
8993 case XML_ELEMENT_NODE:
8994 if (xmlStrEqual(name, cur->name)) {
8995 if (prefix == NULL) {
8996 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008997#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008998 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008999#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009000 addNode(list, cur);
9001 }
9002 } else {
9003 if ((cur->ns != NULL) &&
9004 (xmlStrEqual(URI,
9005 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009006#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009007 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009008#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009009 addNode(list, cur);
9010 }
9011 }
9012 }
9013 break;
9014 case XML_ATTRIBUTE_NODE:{
9015 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009016
Daniel Veillardf06307e2001-07-03 10:35:50 +00009017 if (xmlStrEqual(name, attr->name)) {
9018 if (prefix == NULL) {
9019 if ((attr->ns == NULL) ||
9020 (attr->ns->prefix == NULL)) {
9021#ifdef DEBUG_STEP
9022 n++;
9023#endif
9024 addNode(list,
9025 (xmlNodePtr) attr);
9026 }
9027 } else {
9028 if ((attr->ns != NULL) &&
9029 (xmlStrEqual(URI,
9030 attr->ns->
9031 href))) {
9032#ifdef DEBUG_STEP
9033 n++;
9034#endif
9035 addNode(list,
9036 (xmlNodePtr) attr);
9037 }
9038 }
9039 }
9040 break;
9041 }
9042 case XML_NAMESPACE_DECL:
9043 if (cur->type == XML_NAMESPACE_DECL) {
9044 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009045
Daniel Veillardf06307e2001-07-03 10:35:50 +00009046 if ((ns->prefix != NULL) && (name != NULL)
9047 && (xmlStrEqual(ns->prefix, name))) {
9048#ifdef DEBUG_STEP
9049 n++;
9050#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009051 xmlXPathNodeSetAddNs(list,
9052 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 }
9054 }
9055 break;
9056 default:
9057 break;
9058 }
9059 break;
9060 break;
9061 }
9062 } while (cur != NULL);
9063
9064 /*
9065 * If there is some predicate filtering do it now
9066 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009067 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009068 xmlXPathObjectPtr obj2;
9069
9070 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9071 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9072 CHECK_TYPE0(XPATH_NODESET);
9073 obj2 = valuePop(ctxt);
9074 list = obj2->nodesetval;
9075 obj2->nodesetval = NULL;
9076 xmlXPathFreeObject(obj2);
9077 }
9078 if (ret == NULL) {
9079 ret = list;
9080 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009081 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009082 xmlXPathFreeNodeSet(list);
9083 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009084 }
9085 ctxt->context->node = tmp;
9086#ifdef DEBUG_STEP
9087 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009088 "\nExamined %d nodes, found %d nodes at that step\n",
9089 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009090#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009092 if ((obj->boolval) && (obj->user != NULL)) {
9093 ctxt->value->boolval = 1;
9094 ctxt->value->user = obj->user;
9095 obj->user = NULL;
9096 obj->boolval = 0;
9097 }
9098 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099 return(t);
9100}
9101
9102/**
9103 * xmlXPathNodeCollectAndTestNth:
9104 * @ctxt: the XPath Parser context
9105 * @op: the XPath precompiled step operation
9106 * @indx: the index to collect
9107 * @first: pointer to the first element in document order
9108 * @last: pointer to the last element in document order
9109 *
9110 * This is the function implementing a step: based on the current list
9111 * of nodes, it builds up a new list, looking at all nodes under that
9112 * axis and selecting them it also do the predicate filtering
9113 *
9114 * Pushes the new NodeSet resulting from the search.
9115 * Returns the number of node traversed
9116 */
9117static int
9118xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9119 xmlXPathStepOpPtr op, int indx,
9120 xmlNodePtr * first, xmlNodePtr * last)
9121{
9122 xmlXPathAxisVal axis = op->value;
9123 xmlXPathTestVal test = op->value2;
9124 xmlXPathTypeVal type = op->value3;
9125 const xmlChar *prefix = op->value4;
9126 const xmlChar *name = op->value5;
9127 const xmlChar *URI = NULL;
9128 int n = 0, t = 0;
9129
9130 int i;
9131 xmlNodeSetPtr list;
9132 xmlXPathTraversalFunction next = NULL;
9133 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9134 xmlNodePtr cur = NULL;
9135 xmlXPathObjectPtr obj;
9136 xmlNodeSetPtr nodelist;
9137 xmlNodePtr tmp;
9138
9139 CHECK_TYPE0(XPATH_NODESET);
9140 obj = valuePop(ctxt);
9141 addNode = xmlXPathNodeSetAdd;
9142 if (prefix != NULL) {
9143 URI = xmlXPathNsLookup(ctxt->context, prefix);
9144 if (URI == NULL)
9145 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9146 }
9147#ifdef DEBUG_STEP_NTH
9148 xmlGenericError(xmlGenericErrorContext, "new step : ");
9149 if (first != NULL) {
9150 if (*first != NULL)
9151 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9152 (*first)->name);
9153 else
9154 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9155 }
9156 if (last != NULL) {
9157 if (*last != NULL)
9158 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9159 (*last)->name);
9160 else
9161 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9162 }
9163#endif
9164 switch (axis) {
9165 case AXIS_ANCESTOR:
9166#ifdef DEBUG_STEP_NTH
9167 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9168#endif
9169 first = NULL;
9170 next = xmlXPathNextAncestor;
9171 break;
9172 case AXIS_ANCESTOR_OR_SELF:
9173#ifdef DEBUG_STEP_NTH
9174 xmlGenericError(xmlGenericErrorContext,
9175 "axis 'ancestors-or-self' ");
9176#endif
9177 first = NULL;
9178 next = xmlXPathNextAncestorOrSelf;
9179 break;
9180 case AXIS_ATTRIBUTE:
9181#ifdef DEBUG_STEP_NTH
9182 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9183#endif
9184 first = NULL;
9185 last = NULL;
9186 next = xmlXPathNextAttribute;
9187 break;
9188 case AXIS_CHILD:
9189#ifdef DEBUG_STEP_NTH
9190 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9191#endif
9192 last = NULL;
9193 next = xmlXPathNextChild;
9194 break;
9195 case AXIS_DESCENDANT:
9196#ifdef DEBUG_STEP_NTH
9197 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9198#endif
9199 last = NULL;
9200 next = xmlXPathNextDescendant;
9201 break;
9202 case AXIS_DESCENDANT_OR_SELF:
9203#ifdef DEBUG_STEP_NTH
9204 xmlGenericError(xmlGenericErrorContext,
9205 "axis 'descendant-or-self' ");
9206#endif
9207 last = NULL;
9208 next = xmlXPathNextDescendantOrSelf;
9209 break;
9210 case AXIS_FOLLOWING:
9211#ifdef DEBUG_STEP_NTH
9212 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9213#endif
9214 last = NULL;
9215 next = xmlXPathNextFollowing;
9216 break;
9217 case AXIS_FOLLOWING_SIBLING:
9218#ifdef DEBUG_STEP_NTH
9219 xmlGenericError(xmlGenericErrorContext,
9220 "axis 'following-siblings' ");
9221#endif
9222 last = NULL;
9223 next = xmlXPathNextFollowingSibling;
9224 break;
9225 case AXIS_NAMESPACE:
9226#ifdef DEBUG_STEP_NTH
9227 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9228#endif
9229 last = NULL;
9230 first = NULL;
9231 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9232 break;
9233 case AXIS_PARENT:
9234#ifdef DEBUG_STEP_NTH
9235 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9236#endif
9237 first = NULL;
9238 next = xmlXPathNextParent;
9239 break;
9240 case AXIS_PRECEDING:
9241#ifdef DEBUG_STEP_NTH
9242 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9243#endif
9244 first = NULL;
9245 next = xmlXPathNextPrecedingInternal;
9246 break;
9247 case AXIS_PRECEDING_SIBLING:
9248#ifdef DEBUG_STEP_NTH
9249 xmlGenericError(xmlGenericErrorContext,
9250 "axis 'preceding-sibling' ");
9251#endif
9252 first = NULL;
9253 next = xmlXPathNextPrecedingSibling;
9254 break;
9255 case AXIS_SELF:
9256#ifdef DEBUG_STEP_NTH
9257 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9258#endif
9259 first = NULL;
9260 last = NULL;
9261 next = xmlXPathNextSelf;
9262 break;
9263 }
9264 if (next == NULL)
9265 return(0);
9266
9267 nodelist = obj->nodesetval;
9268 if (nodelist == NULL) {
9269 xmlXPathFreeObject(obj);
9270 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9271 return(0);
9272 }
9273 addNode = xmlXPathNodeSetAddUnique;
9274#ifdef DEBUG_STEP_NTH
9275 xmlGenericError(xmlGenericErrorContext,
9276 " context contains %d nodes\n", nodelist->nodeNr);
9277 switch (test) {
9278 case NODE_TEST_NONE:
9279 xmlGenericError(xmlGenericErrorContext,
9280 " searching for none !!!\n");
9281 break;
9282 case NODE_TEST_TYPE:
9283 xmlGenericError(xmlGenericErrorContext,
9284 " searching for type %d\n", type);
9285 break;
9286 case NODE_TEST_PI:
9287 xmlGenericError(xmlGenericErrorContext,
9288 " searching for PI !!!\n");
9289 break;
9290 case NODE_TEST_ALL:
9291 xmlGenericError(xmlGenericErrorContext,
9292 " searching for *\n");
9293 break;
9294 case NODE_TEST_NS:
9295 xmlGenericError(xmlGenericErrorContext,
9296 " searching for namespace %s\n",
9297 prefix);
9298 break;
9299 case NODE_TEST_NAME:
9300 xmlGenericError(xmlGenericErrorContext,
9301 " searching for name %s\n", name);
9302 if (prefix != NULL)
9303 xmlGenericError(xmlGenericErrorContext,
9304 " with namespace %s\n", prefix);
9305 break;
9306 }
9307 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9308#endif
9309 /*
9310 * 2.3 Node Tests
9311 * - For the attribute axis, the principal node type is attribute.
9312 * - For the namespace axis, the principal node type is namespace.
9313 * - For other axes, the principal node type is element.
9314 *
9315 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009316 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009317 * select all element children of the context node
9318 */
9319 tmp = ctxt->context->node;
9320 list = xmlXPathNodeSetCreate(NULL);
9321 for (i = 0; i < nodelist->nodeNr; i++) {
9322 ctxt->context->node = nodelist->nodeTab[i];
9323
9324 cur = NULL;
9325 n = 0;
9326 do {
9327 cur = next(ctxt, cur);
9328 if (cur == NULL)
9329 break;
9330 if ((first != NULL) && (*first == cur))
9331 break;
9332 if (((t % 256) == 0) &&
9333 (first != NULL) && (*first != NULL) &&
9334 (xmlXPathCmpNodes(*first, cur) >= 0))
9335 break;
9336 if ((last != NULL) && (*last == cur))
9337 break;
9338 if (((t % 256) == 0) &&
9339 (last != NULL) && (*last != NULL) &&
9340 (xmlXPathCmpNodes(cur, *last) >= 0))
9341 break;
9342 t++;
9343 switch (test) {
9344 case NODE_TEST_NONE:
9345 ctxt->context->node = tmp;
9346 STRANGE return(0);
9347 case NODE_TEST_TYPE:
9348 if ((cur->type == type) ||
9349 ((type == NODE_TYPE_NODE) &&
9350 ((cur->type == XML_DOCUMENT_NODE) ||
9351 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9352 (cur->type == XML_ELEMENT_NODE) ||
9353 (cur->type == XML_PI_NODE) ||
9354 (cur->type == XML_COMMENT_NODE) ||
9355 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009356 (cur->type == XML_TEXT_NODE))) ||
9357 ((type == NODE_TYPE_TEXT) &&
9358 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009359 n++;
9360 if (n == indx)
9361 addNode(list, cur);
9362 }
9363 break;
9364 case NODE_TEST_PI:
9365 if (cur->type == XML_PI_NODE) {
9366 if ((name != NULL) &&
9367 (!xmlStrEqual(name, cur->name)))
9368 break;
9369 n++;
9370 if (n == indx)
9371 addNode(list, cur);
9372 }
9373 break;
9374 case NODE_TEST_ALL:
9375 if (axis == AXIS_ATTRIBUTE) {
9376 if (cur->type == XML_ATTRIBUTE_NODE) {
9377 n++;
9378 if (n == indx)
9379 addNode(list, cur);
9380 }
9381 } else if (axis == AXIS_NAMESPACE) {
9382 if (cur->type == XML_NAMESPACE_DECL) {
9383 n++;
9384 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009385 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9386 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009387 }
9388 } else {
9389 if (cur->type == XML_ELEMENT_NODE) {
9390 if (prefix == NULL) {
9391 n++;
9392 if (n == indx)
9393 addNode(list, cur);
9394 } else if ((cur->ns != NULL) &&
9395 (xmlStrEqual(URI, cur->ns->href))) {
9396 n++;
9397 if (n == indx)
9398 addNode(list, cur);
9399 }
9400 }
9401 }
9402 break;
9403 case NODE_TEST_NS:{
9404 TODO;
9405 break;
9406 }
9407 case NODE_TEST_NAME:
9408 switch (cur->type) {
9409 case XML_ELEMENT_NODE:
9410 if (xmlStrEqual(name, cur->name)) {
9411 if (prefix == NULL) {
9412 if (cur->ns == NULL) {
9413 n++;
9414 if (n == indx)
9415 addNode(list, cur);
9416 }
9417 } else {
9418 if ((cur->ns != NULL) &&
9419 (xmlStrEqual(URI,
9420 cur->ns->href))) {
9421 n++;
9422 if (n == indx)
9423 addNode(list, cur);
9424 }
9425 }
9426 }
9427 break;
9428 case XML_ATTRIBUTE_NODE:{
9429 xmlAttrPtr attr = (xmlAttrPtr) cur;
9430
9431 if (xmlStrEqual(name, attr->name)) {
9432 if (prefix == NULL) {
9433 if ((attr->ns == NULL) ||
9434 (attr->ns->prefix == NULL)) {
9435 n++;
9436 if (n == indx)
9437 addNode(list, cur);
9438 }
9439 } else {
9440 if ((attr->ns != NULL) &&
9441 (xmlStrEqual(URI,
9442 attr->ns->
9443 href))) {
9444 n++;
9445 if (n == indx)
9446 addNode(list, cur);
9447 }
9448 }
9449 }
9450 break;
9451 }
9452 case XML_NAMESPACE_DECL:
9453 if (cur->type == XML_NAMESPACE_DECL) {
9454 xmlNsPtr ns = (xmlNsPtr) cur;
9455
9456 if ((ns->prefix != NULL) && (name != NULL)
9457 && (xmlStrEqual(ns->prefix, name))) {
9458 n++;
9459 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009460 xmlXPathNodeSetAddNs(list,
9461 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009462 }
9463 }
9464 break;
9465 default:
9466 break;
9467 }
9468 break;
9469 break;
9470 }
9471 } while (n < indx);
9472 }
9473 ctxt->context->node = tmp;
9474#ifdef DEBUG_STEP_NTH
9475 xmlGenericError(xmlGenericErrorContext,
9476 "\nExamined %d nodes, found %d nodes at that step\n",
9477 t, list->nodeNr);
9478#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009479 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009480 if ((obj->boolval) && (obj->user != NULL)) {
9481 ctxt->value->boolval = 1;
9482 ctxt->value->user = obj->user;
9483 obj->user = NULL;
9484 obj->boolval = 0;
9485 }
9486 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009487 return(t);
9488}
9489
9490/**
9491 * xmlXPathCompOpEvalFirst:
9492 * @ctxt: the XPath parser context with the compiled expression
9493 * @op: an XPath compiled operation
9494 * @first: the first elem found so far
9495 *
9496 * Evaluate the Precompiled XPath operation searching only the first
9497 * element in document order
9498 *
9499 * Returns the number of examined objects.
9500 */
9501static int
9502xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9503 xmlXPathStepOpPtr op, xmlNodePtr * first)
9504{
9505 int total = 0, cur;
9506 xmlXPathCompExprPtr comp;
9507 xmlXPathObjectPtr arg1, arg2;
9508
Daniel Veillard556c6682001-10-06 09:59:51 +00009509 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009510 comp = ctxt->comp;
9511 switch (op->op) {
9512 case XPATH_OP_END:
9513 return (0);
9514 case XPATH_OP_UNION:
9515 total =
9516 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9517 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009518 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009519 if ((ctxt->value != NULL)
9520 && (ctxt->value->type == XPATH_NODESET)
9521 && (ctxt->value->nodesetval != NULL)
9522 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9523 /*
9524 * limit tree traversing to first node in the result
9525 */
9526 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9527 *first = ctxt->value->nodesetval->nodeTab[0];
9528 }
9529 cur =
9530 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9531 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009532 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009533 CHECK_TYPE0(XPATH_NODESET);
9534 arg2 = valuePop(ctxt);
9535
9536 CHECK_TYPE0(XPATH_NODESET);
9537 arg1 = valuePop(ctxt);
9538
9539 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9540 arg2->nodesetval);
9541 valuePush(ctxt, arg1);
9542 xmlXPathFreeObject(arg2);
9543 /* optimizer */
9544 if (total > cur)
9545 xmlXPathCompSwap(op);
9546 return (total + cur);
9547 case XPATH_OP_ROOT:
9548 xmlXPathRoot(ctxt);
9549 return (0);
9550 case XPATH_OP_NODE:
9551 if (op->ch1 != -1)
9552 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009553 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009554 if (op->ch2 != -1)
9555 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009556 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009557 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9558 return (total);
9559 case XPATH_OP_RESET:
9560 if (op->ch1 != -1)
9561 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009562 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009563 if (op->ch2 != -1)
9564 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009565 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009566 ctxt->context->node = NULL;
9567 return (total);
9568 case XPATH_OP_COLLECT:{
9569 if (op->ch1 == -1)
9570 return (total);
9571
9572 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009573 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009574
9575 /*
9576 * Optimization for [n] selection where n is a number
9577 */
9578 if ((op->ch2 != -1) &&
9579 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9580 (comp->steps[op->ch2].ch1 == -1) &&
9581 (comp->steps[op->ch2].ch2 != -1) &&
9582 (comp->steps[comp->steps[op->ch2].ch2].op ==
9583 XPATH_OP_VALUE)) {
9584 xmlXPathObjectPtr val;
9585
9586 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9587 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9588 int indx = (int) val->floatval;
9589
9590 if (val->floatval == (float) indx) {
9591 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9592 first, NULL);
9593 return (total);
9594 }
9595 }
9596 }
9597 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9598 return (total);
9599 }
9600 case XPATH_OP_VALUE:
9601 valuePush(ctxt,
9602 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9603 return (0);
9604 case XPATH_OP_SORT:
9605 if (op->ch1 != -1)
9606 total +=
9607 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9608 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009609 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009610 if ((ctxt->value != NULL)
9611 && (ctxt->value->type == XPATH_NODESET)
9612 && (ctxt->value->nodesetval != NULL))
9613 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9614 return (total);
9615 default:
9616 return (xmlXPathCompOpEval(ctxt, op));
9617 }
9618}
9619
9620/**
9621 * xmlXPathCompOpEvalLast:
9622 * @ctxt: the XPath parser context with the compiled expression
9623 * @op: an XPath compiled operation
9624 * @last: the last elem found so far
9625 *
9626 * Evaluate the Precompiled XPath operation searching only the last
9627 * element in document order
9628 *
9629 * Returns the number of node traversed
9630 */
9631static int
9632xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9633 xmlNodePtr * last)
9634{
9635 int total = 0, cur;
9636 xmlXPathCompExprPtr comp;
9637 xmlXPathObjectPtr arg1, arg2;
9638
Daniel Veillard556c6682001-10-06 09:59:51 +00009639 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009640 comp = ctxt->comp;
9641 switch (op->op) {
9642 case XPATH_OP_END:
9643 return (0);
9644 case XPATH_OP_UNION:
9645 total =
9646 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009647 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009648 if ((ctxt->value != NULL)
9649 && (ctxt->value->type == XPATH_NODESET)
9650 && (ctxt->value->nodesetval != NULL)
9651 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9652 /*
9653 * limit tree traversing to first node in the result
9654 */
9655 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9656 *last =
9657 ctxt->value->nodesetval->nodeTab[ctxt->value->
9658 nodesetval->nodeNr -
9659 1];
9660 }
9661 cur =
9662 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009663 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009664 if ((ctxt->value != NULL)
9665 && (ctxt->value->type == XPATH_NODESET)
9666 && (ctxt->value->nodesetval != NULL)
9667 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9668 }
9669 CHECK_TYPE0(XPATH_NODESET);
9670 arg2 = valuePop(ctxt);
9671
9672 CHECK_TYPE0(XPATH_NODESET);
9673 arg1 = valuePop(ctxt);
9674
9675 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9676 arg2->nodesetval);
9677 valuePush(ctxt, arg1);
9678 xmlXPathFreeObject(arg2);
9679 /* optimizer */
9680 if (total > cur)
9681 xmlXPathCompSwap(op);
9682 return (total + cur);
9683 case XPATH_OP_ROOT:
9684 xmlXPathRoot(ctxt);
9685 return (0);
9686 case XPATH_OP_NODE:
9687 if (op->ch1 != -1)
9688 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009689 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009690 if (op->ch2 != -1)
9691 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009692 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9694 return (total);
9695 case XPATH_OP_RESET:
9696 if (op->ch1 != -1)
9697 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009698 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009699 if (op->ch2 != -1)
9700 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009701 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009702 ctxt->context->node = NULL;
9703 return (total);
9704 case XPATH_OP_COLLECT:{
9705 if (op->ch1 == -1)
9706 return (0);
9707
9708 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009709 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009710
9711 /*
9712 * Optimization for [n] selection where n is a number
9713 */
9714 if ((op->ch2 != -1) &&
9715 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9716 (comp->steps[op->ch2].ch1 == -1) &&
9717 (comp->steps[op->ch2].ch2 != -1) &&
9718 (comp->steps[comp->steps[op->ch2].ch2].op ==
9719 XPATH_OP_VALUE)) {
9720 xmlXPathObjectPtr val;
9721
9722 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9723 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9724 int indx = (int) val->floatval;
9725
9726 if (val->floatval == (float) indx) {
9727 total +=
9728 xmlXPathNodeCollectAndTestNth(ctxt, op,
9729 indx, NULL,
9730 last);
9731 return (total);
9732 }
9733 }
9734 }
9735 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9736 return (total);
9737 }
9738 case XPATH_OP_VALUE:
9739 valuePush(ctxt,
9740 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9741 return (0);
9742 case XPATH_OP_SORT:
9743 if (op->ch1 != -1)
9744 total +=
9745 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9746 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009747 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009748 if ((ctxt->value != NULL)
9749 && (ctxt->value->type == XPATH_NODESET)
9750 && (ctxt->value->nodesetval != NULL))
9751 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9752 return (total);
9753 default:
9754 return (xmlXPathCompOpEval(ctxt, op));
9755 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009756}
9757
Owen Taylor3473f882001-02-23 17:55:21 +00009758/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009759 * xmlXPathCompOpEval:
9760 * @ctxt: the XPath parser context with the compiled expression
9761 * @op: an XPath compiled operation
9762 *
9763 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009764 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009765 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009766static int
9767xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9768{
9769 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009770 int equal, ret;
9771 xmlXPathCompExprPtr comp;
9772 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009773 xmlNodePtr bak;
9774 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009775 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009776 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009777
Daniel Veillard556c6682001-10-06 09:59:51 +00009778 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009779 comp = ctxt->comp;
9780 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009781 case XPATH_OP_END:
9782 return (0);
9783 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009784 bakd = ctxt->context->doc;
9785 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009786 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009787 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009788 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009789 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009790 xmlXPathBooleanFunction(ctxt, 1);
9791 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9792 return (total);
9793 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009794 ctxt->context->doc = bakd;
9795 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009796 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009797 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009798 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009799 if (ctxt->error) {
9800 xmlXPathFreeObject(arg2);
9801 return(0);
9802 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009803 xmlXPathBooleanFunction(ctxt, 1);
9804 arg1 = valuePop(ctxt);
9805 arg1->boolval &= arg2->boolval;
9806 valuePush(ctxt, arg1);
9807 xmlXPathFreeObject(arg2);
9808 return (total);
9809 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009810 bakd = ctxt->context->doc;
9811 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009812 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009813 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009814 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009815 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009816 xmlXPathBooleanFunction(ctxt, 1);
9817 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9818 return (total);
9819 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009820 ctxt->context->doc = bakd;
9821 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009822 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009823 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009824 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009825 if (ctxt->error) {
9826 xmlXPathFreeObject(arg2);
9827 return(0);
9828 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009829 xmlXPathBooleanFunction(ctxt, 1);
9830 arg1 = valuePop(ctxt);
9831 arg1->boolval |= arg2->boolval;
9832 valuePush(ctxt, arg1);
9833 xmlXPathFreeObject(arg2);
9834 return (total);
9835 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009836 bakd = ctxt->context->doc;
9837 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009838 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009839 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009840 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009841 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009842 ctxt->context->doc = bakd;
9843 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009844 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009845 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009846 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009847 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009848 if (op->value)
9849 equal = xmlXPathEqualValues(ctxt);
9850 else
9851 equal = xmlXPathNotEqualValues(ctxt);
9852 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009853 return (total);
9854 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009855 bakd = ctxt->context->doc;
9856 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009857 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009858 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009859 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009860 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009861 ctxt->context->doc = bakd;
9862 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009863 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009864 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009865 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009866 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009867 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9868 valuePush(ctxt, xmlXPathNewBoolean(ret));
9869 return (total);
9870 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009871 bakd = ctxt->context->doc;
9872 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009873 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009874 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009875 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009876 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009877 if (op->ch2 != -1) {
9878 ctxt->context->doc = bakd;
9879 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009880 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009881 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009882 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009883 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009884 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009885 if (op->value == 0)
9886 xmlXPathSubValues(ctxt);
9887 else if (op->value == 1)
9888 xmlXPathAddValues(ctxt);
9889 else if (op->value == 2)
9890 xmlXPathValueFlipSign(ctxt);
9891 else if (op->value == 3) {
9892 CAST_TO_NUMBER;
9893 CHECK_TYPE0(XPATH_NUMBER);
9894 }
9895 return (total);
9896 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009897 bakd = ctxt->context->doc;
9898 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009899 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009900 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009901 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009902 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009903 ctxt->context->doc = bakd;
9904 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009905 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009906 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009907 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009908 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009909 if (op->value == 0)
9910 xmlXPathMultValues(ctxt);
9911 else if (op->value == 1)
9912 xmlXPathDivValues(ctxt);
9913 else if (op->value == 2)
9914 xmlXPathModValues(ctxt);
9915 return (total);
9916 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009917 bakd = ctxt->context->doc;
9918 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009919 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009920 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009921 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009922 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009923 ctxt->context->doc = bakd;
9924 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009925 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009926 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009927 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009928 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009929 CHECK_TYPE0(XPATH_NODESET);
9930 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009931
Daniel Veillardf06307e2001-07-03 10:35:50 +00009932 CHECK_TYPE0(XPATH_NODESET);
9933 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009934
Daniel Veillardf06307e2001-07-03 10:35:50 +00009935 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9936 arg2->nodesetval);
9937 valuePush(ctxt, arg1);
9938 xmlXPathFreeObject(arg2);
9939 return (total);
9940 case XPATH_OP_ROOT:
9941 xmlXPathRoot(ctxt);
9942 return (total);
9943 case XPATH_OP_NODE:
9944 if (op->ch1 != -1)
9945 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009946 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009947 if (op->ch2 != -1)
9948 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009949 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009950 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9951 return (total);
9952 case XPATH_OP_RESET:
9953 if (op->ch1 != -1)
9954 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009955 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009956 if (op->ch2 != -1)
9957 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009958 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009959 ctxt->context->node = NULL;
9960 return (total);
9961 case XPATH_OP_COLLECT:{
9962 if (op->ch1 == -1)
9963 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009964
Daniel Veillardf06307e2001-07-03 10:35:50 +00009965 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009966 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009967
Daniel Veillardf06307e2001-07-03 10:35:50 +00009968 /*
9969 * Optimization for [n] selection where n is a number
9970 */
9971 if ((op->ch2 != -1) &&
9972 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9973 (comp->steps[op->ch2].ch1 == -1) &&
9974 (comp->steps[op->ch2].ch2 != -1) &&
9975 (comp->steps[comp->steps[op->ch2].ch2].op ==
9976 XPATH_OP_VALUE)) {
9977 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009978
Daniel Veillardf06307e2001-07-03 10:35:50 +00009979 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9980 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9981 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009982
Daniel Veillardf06307e2001-07-03 10:35:50 +00009983 if (val->floatval == (float) indx) {
9984 total +=
9985 xmlXPathNodeCollectAndTestNth(ctxt, op,
9986 indx, NULL,
9987 NULL);
9988 return (total);
9989 }
9990 }
9991 }
9992 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9993 return (total);
9994 }
9995 case XPATH_OP_VALUE:
9996 valuePush(ctxt,
9997 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9998 return (total);
9999 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010000 xmlXPathObjectPtr val;
10001
Daniel Veillardf06307e2001-07-03 10:35:50 +000010002 if (op->ch1 != -1)
10003 total +=
10004 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010005 if (op->value5 == NULL) {
10006 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10007 if (val == NULL) {
10008 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10009 return(0);
10010 }
10011 valuePush(ctxt, val);
10012 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010013 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010014
Daniel Veillardf06307e2001-07-03 10:35:50 +000010015 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10016 if (URI == NULL) {
10017 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010018 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010019 op->value4, op->value5);
10020 return (total);
10021 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010022 val = xmlXPathVariableLookupNS(ctxt->context,
10023 op->value4, URI);
10024 if (val == NULL) {
10025 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10026 return(0);
10027 }
10028 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010029 }
10030 return (total);
10031 }
10032 case XPATH_OP_FUNCTION:{
10033 xmlXPathFunction func;
10034 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010035 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010036
10037 if (op->ch1 != -1)
10038 total +=
10039 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010040 if (ctxt->valueNr < op->value) {
10041 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010042 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010043 ctxt->error = XPATH_INVALID_OPERAND;
10044 return (total);
10045 }
10046 for (i = 0; i < op->value; i++)
10047 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10048 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010049 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010050 ctxt->error = XPATH_INVALID_OPERAND;
10051 return (total);
10052 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010053 if (op->cache != NULL)
10054 func = (xmlXPathFunction) op->cache;
10055 else {
10056 const xmlChar *URI = NULL;
10057
10058 if (op->value5 == NULL)
10059 func =
10060 xmlXPathFunctionLookup(ctxt->context,
10061 op->value4);
10062 else {
10063 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10064 if (URI == NULL) {
10065 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010066 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010067 op->value4, op->value5);
10068 return (total);
10069 }
10070 func = xmlXPathFunctionLookupNS(ctxt->context,
10071 op->value4, URI);
10072 }
10073 if (func == NULL) {
10074 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010075 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010076 op->value4);
10077 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010078 }
10079 op->cache = (void *) func;
10080 op->cacheURI = (void *) URI;
10081 }
10082 oldFunc = ctxt->context->function;
10083 oldFuncURI = ctxt->context->functionURI;
10084 ctxt->context->function = op->value4;
10085 ctxt->context->functionURI = op->cacheURI;
10086 func(ctxt, op->value);
10087 ctxt->context->function = oldFunc;
10088 ctxt->context->functionURI = oldFuncURI;
10089 return (total);
10090 }
10091 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010092 bakd = ctxt->context->doc;
10093 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010094 if (op->ch1 != -1)
10095 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010096 ctxt->context->doc = bakd;
10097 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010098 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099 if (op->ch2 != -1)
10100 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010101 ctxt->context->doc = bakd;
10102 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010103 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010104 return (total);
10105 case XPATH_OP_PREDICATE:
10106 case XPATH_OP_FILTER:{
10107 xmlXPathObjectPtr res;
10108 xmlXPathObjectPtr obj, tmp;
10109 xmlNodeSetPtr newset = NULL;
10110 xmlNodeSetPtr oldset;
10111 xmlNodePtr oldnode;
10112 int i;
10113
10114 /*
10115 * Optimization for ()[1] selection i.e. the first elem
10116 */
10117 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10118 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10119 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10120 xmlXPathObjectPtr val;
10121
10122 val = comp->steps[op->ch2].value4;
10123 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10124 (val->floatval == 1.0)) {
10125 xmlNodePtr first = NULL;
10126
10127 total +=
10128 xmlXPathCompOpEvalFirst(ctxt,
10129 &comp->steps[op->ch1],
10130 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010131 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010132 /*
10133 * The nodeset should be in document order,
10134 * Keep only the first value
10135 */
10136 if ((ctxt->value != NULL) &&
10137 (ctxt->value->type == XPATH_NODESET) &&
10138 (ctxt->value->nodesetval != NULL) &&
10139 (ctxt->value->nodesetval->nodeNr > 1))
10140 ctxt->value->nodesetval->nodeNr = 1;
10141 return (total);
10142 }
10143 }
10144 /*
10145 * Optimization for ()[last()] selection i.e. the last elem
10146 */
10147 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10148 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10149 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10150 int f = comp->steps[op->ch2].ch1;
10151
10152 if ((f != -1) &&
10153 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10154 (comp->steps[f].value5 == NULL) &&
10155 (comp->steps[f].value == 0) &&
10156 (comp->steps[f].value4 != NULL) &&
10157 (xmlStrEqual
10158 (comp->steps[f].value4, BAD_CAST "last"))) {
10159 xmlNodePtr last = NULL;
10160
10161 total +=
10162 xmlXPathCompOpEvalLast(ctxt,
10163 &comp->steps[op->ch1],
10164 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010165 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010166 /*
10167 * The nodeset should be in document order,
10168 * Keep only the last value
10169 */
10170 if ((ctxt->value != NULL) &&
10171 (ctxt->value->type == XPATH_NODESET) &&
10172 (ctxt->value->nodesetval != NULL) &&
10173 (ctxt->value->nodesetval->nodeTab != NULL) &&
10174 (ctxt->value->nodesetval->nodeNr > 1)) {
10175 ctxt->value->nodesetval->nodeTab[0] =
10176 ctxt->value->nodesetval->nodeTab[ctxt->
10177 value->
10178 nodesetval->
10179 nodeNr -
10180 1];
10181 ctxt->value->nodesetval->nodeNr = 1;
10182 }
10183 return (total);
10184 }
10185 }
10186
10187 if (op->ch1 != -1)
10188 total +=
10189 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010190 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010191 if (op->ch2 == -1)
10192 return (total);
10193 if (ctxt->value == NULL)
10194 return (total);
10195
10196 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010197
10198#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010199 /*
10200 * Hum are we filtering the result of an XPointer expression
10201 */
10202 if (ctxt->value->type == XPATH_LOCATIONSET) {
10203 xmlLocationSetPtr newlocset = NULL;
10204 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010205
Daniel Veillardf06307e2001-07-03 10:35:50 +000010206 /*
10207 * Extract the old locset, and then evaluate the result of the
10208 * expression for all the element in the locset. use it to grow
10209 * up a new locset.
10210 */
10211 CHECK_TYPE0(XPATH_LOCATIONSET);
10212 obj = valuePop(ctxt);
10213 oldlocset = obj->user;
10214 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010215
Daniel Veillardf06307e2001-07-03 10:35:50 +000010216 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10217 ctxt->context->contextSize = 0;
10218 ctxt->context->proximityPosition = 0;
10219 if (op->ch2 != -1)
10220 total +=
10221 xmlXPathCompOpEval(ctxt,
10222 &comp->steps[op->ch2]);
10223 res = valuePop(ctxt);
10224 if (res != NULL)
10225 xmlXPathFreeObject(res);
10226 valuePush(ctxt, obj);
10227 CHECK_ERROR0;
10228 return (total);
10229 }
10230 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010231
Daniel Veillardf06307e2001-07-03 10:35:50 +000010232 for (i = 0; i < oldlocset->locNr; i++) {
10233 /*
10234 * Run the evaluation with a node list made of a
10235 * single item in the nodelocset.
10236 */
10237 ctxt->context->node = oldlocset->locTab[i]->user;
10238 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10239 valuePush(ctxt, tmp);
10240 ctxt->context->contextSize = oldlocset->locNr;
10241 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010242
Daniel Veillardf06307e2001-07-03 10:35:50 +000010243 if (op->ch2 != -1)
10244 total +=
10245 xmlXPathCompOpEval(ctxt,
10246 &comp->steps[op->ch2]);
10247 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010248
Daniel Veillardf06307e2001-07-03 10:35:50 +000010249 /*
10250 * The result of the evaluation need to be tested to
10251 * decided whether the filter succeeded or not
10252 */
10253 res = valuePop(ctxt);
10254 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10255 xmlXPtrLocationSetAdd(newlocset,
10256 xmlXPathObjectCopy
10257 (oldlocset->locTab[i]));
10258 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010259
Daniel Veillardf06307e2001-07-03 10:35:50 +000010260 /*
10261 * Cleanup
10262 */
10263 if (res != NULL)
10264 xmlXPathFreeObject(res);
10265 if (ctxt->value == tmp) {
10266 res = valuePop(ctxt);
10267 xmlXPathFreeObject(res);
10268 }
10269
10270 ctxt->context->node = NULL;
10271 }
10272
10273 /*
10274 * The result is used as the new evaluation locset.
10275 */
10276 xmlXPathFreeObject(obj);
10277 ctxt->context->node = NULL;
10278 ctxt->context->contextSize = -1;
10279 ctxt->context->proximityPosition = -1;
10280 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10281 ctxt->context->node = oldnode;
10282 return (total);
10283 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010284#endif /* LIBXML_XPTR_ENABLED */
10285
Daniel Veillardf06307e2001-07-03 10:35:50 +000010286 /*
10287 * Extract the old set, and then evaluate the result of the
10288 * expression for all the element in the set. use it to grow
10289 * up a new set.
10290 */
10291 CHECK_TYPE0(XPATH_NODESET);
10292 obj = valuePop(ctxt);
10293 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010294
Daniel Veillardf06307e2001-07-03 10:35:50 +000010295 oldnode = ctxt->context->node;
10296 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010297
Daniel Veillardf06307e2001-07-03 10:35:50 +000010298 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10299 ctxt->context->contextSize = 0;
10300 ctxt->context->proximityPosition = 0;
10301 if (op->ch2 != -1)
10302 total +=
10303 xmlXPathCompOpEval(ctxt,
10304 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010305 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010306 res = valuePop(ctxt);
10307 if (res != NULL)
10308 xmlXPathFreeObject(res);
10309 valuePush(ctxt, obj);
10310 ctxt->context->node = oldnode;
10311 CHECK_ERROR0;
10312 } else {
10313 /*
10314 * Initialize the new set.
10315 */
10316 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010317
Daniel Veillardf06307e2001-07-03 10:35:50 +000010318 for (i = 0; i < oldset->nodeNr; i++) {
10319 /*
10320 * Run the evaluation with a node list made of
10321 * a single item in the nodeset.
10322 */
10323 ctxt->context->node = oldset->nodeTab[i];
10324 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10325 valuePush(ctxt, tmp);
10326 ctxt->context->contextSize = oldset->nodeNr;
10327 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010328
Daniel Veillardf06307e2001-07-03 10:35:50 +000010329 if (op->ch2 != -1)
10330 total +=
10331 xmlXPathCompOpEval(ctxt,
10332 &comp->steps[op->ch2]);
10333 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010334
Daniel Veillardf06307e2001-07-03 10:35:50 +000010335 /*
10336 * The result of the evaluation need to be tested to
10337 * decided whether the filter succeeded or not
10338 */
10339 res = valuePop(ctxt);
10340 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10341 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10342 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010343
Daniel Veillardf06307e2001-07-03 10:35:50 +000010344 /*
10345 * Cleanup
10346 */
10347 if (res != NULL)
10348 xmlXPathFreeObject(res);
10349 if (ctxt->value == tmp) {
10350 res = valuePop(ctxt);
10351 xmlXPathFreeObject(res);
10352 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010353
Daniel Veillardf06307e2001-07-03 10:35:50 +000010354 ctxt->context->node = NULL;
10355 }
10356
10357 /*
10358 * The result is used as the new evaluation set.
10359 */
10360 xmlXPathFreeObject(obj);
10361 ctxt->context->node = NULL;
10362 ctxt->context->contextSize = -1;
10363 ctxt->context->proximityPosition = -1;
10364 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10365 }
10366 ctxt->context->node = oldnode;
10367 return (total);
10368 }
10369 case XPATH_OP_SORT:
10370 if (op->ch1 != -1)
10371 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010372 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010373 if ((ctxt->value != NULL) &&
10374 (ctxt->value->type == XPATH_NODESET) &&
10375 (ctxt->value->nodesetval != NULL))
10376 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10377 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010378#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010379 case XPATH_OP_RANGETO:{
10380 xmlXPathObjectPtr range;
10381 xmlXPathObjectPtr res, obj;
10382 xmlXPathObjectPtr tmp;
10383 xmlLocationSetPtr newset = NULL;
10384 xmlNodeSetPtr oldset;
10385 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010386
Daniel Veillardf06307e2001-07-03 10:35:50 +000010387 if (op->ch1 != -1)
10388 total +=
10389 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10390 if (op->ch2 == -1)
10391 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010392
Daniel Veillardf06307e2001-07-03 10:35:50 +000010393 CHECK_TYPE0(XPATH_NODESET);
10394 obj = valuePop(ctxt);
10395 oldset = obj->nodesetval;
10396 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010397
Daniel Veillardf06307e2001-07-03 10:35:50 +000010398 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010399
Daniel Veillardf06307e2001-07-03 10:35:50 +000010400 if (oldset != NULL) {
10401 for (i = 0; i < oldset->nodeNr; i++) {
10402 /*
10403 * Run the evaluation with a node list made of a single item
10404 * in the nodeset.
10405 */
10406 ctxt->context->node = oldset->nodeTab[i];
10407 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10408 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010409
Daniel Veillardf06307e2001-07-03 10:35:50 +000010410 if (op->ch2 != -1)
10411 total +=
10412 xmlXPathCompOpEval(ctxt,
10413 &comp->steps[op->ch2]);
10414 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010415
Daniel Veillardf06307e2001-07-03 10:35:50 +000010416 /*
10417 * The result of the evaluation need to be tested to
10418 * decided whether the filter succeeded or not
10419 */
10420 res = valuePop(ctxt);
10421 range =
10422 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10423 res);
10424 if (range != NULL) {
10425 xmlXPtrLocationSetAdd(newset, range);
10426 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010427
Daniel Veillardf06307e2001-07-03 10:35:50 +000010428 /*
10429 * Cleanup
10430 */
10431 if (res != NULL)
10432 xmlXPathFreeObject(res);
10433 if (ctxt->value == tmp) {
10434 res = valuePop(ctxt);
10435 xmlXPathFreeObject(res);
10436 }
10437
10438 ctxt->context->node = NULL;
10439 }
10440 }
10441
10442 /*
10443 * The result is used as the new evaluation set.
10444 */
10445 xmlXPathFreeObject(obj);
10446 ctxt->context->node = NULL;
10447 ctxt->context->contextSize = -1;
10448 ctxt->context->proximityPosition = -1;
10449 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10450 return (total);
10451 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010452#endif /* LIBXML_XPTR_ENABLED */
10453 }
10454 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010455 "XPath: unknown precompiled operation %d\n", op->op);
10456 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010457}
10458
10459/**
10460 * xmlXPathRunEval:
10461 * @ctxt: the XPath parser context with the compiled expression
10462 *
10463 * Evaluate the Precompiled XPath expression in the given context.
10464 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010465static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010466xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10467 xmlXPathCompExprPtr comp;
10468
10469 if ((ctxt == NULL) || (ctxt->comp == NULL))
10470 return;
10471
10472 if (ctxt->valueTab == NULL) {
10473 /* Allocate the value stack */
10474 ctxt->valueTab = (xmlXPathObjectPtr *)
10475 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10476 if (ctxt->valueTab == NULL) {
10477 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010478 }
10479 ctxt->valueNr = 0;
10480 ctxt->valueMax = 10;
10481 ctxt->value = NULL;
10482 }
10483 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010484 if(comp->last < 0) {
10485 xmlGenericError(xmlGenericErrorContext,
10486 "xmlXPathRunEval: last is less than zero\n");
10487 return;
10488 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010489 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10490}
10491
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010492/************************************************************************
10493 * *
10494 * Public interfaces *
10495 * *
10496 ************************************************************************/
10497
10498/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010499 * xmlXPathEvalPredicate:
10500 * @ctxt: the XPath context
10501 * @res: the Predicate Expression evaluation result
10502 *
10503 * Evaluate a predicate result for the current node.
10504 * A PredicateExpr is evaluated by evaluating the Expr and converting
10505 * the result to a boolean. If the result is a number, the result will
10506 * be converted to true if the number is equal to the position of the
10507 * context node in the context node list (as returned by the position
10508 * function) and will be converted to false otherwise; if the result
10509 * is not a number, then the result will be converted as if by a call
10510 * to the boolean function.
10511 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010512 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010513 */
10514int
10515xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10516 if (res == NULL) return(0);
10517 switch (res->type) {
10518 case XPATH_BOOLEAN:
10519 return(res->boolval);
10520 case XPATH_NUMBER:
10521 return(res->floatval == ctxt->proximityPosition);
10522 case XPATH_NODESET:
10523 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010524 if (res->nodesetval == NULL)
10525 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010526 return(res->nodesetval->nodeNr != 0);
10527 case XPATH_STRING:
10528 return((res->stringval != NULL) &&
10529 (xmlStrlen(res->stringval) != 0));
10530 default:
10531 STRANGE
10532 }
10533 return(0);
10534}
10535
10536/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010537 * xmlXPathEvaluatePredicateResult:
10538 * @ctxt: the XPath Parser context
10539 * @res: the Predicate Expression evaluation result
10540 *
10541 * Evaluate a predicate result for the current node.
10542 * A PredicateExpr is evaluated by evaluating the Expr and converting
10543 * the result to a boolean. If the result is a number, the result will
10544 * be converted to true if the number is equal to the position of the
10545 * context node in the context node list (as returned by the position
10546 * function) and will be converted to false otherwise; if the result
10547 * is not a number, then the result will be converted as if by a call
10548 * to the boolean function.
10549 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010550 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010551 */
10552int
10553xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10554 xmlXPathObjectPtr res) {
10555 if (res == NULL) return(0);
10556 switch (res->type) {
10557 case XPATH_BOOLEAN:
10558 return(res->boolval);
10559 case XPATH_NUMBER:
10560 return(res->floatval == ctxt->context->proximityPosition);
10561 case XPATH_NODESET:
10562 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010563 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010564 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010565 return(res->nodesetval->nodeNr != 0);
10566 case XPATH_STRING:
10567 return((res->stringval != NULL) &&
10568 (xmlStrlen(res->stringval) != 0));
10569 default:
10570 STRANGE
10571 }
10572 return(0);
10573}
10574
10575/**
10576 * xmlXPathCompile:
10577 * @str: the XPath expression
10578 *
10579 * Compile an XPath expression
10580 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010581 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010582 * the caller has to free the object.
10583 */
10584xmlXPathCompExprPtr
10585xmlXPathCompile(const xmlChar *str) {
10586 xmlXPathParserContextPtr ctxt;
10587 xmlXPathCompExprPtr comp;
10588
10589 xmlXPathInit();
10590
10591 ctxt = xmlXPathNewParserContext(str, NULL);
10592 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010593
Daniel Veillard40af6492001-04-22 08:50:55 +000010594 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010595 /*
10596 * aleksey: in some cases this line prints *second* error message
10597 * (see bug #78858) and probably this should be fixed.
10598 * However, we are not sure that all error messages are printed
10599 * out in other places. It's not critical so we leave it as-is for now
10600 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010601 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10602 comp = NULL;
10603 } else {
10604 comp = ctxt->comp;
10605 ctxt->comp = NULL;
10606 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010607 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010608 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010609 comp->expr = xmlStrdup(str);
10610#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010611 comp->string = xmlStrdup(str);
10612 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010613#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010614 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010615 return(comp);
10616}
10617
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010618/**
10619 * xmlXPathCompiledEval:
10620 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010621 * @ctx: the XPath context
10622 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010623 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010624 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010625 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010626 * the caller has to free the object.
10627 */
10628xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010629xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010630 xmlXPathParserContextPtr ctxt;
10631 xmlXPathObjectPtr res, tmp, init = NULL;
10632 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010633#ifndef LIBXML_THREAD_ENABLED
10634 static int reentance = 0;
10635#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010636
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010637 if ((comp == NULL) || (ctx == NULL))
10638 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010639 xmlXPathInit();
10640
10641 CHECK_CONTEXT(ctx)
10642
Daniel Veillard81463942001-10-16 12:34:39 +000010643#ifndef LIBXML_THREAD_ENABLED
10644 reentance++;
10645 if (reentance > 1)
10646 xmlXPathDisableOptimizer = 1;
10647#endif
10648
Daniel Veillardf06307e2001-07-03 10:35:50 +000010649#ifdef DEBUG_EVAL_COUNTS
10650 comp->nb++;
10651 if ((comp->string != NULL) && (comp->nb > 100)) {
10652 fprintf(stderr, "100 x %s\n", comp->string);
10653 comp->nb = 0;
10654 }
10655#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010656 ctxt = xmlXPathCompParserContext(comp, ctx);
10657 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010658
10659 if (ctxt->value == NULL) {
10660 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010661 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010662 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010663 } else {
10664 res = valuePop(ctxt);
10665 }
10666
Daniel Veillardf06307e2001-07-03 10:35:50 +000010667
Owen Taylor3473f882001-02-23 17:55:21 +000010668 do {
10669 tmp = valuePop(ctxt);
10670 if (tmp != NULL) {
10671 if (tmp != init)
10672 stack++;
10673 xmlXPathFreeObject(tmp);
10674 }
10675 } while (tmp != NULL);
10676 if ((stack != 0) && (res != NULL)) {
10677 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010678 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010679 stack);
10680 }
10681 if (ctxt->error != XPATH_EXPRESSION_OK) {
10682 xmlXPathFreeObject(res);
10683 res = NULL;
10684 }
10685
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010686
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010687 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010688 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010689#ifndef LIBXML_THREAD_ENABLED
10690 reentance--;
10691#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010692 return(res);
10693}
10694
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010695/**
10696 * xmlXPathEvalExpr:
10697 * @ctxt: the XPath Parser context
10698 *
10699 * Parse and evaluate an XPath expression in the given context,
10700 * then push the result on the context stack
10701 */
10702void
10703xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10704 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010705 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010706 xmlXPathRunEval(ctxt);
10707}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010708
10709/**
10710 * xmlXPathEval:
10711 * @str: the XPath expression
10712 * @ctx: the XPath context
10713 *
10714 * Evaluate the XPath Location Path in the given context.
10715 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010716 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010717 * the caller has to free the object.
10718 */
10719xmlXPathObjectPtr
10720xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10721 xmlXPathParserContextPtr ctxt;
10722 xmlXPathObjectPtr res, tmp, init = NULL;
10723 int stack = 0;
10724
10725 xmlXPathInit();
10726
10727 CHECK_CONTEXT(ctx)
10728
10729 ctxt = xmlXPathNewParserContext(str, ctx);
10730 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010731
10732 if (ctxt->value == NULL) {
10733 xmlGenericError(xmlGenericErrorContext,
10734 "xmlXPathEval: evaluation failed\n");
10735 res = NULL;
10736 } else if (*ctxt->cur != 0) {
10737 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10738 res = NULL;
10739 } else {
10740 res = valuePop(ctxt);
10741 }
10742
10743 do {
10744 tmp = valuePop(ctxt);
10745 if (tmp != NULL) {
10746 if (tmp != init)
10747 stack++;
10748 xmlXPathFreeObject(tmp);
10749 }
10750 } while (tmp != NULL);
10751 if ((stack != 0) && (res != NULL)) {
10752 xmlGenericError(xmlGenericErrorContext,
10753 "xmlXPathEval: %d object left on the stack\n",
10754 stack);
10755 }
10756 if (ctxt->error != XPATH_EXPRESSION_OK) {
10757 xmlXPathFreeObject(res);
10758 res = NULL;
10759 }
10760
Owen Taylor3473f882001-02-23 17:55:21 +000010761 xmlXPathFreeParserContext(ctxt);
10762 return(res);
10763}
10764
10765/**
10766 * xmlXPathEvalExpression:
10767 * @str: the XPath expression
10768 * @ctxt: the XPath context
10769 *
10770 * Evaluate the XPath expression in the given context.
10771 *
10772 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10773 * the caller has to free the object.
10774 */
10775xmlXPathObjectPtr
10776xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10777 xmlXPathParserContextPtr pctxt;
10778 xmlXPathObjectPtr res, tmp;
10779 int stack = 0;
10780
10781 xmlXPathInit();
10782
10783 CHECK_CONTEXT(ctxt)
10784
10785 pctxt = xmlXPathNewParserContext(str, ctxt);
10786 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010787
10788 if (*pctxt->cur != 0) {
10789 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10790 res = NULL;
10791 } else {
10792 res = valuePop(pctxt);
10793 }
10794 do {
10795 tmp = valuePop(pctxt);
10796 if (tmp != NULL) {
10797 xmlXPathFreeObject(tmp);
10798 stack++;
10799 }
10800 } while (tmp != NULL);
10801 if ((stack != 0) && (res != NULL)) {
10802 xmlGenericError(xmlGenericErrorContext,
10803 "xmlXPathEvalExpression: %d object left on the stack\n",
10804 stack);
10805 }
10806 xmlXPathFreeParserContext(pctxt);
10807 return(res);
10808}
10809
Daniel Veillard42766c02002-08-22 20:52:17 +000010810/************************************************************************
10811 * *
10812 * Extra functions not pertaining to the XPath spec *
10813 * *
10814 ************************************************************************/
10815/**
10816 * xmlXPathEscapeUriFunction:
10817 * @ctxt: the XPath Parser context
10818 * @nargs: the number of arguments
10819 *
10820 * Implement the escape-uri() XPath function
10821 * string escape-uri(string $str, bool $escape-reserved)
10822 *
10823 * This function applies the URI escaping rules defined in section 2 of [RFC
10824 * 2396] to the string supplied as $uri-part, which typically represents all
10825 * or part of a URI. The effect of the function is to replace any special
10826 * character in the string by an escape sequence of the form %xx%yy...,
10827 * where xxyy... is the hexadecimal representation of the octets used to
10828 * represent the character in UTF-8.
10829 *
10830 * The set of characters that are escaped depends on the setting of the
10831 * boolean argument $escape-reserved.
10832 *
10833 * If $escape-reserved is true, all characters are escaped other than lower
10834 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10835 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10836 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10837 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10838 * A-F).
10839 *
10840 * If $escape-reserved is false, the behavior differs in that characters
10841 * referred to in [RFC 2396] as reserved characters are not escaped. These
10842 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10843 *
10844 * [RFC 2396] does not define whether escaped URIs should use lower case or
10845 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10846 * compared using string comparison functions, this function must always use
10847 * the upper-case letters A-F.
10848 *
10849 * Generally, $escape-reserved should be set to true when escaping a string
10850 * that is to form a single part of a URI, and to false when escaping an
10851 * entire URI or URI reference.
10852 *
10853 * In the case of non-ascii characters, the string is encoded according to
10854 * utf-8 and then converted according to RFC 2396.
10855 *
10856 * Examples
10857 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10858 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10859 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10860 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10861 *
10862 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010863static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010864xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10865 xmlXPathObjectPtr str;
10866 int escape_reserved;
10867 xmlBufferPtr target;
10868 xmlChar *cptr;
10869 xmlChar escape[4];
10870
10871 CHECK_ARITY(2);
10872
10873 escape_reserved = xmlXPathPopBoolean(ctxt);
10874
10875 CAST_TO_STRING;
10876 str = valuePop(ctxt);
10877
10878 target = xmlBufferCreate();
10879
10880 escape[0] = '%';
10881 escape[3] = 0;
10882
10883 if (target) {
10884 for (cptr = str->stringval; *cptr; cptr++) {
10885 if ((*cptr >= 'A' && *cptr <= 'Z') ||
10886 (*cptr >= 'a' && *cptr <= 'z') ||
10887 (*cptr >= '0' && *cptr <= '9') ||
10888 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
10889 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
10890 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
10891 (*cptr == '%' &&
10892 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
10893 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
10894 (cptr[1] >= '0' && cptr[1] <= '9')) &&
10895 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
10896 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
10897 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
10898 (!escape_reserved &&
10899 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
10900 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
10901 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
10902 *cptr == ','))) {
10903 xmlBufferAdd(target, cptr, 1);
10904 } else {
10905 if ((*cptr >> 4) < 10)
10906 escape[1] = '0' + (*cptr >> 4);
10907 else
10908 escape[1] = 'A' - 10 + (*cptr >> 4);
10909 if ((*cptr & 0xF) < 10)
10910 escape[2] = '0' + (*cptr & 0xF);
10911 else
10912 escape[2] = 'A' - 10 + (*cptr & 0xF);
10913
10914 xmlBufferAdd(target, &escape[0], 3);
10915 }
10916 }
10917 }
10918 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
10919 xmlBufferFree(target);
10920 xmlXPathFreeObject(str);
10921}
10922
Owen Taylor3473f882001-02-23 17:55:21 +000010923/**
10924 * xmlXPathRegisterAllFunctions:
10925 * @ctxt: the XPath context
10926 *
10927 * Registers all default XPath functions in this context
10928 */
10929void
10930xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10931{
10932 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10933 xmlXPathBooleanFunction);
10934 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10935 xmlXPathCeilingFunction);
10936 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10937 xmlXPathCountFunction);
10938 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10939 xmlXPathConcatFunction);
10940 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10941 xmlXPathContainsFunction);
10942 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10943 xmlXPathIdFunction);
10944 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10945 xmlXPathFalseFunction);
10946 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10947 xmlXPathFloorFunction);
10948 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10949 xmlXPathLastFunction);
10950 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10951 xmlXPathLangFunction);
10952 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10953 xmlXPathLocalNameFunction);
10954 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10955 xmlXPathNotFunction);
10956 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10957 xmlXPathNameFunction);
10958 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10959 xmlXPathNamespaceURIFunction);
10960 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10961 xmlXPathNormalizeFunction);
10962 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10963 xmlXPathNumberFunction);
10964 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10965 xmlXPathPositionFunction);
10966 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10967 xmlXPathRoundFunction);
10968 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10969 xmlXPathStringFunction);
10970 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10971 xmlXPathStringLengthFunction);
10972 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10973 xmlXPathStartsWithFunction);
10974 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10975 xmlXPathSubstringFunction);
10976 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10977 xmlXPathSubstringBeforeFunction);
10978 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10979 xmlXPathSubstringAfterFunction);
10980 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10981 xmlXPathSumFunction);
10982 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10983 xmlXPathTrueFunction);
10984 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10985 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000010986
10987 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
10988 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
10989 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000010990}
10991
10992#endif /* LIBXML_XPATH_ENABLED */