blob: 2e0c9ebf2cb848f8e1861b286f28a0565881683f [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
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000054
Daniel Veillard9e7160d2001-03-18 23:17:47 +000055/************************************************************************
56 * *
57 * Floating point stuff *
58 * *
59 ************************************************************************/
60
Daniel Veillardc0631a62001-09-20 13:56:06 +000061#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000062#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000063#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000064#include "trionan.c"
65
Owen Taylor3473f882001-02-23 17:55:21 +000066/*
Owen Taylor3473f882001-02-23 17:55:21 +000067 * The lack of portability of this section of the libc is annoying !
68 */
69double xmlXPathNAN = 0;
70double xmlXPathPINF = 1;
71double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000072double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000073static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000074
Owen Taylor3473f882001-02-23 17:55:21 +000075/**
76 * xmlXPathInit:
77 *
78 * Initialize the XPath environment
79 */
80void
81xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000082 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000083
Bjorn Reese45029602001-08-21 09:23:53 +000084 xmlXPathPINF = trio_pinf();
85 xmlXPathNINF = trio_ninf();
86 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +000087 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +000088
Daniel Veillard20ee8c02001-10-05 09:18:14 +000089 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000090}
91
Daniel Veillardcda96922001-08-21 10:56:31 +000092/**
93 * xmlXPathIsNaN:
94 * @val: a double value
95 *
96 * Provides a portable isnan() function to detect whether a double
97 * is a NotaNumber. Based on trio code
98 * http://sourceforge.net/projects/ctrio/
99 *
100 * Returns 1 if the value is a NaN, 0 otherwise
101 */
102int
103xmlXPathIsNaN(double val) {
104 return(trio_isnan(val));
105}
106
107/**
108 * xmlXPathIsInf:
109 * @val: a double value
110 *
111 * Provides a portable isinf() function to detect whether a double
112 * is a +Infinite or -Infinite. Based on trio code
113 * http://sourceforge.net/projects/ctrio/
114 *
115 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
116 */
117int
118xmlXPathIsInf(double val) {
119 return(trio_isinf(val));
120}
121
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000122/**
123 * xmlXPathGetSign:
124 * @val: a double value
125 *
126 * Provides a portable function to detect the sign of a double
127 * Modified from trio code
128 * http://sourceforge.net/projects/ctrio/
129 *
130 * Returns 1 if the value is Negative, 0 if positive
131 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000132static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000133xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000134 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000135}
136
137
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000138#ifdef LIBXML_XPATH_ENABLED
139/*
140 * TODO: when compatibility allows remove all "fake node libxslt" strings
141 * the test should just be name[0] = ' '
142 */
143/* #define DEBUG */
144/* #define DEBUG_STEP */
145/* #define DEBUG_STEP_NTH */
146/* #define DEBUG_EXPR */
147/* #define DEBUG_EVAL_COUNTS */
148
149static xmlNs xmlXPathXMLNamespaceStruct = {
150 NULL,
151 XML_NAMESPACE_DECL,
152 XML_XML_NAMESPACE,
153 BAD_CAST "xml",
154 NULL
155};
156static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
157#ifndef LIBXML_THREAD_ENABLED
158/*
159 * Optimizer is disabled only when threaded apps are detected while
160 * the library ain't compiled for thread safety.
161 */
162static int xmlXPathDisableOptimizer = 0;
163#endif
164
Owen Taylor3473f882001-02-23 17:55:21 +0000165/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000166 * *
167 * Parser Types *
168 * *
169 ************************************************************************/
170
171/*
172 * Types are private:
173 */
174
175typedef enum {
176 XPATH_OP_END=0,
177 XPATH_OP_AND,
178 XPATH_OP_OR,
179 XPATH_OP_EQUAL,
180 XPATH_OP_CMP,
181 XPATH_OP_PLUS,
182 XPATH_OP_MULT,
183 XPATH_OP_UNION,
184 XPATH_OP_ROOT,
185 XPATH_OP_NODE,
186 XPATH_OP_RESET,
187 XPATH_OP_COLLECT,
188 XPATH_OP_VALUE,
189 XPATH_OP_VARIABLE,
190 XPATH_OP_FUNCTION,
191 XPATH_OP_ARG,
192 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000193 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000194 XPATH_OP_SORT
195#ifdef LIBXML_XPTR_ENABLED
196 ,XPATH_OP_RANGETO
197#endif
198} xmlXPathOp;
199
200typedef enum {
201 AXIS_ANCESTOR = 1,
202 AXIS_ANCESTOR_OR_SELF,
203 AXIS_ATTRIBUTE,
204 AXIS_CHILD,
205 AXIS_DESCENDANT,
206 AXIS_DESCENDANT_OR_SELF,
207 AXIS_FOLLOWING,
208 AXIS_FOLLOWING_SIBLING,
209 AXIS_NAMESPACE,
210 AXIS_PARENT,
211 AXIS_PRECEDING,
212 AXIS_PRECEDING_SIBLING,
213 AXIS_SELF
214} xmlXPathAxisVal;
215
216typedef enum {
217 NODE_TEST_NONE = 0,
218 NODE_TEST_TYPE = 1,
219 NODE_TEST_PI = 2,
220 NODE_TEST_ALL = 3,
221 NODE_TEST_NS = 4,
222 NODE_TEST_NAME = 5
223} xmlXPathTestVal;
224
225typedef enum {
226 NODE_TYPE_NODE = 0,
227 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
228 NODE_TYPE_TEXT = XML_TEXT_NODE,
229 NODE_TYPE_PI = XML_PI_NODE
230} xmlXPathTypeVal;
231
232
233typedef struct _xmlXPathStepOp xmlXPathStepOp;
234typedef xmlXPathStepOp *xmlXPathStepOpPtr;
235struct _xmlXPathStepOp {
236 xmlXPathOp op;
237 int ch1;
238 int ch2;
239 int value;
240 int value2;
241 int value3;
242 void *value4;
243 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000244 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000245 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000246};
247
248struct _xmlXPathCompExpr {
249 int nbStep;
250 int maxStep;
251 xmlXPathStepOp *steps; /* ops for computation */
252 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000253 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000254#ifdef DEBUG_EVAL_COUNTS
255 int nb;
256 xmlChar *string;
257#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000258};
259
260/************************************************************************
261 * *
262 * Parser Type functions *
263 * *
264 ************************************************************************/
265
266/**
267 * xmlXPathNewCompExpr:
268 *
269 * Create a new Xpath component
270 *
271 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
272 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000273static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000274xmlXPathNewCompExpr(void) {
275 xmlXPathCompExprPtr cur;
276
277 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
278 if (cur == NULL) {
279 xmlGenericError(xmlGenericErrorContext,
280 "xmlXPathNewCompExpr : malloc failed\n");
281 return(NULL);
282 }
283 memset(cur, 0, sizeof(xmlXPathCompExpr));
284 cur->maxStep = 10;
285 cur->nbStep = 0;
286 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
287 sizeof(xmlXPathStepOp));
288 if (cur->steps == NULL) {
289 xmlGenericError(xmlGenericErrorContext,
290 "xmlXPathNewCompExpr : malloc failed\n");
291 xmlFree(cur);
292 return(NULL);
293 }
294 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
295 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000296#ifdef DEBUG_EVAL_COUNTS
297 cur->nb = 0;
298#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000299 return(cur);
300}
301
302/**
303 * xmlXPathFreeCompExpr:
304 * @comp: an XPATH comp
305 *
306 * Free up the memory allocated by @comp
307 */
308void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000309xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
310{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000311 xmlXPathStepOpPtr op;
312 int i;
313
314 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000315 return;
316 for (i = 0; i < comp->nbStep; i++) {
317 op = &comp->steps[i];
318 if (op->value4 != NULL) {
319 if (op->op == XPATH_OP_VALUE)
320 xmlXPathFreeObject(op->value4);
321 else
322 xmlFree(op->value4);
323 }
324 if (op->value5 != NULL)
325 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000326 }
327 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000329 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000330#ifdef DEBUG_EVAL_COUNTS
331 if (comp->string != NULL) {
332 xmlFree(comp->string);
333 }
334#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000335 if (comp->expr != NULL) {
336 xmlFree(comp->expr);
337 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000338
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000339 xmlFree(comp);
340}
341
342/**
343 * xmlXPathCompExprAdd:
344 * @comp: the compiled expression
345 * @ch1: first child index
346 * @ch2: second child index
347 * @op: an op
348 * @value: the first int value
349 * @value2: the second int value
350 * @value3: the third int value
351 * @value4: the first string value
352 * @value5: the second string value
353 *
354 * Add an step to an XPath Compiled Expression
355 *
356 * Returns -1 in case of failure, the index otherwise
357 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000358static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000359xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
360 xmlXPathOp op, int value,
361 int value2, int value3, void *value4, void *value5) {
362 if (comp->nbStep >= comp->maxStep) {
363 xmlXPathStepOp *real;
364
365 comp->maxStep *= 2;
366 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
367 comp->maxStep * sizeof(xmlXPathStepOp));
368 if (real == NULL) {
369 comp->maxStep /= 2;
370 xmlGenericError(xmlGenericErrorContext,
371 "xmlXPathCompExprAdd : realloc failed\n");
372 return(-1);
373 }
374 comp->steps = real;
375 }
376 comp->last = comp->nbStep;
377 comp->steps[comp->nbStep].ch1 = ch1;
378 comp->steps[comp->nbStep].ch2 = ch2;
379 comp->steps[comp->nbStep].op = op;
380 comp->steps[comp->nbStep].value = value;
381 comp->steps[comp->nbStep].value2 = value2;
382 comp->steps[comp->nbStep].value3 = value3;
383 comp->steps[comp->nbStep].value4 = value4;
384 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000385 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000386 return(comp->nbStep++);
387}
388
Daniel Veillardf06307e2001-07-03 10:35:50 +0000389/**
390 * xmlXPathCompSwap:
391 * @comp: the compiled expression
392 * @op: operation index
393 *
394 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000395 */
396static void
397xmlXPathCompSwap(xmlXPathStepOpPtr op) {
398 int tmp;
399
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000400#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000401 /*
402 * Since this manipulates possibly shared variables, this is
403 * disable if one detects that the library is used in a multithreaded
404 * application
405 */
406 if (xmlXPathDisableOptimizer)
407 return;
408#endif
409
Daniel Veillardf06307e2001-07-03 10:35:50 +0000410 tmp = op->ch1;
411 op->ch1 = op->ch2;
412 op->ch2 = tmp;
413}
414
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000415#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
416 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
417 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000418#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
419 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
420 (op), (val), (val2), (val3), (val4), (val5))
421
422#define PUSH_LEAVE_EXPR(op, val, val2) \
423xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
424
425#define PUSH_UNARY_EXPR(op, ch, val, val2) \
426xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
427
428#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
429xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
430
431/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000432 * *
433 * Debugging related functions *
434 * *
435 ************************************************************************/
436
437#define TODO \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Unimplemented block at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#define STRANGE \
443 xmlGenericError(xmlGenericErrorContext, \
444 "Internal error at %s:%d\n", \
445 __FILE__, __LINE__);
446
447#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000448static void
449xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000450 int i;
451 char shift[100];
452
453 for (i = 0;((i < depth) && (i < 25));i++)
454 shift[2 * i] = shift[2 * i + 1] = ' ';
455 shift[2 * i] = shift[2 * i + 1] = 0;
456 if (cur == NULL) {
457 fprintf(output, shift);
458 fprintf(output, "Node is NULL !\n");
459 return;
460
461 }
462
463 if ((cur->type == XML_DOCUMENT_NODE) ||
464 (cur->type == XML_HTML_DOCUMENT_NODE)) {
465 fprintf(output, shift);
466 fprintf(output, " /\n");
467 } else if (cur->type == XML_ATTRIBUTE_NODE)
468 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
469 else
470 xmlDebugDumpOneNode(output, cur, depth);
471}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000472static void
473xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000474 xmlNodePtr tmp;
475 int i;
476 char shift[100];
477
478 for (i = 0;((i < depth) && (i < 25));i++)
479 shift[2 * i] = shift[2 * i + 1] = ' ';
480 shift[2 * i] = shift[2 * i + 1] = 0;
481 if (cur == NULL) {
482 fprintf(output, shift);
483 fprintf(output, "Node is NULL !\n");
484 return;
485
486 }
487
488 while (cur != NULL) {
489 tmp = cur;
490 cur = cur->next;
491 xmlDebugDumpOneNode(output, tmp, depth);
492 }
493}
Owen Taylor3473f882001-02-23 17:55:21 +0000494
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000495static void
496xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000497 int i;
498 char shift[100];
499
500 for (i = 0;((i < depth) && (i < 25));i++)
501 shift[2 * i] = shift[2 * i + 1] = ' ';
502 shift[2 * i] = shift[2 * i + 1] = 0;
503
504 if (cur == NULL) {
505 fprintf(output, shift);
506 fprintf(output, "NodeSet is NULL !\n");
507 return;
508
509 }
510
Daniel Veillard911f49a2001-04-07 15:39:35 +0000511 if (cur != NULL) {
512 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
513 for (i = 0;i < cur->nodeNr;i++) {
514 fprintf(output, shift);
515 fprintf(output, "%d", i + 1);
516 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
517 }
Owen Taylor3473f882001-02-23 17:55:21 +0000518 }
519}
520
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000521static void
522xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000523 int i;
524 char shift[100];
525
526 for (i = 0;((i < depth) && (i < 25));i++)
527 shift[2 * i] = shift[2 * i + 1] = ' ';
528 shift[2 * i] = shift[2 * i + 1] = 0;
529
530 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
531 fprintf(output, shift);
532 fprintf(output, "Value Tree is NULL !\n");
533 return;
534
535 }
536
537 fprintf(output, shift);
538 fprintf(output, "%d", i + 1);
539 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
540}
Owen Taylor3473f882001-02-23 17:55:21 +0000541#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000542static void
543xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000544 int i;
545 char shift[100];
546
547 for (i = 0;((i < depth) && (i < 25));i++)
548 shift[2 * i] = shift[2 * i + 1] = ' ';
549 shift[2 * i] = shift[2 * i + 1] = 0;
550
551 if (cur == NULL) {
552 fprintf(output, shift);
553 fprintf(output, "LocationSet is NULL !\n");
554 return;
555
556 }
557
558 for (i = 0;i < cur->locNr;i++) {
559 fprintf(output, shift);
560 fprintf(output, "%d : ", i + 1);
561 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
562 }
563}
Daniel Veillard017b1082001-06-21 11:20:21 +0000564#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000565
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000566/**
567 * xmlXPathDebugDumpObject:
568 * @output: the FILE * to dump the output
569 * @cur: the object to inspect
570 * @depth: indentation level
571 *
572 * Dump the content of the object for debugging purposes
573 */
574void
575xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000576 int i;
577 char shift[100];
578
579 for (i = 0;((i < depth) && (i < 25));i++)
580 shift[2 * i] = shift[2 * i + 1] = ' ';
581 shift[2 * i] = shift[2 * i + 1] = 0;
582
583 fprintf(output, shift);
584
585 if (cur == NULL) {
586 fprintf(output, "Object is empty (NULL)\n");
587 return;
588 }
589 switch(cur->type) {
590 case XPATH_UNDEFINED:
591 fprintf(output, "Object is uninitialized\n");
592 break;
593 case XPATH_NODESET:
594 fprintf(output, "Object is a Node Set :\n");
595 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
596 break;
597 case XPATH_XSLT_TREE:
598 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000599 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000600 break;
601 case XPATH_BOOLEAN:
602 fprintf(output, "Object is a Boolean : ");
603 if (cur->boolval) fprintf(output, "true\n");
604 else fprintf(output, "false\n");
605 break;
606 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000607 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000608 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000609 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000610 break;
611 case -1:
612 fprintf(output, "Object is a number : -Infinity\n");
613 break;
614 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000615 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000616 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000617 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
618 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000619 } else {
620 fprintf(output, "Object is a number : %0g\n", cur->floatval);
621 }
622 }
Owen Taylor3473f882001-02-23 17:55:21 +0000623 break;
624 case XPATH_STRING:
625 fprintf(output, "Object is a string : ");
626 xmlDebugDumpString(output, cur->stringval);
627 fprintf(output, "\n");
628 break;
629 case XPATH_POINT:
630 fprintf(output, "Object is a point : index %d in node", cur->index);
631 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
632 fprintf(output, "\n");
633 break;
634 case XPATH_RANGE:
635 if ((cur->user2 == NULL) ||
636 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
637 fprintf(output, "Object is a collapsed range :\n");
638 fprintf(output, shift);
639 if (cur->index >= 0)
640 fprintf(output, "index %d in ", cur->index);
641 fprintf(output, "node\n");
642 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
643 depth + 1);
644 } else {
645 fprintf(output, "Object is a range :\n");
646 fprintf(output, shift);
647 fprintf(output, "From ");
648 if (cur->index >= 0)
649 fprintf(output, "index %d in ", cur->index);
650 fprintf(output, "node\n");
651 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
652 depth + 1);
653 fprintf(output, shift);
654 fprintf(output, "To ");
655 if (cur->index2 >= 0)
656 fprintf(output, "index %d in ", cur->index2);
657 fprintf(output, "node\n");
658 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
659 depth + 1);
660 fprintf(output, "\n");
661 }
662 break;
663 case XPATH_LOCATIONSET:
664#if defined(LIBXML_XPTR_ENABLED)
665 fprintf(output, "Object is a Location Set:\n");
666 xmlXPathDebugDumpLocationSet(output,
667 (xmlLocationSetPtr) cur->user, depth);
668#endif
669 break;
670 case XPATH_USERS:
671 fprintf(output, "Object is user defined\n");
672 break;
673 }
674}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000675
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000676static void
677xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000678 xmlXPathStepOpPtr op, int depth) {
679 int i;
680 char shift[100];
681
682 for (i = 0;((i < depth) && (i < 25));i++)
683 shift[2 * i] = shift[2 * i + 1] = ' ';
684 shift[2 * i] = shift[2 * i + 1] = 0;
685
686 fprintf(output, shift);
687 if (op == NULL) {
688 fprintf(output, "Step is NULL\n");
689 return;
690 }
691 switch (op->op) {
692 case XPATH_OP_END:
693 fprintf(output, "END"); break;
694 case XPATH_OP_AND:
695 fprintf(output, "AND"); break;
696 case XPATH_OP_OR:
697 fprintf(output, "OR"); break;
698 case XPATH_OP_EQUAL:
699 if (op->value)
700 fprintf(output, "EQUAL =");
701 else
702 fprintf(output, "EQUAL !=");
703 break;
704 case XPATH_OP_CMP:
705 if (op->value)
706 fprintf(output, "CMP <");
707 else
708 fprintf(output, "CMP >");
709 if (!op->value2)
710 fprintf(output, "=");
711 break;
712 case XPATH_OP_PLUS:
713 if (op->value == 0)
714 fprintf(output, "PLUS -");
715 else if (op->value == 1)
716 fprintf(output, "PLUS +");
717 else if (op->value == 2)
718 fprintf(output, "PLUS unary -");
719 else if (op->value == 3)
720 fprintf(output, "PLUS unary - -");
721 break;
722 case XPATH_OP_MULT:
723 if (op->value == 0)
724 fprintf(output, "MULT *");
725 else if (op->value == 1)
726 fprintf(output, "MULT div");
727 else
728 fprintf(output, "MULT mod");
729 break;
730 case XPATH_OP_UNION:
731 fprintf(output, "UNION"); break;
732 case XPATH_OP_ROOT:
733 fprintf(output, "ROOT"); break;
734 case XPATH_OP_NODE:
735 fprintf(output, "NODE"); break;
736 case XPATH_OP_RESET:
737 fprintf(output, "RESET"); break;
738 case XPATH_OP_SORT:
739 fprintf(output, "SORT"); break;
740 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000741 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
742 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
743 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000744 const xmlChar *prefix = op->value4;
745 const xmlChar *name = op->value5;
746
747 fprintf(output, "COLLECT ");
748 switch (axis) {
749 case AXIS_ANCESTOR:
750 fprintf(output, " 'ancestors' "); break;
751 case AXIS_ANCESTOR_OR_SELF:
752 fprintf(output, " 'ancestors-or-self' "); break;
753 case AXIS_ATTRIBUTE:
754 fprintf(output, " 'attributes' "); break;
755 case AXIS_CHILD:
756 fprintf(output, " 'child' "); break;
757 case AXIS_DESCENDANT:
758 fprintf(output, " 'descendant' "); break;
759 case AXIS_DESCENDANT_OR_SELF:
760 fprintf(output, " 'descendant-or-self' "); break;
761 case AXIS_FOLLOWING:
762 fprintf(output, " 'following' "); break;
763 case AXIS_FOLLOWING_SIBLING:
764 fprintf(output, " 'following-siblings' "); break;
765 case AXIS_NAMESPACE:
766 fprintf(output, " 'namespace' "); break;
767 case AXIS_PARENT:
768 fprintf(output, " 'parent' "); break;
769 case AXIS_PRECEDING:
770 fprintf(output, " 'preceding' "); break;
771 case AXIS_PRECEDING_SIBLING:
772 fprintf(output, " 'preceding-sibling' "); break;
773 case AXIS_SELF:
774 fprintf(output, " 'self' "); break;
775 }
776 switch (test) {
777 case NODE_TEST_NONE:
778 fprintf(output, "'none' "); break;
779 case NODE_TEST_TYPE:
780 fprintf(output, "'type' "); break;
781 case NODE_TEST_PI:
782 fprintf(output, "'PI' "); break;
783 case NODE_TEST_ALL:
784 fprintf(output, "'all' "); break;
785 case NODE_TEST_NS:
786 fprintf(output, "'namespace' "); break;
787 case NODE_TEST_NAME:
788 fprintf(output, "'name' "); break;
789 }
790 switch (type) {
791 case NODE_TYPE_NODE:
792 fprintf(output, "'node' "); break;
793 case NODE_TYPE_COMMENT:
794 fprintf(output, "'comment' "); break;
795 case NODE_TYPE_TEXT:
796 fprintf(output, "'text' "); break;
797 case NODE_TYPE_PI:
798 fprintf(output, "'PI' "); break;
799 }
800 if (prefix != NULL)
801 fprintf(output, "%s:", prefix);
802 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000803 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000804 break;
805
806 }
807 case XPATH_OP_VALUE: {
808 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
809
810 fprintf(output, "ELEM ");
811 xmlXPathDebugDumpObject(output, object, 0);
812 goto finish;
813 }
814 case XPATH_OP_VARIABLE: {
815 const xmlChar *prefix = op->value5;
816 const xmlChar *name = op->value4;
817
818 if (prefix != NULL)
819 fprintf(output, "VARIABLE %s:%s", prefix, name);
820 else
821 fprintf(output, "VARIABLE %s", name);
822 break;
823 }
824 case XPATH_OP_FUNCTION: {
825 int nbargs = op->value;
826 const xmlChar *prefix = op->value5;
827 const xmlChar *name = op->value4;
828
829 if (prefix != NULL)
830 fprintf(output, "FUNCTION %s:%s(%d args)",
831 prefix, name, nbargs);
832 else
833 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
834 break;
835 }
836 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
837 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000838 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000839#ifdef LIBXML_XPTR_ENABLED
840 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
841#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000842 default:
843 fprintf(output, "UNKNOWN %d\n", op->op); return;
844 }
845 fprintf(output, "\n");
846finish:
847 if (op->ch1 >= 0)
848 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
849 if (op->ch2 >= 0)
850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
851}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000852
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000853/**
854 * xmlXPathDebugDumpCompExpr:
855 * @output: the FILE * for the output
856 * @comp: the precompiled XPath expression
857 * @depth: the indentation level.
858 *
859 * Dumps the tree of the compiled XPath expression.
860 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000861void
862xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
863 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000864 int i;
865 char shift[100];
866
867 for (i = 0;((i < depth) && (i < 25));i++)
868 shift[2 * i] = shift[2 * i + 1] = ' ';
869 shift[2 * i] = shift[2 * i + 1] = 0;
870
871 fprintf(output, shift);
872
873 if (comp == NULL) {
874 fprintf(output, "Compiled Expression is NULL\n");
875 return;
876 }
877 fprintf(output, "Compiled Expression : %d elements\n",
878 comp->nbStep);
879 i = comp->last;
880 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
881}
Daniel Veillard017b1082001-06-21 11:20:21 +0000882#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000883
884/************************************************************************
885 * *
886 * Parser stacks related functions and macros *
887 * *
888 ************************************************************************/
889
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000890/**
891 * valuePop:
892 * @ctxt: an XPath evaluation context
893 *
894 * Pops the top XPath object from the value stack
895 *
896 * Returns the XPath object just removed
897 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000898extern xmlXPathObjectPtr
899valuePop(xmlXPathParserContextPtr ctxt)
900{
901 xmlXPathObjectPtr ret;
902
903 if (ctxt->valueNr <= 0)
904 return (0);
905 ctxt->valueNr--;
906 if (ctxt->valueNr > 0)
907 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
908 else
909 ctxt->value = NULL;
910 ret = ctxt->valueTab[ctxt->valueNr];
911 ctxt->valueTab[ctxt->valueNr] = 0;
912 return (ret);
913}
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000914/**
915 * valuePush:
916 * @ctxt: an XPath evaluation context
917 * @value: the XPath object
918 *
919 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000920 *
921 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000922 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000923extern int
924valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
925{
926 if (ctxt->valueNr >= ctxt->valueMax) {
927 ctxt->valueMax *= 2;
928 ctxt->valueTab =
929 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
930 ctxt->valueMax *
931 sizeof(ctxt->valueTab[0]));
932 if (ctxt->valueTab == NULL) {
933 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
934 return (0);
935 }
936 }
937 ctxt->valueTab[ctxt->valueNr] = value;
938 ctxt->value = value;
939 return (ctxt->valueNr++);
940}
Owen Taylor3473f882001-02-23 17:55:21 +0000941
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000942/**
943 * xmlXPathPopBoolean:
944 * @ctxt: an XPath parser context
945 *
946 * Pops a boolean from the stack, handling conversion if needed.
947 * Check error with #xmlXPathCheckError.
948 *
949 * Returns the boolean
950 */
951int
952xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
953 xmlXPathObjectPtr obj;
954 int ret;
955
956 obj = valuePop(ctxt);
957 if (obj == NULL) {
958 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
959 return(0);
960 }
961 ret = xmlXPathCastToBoolean(obj);
962 xmlXPathFreeObject(obj);
963 return(ret);
964}
965
966/**
967 * xmlXPathPopNumber:
968 * @ctxt: an XPath parser context
969 *
970 * Pops a number from the stack, handling conversion if needed.
971 * Check error with #xmlXPathCheckError.
972 *
973 * Returns the number
974 */
975double
976xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
977 xmlXPathObjectPtr obj;
978 double ret;
979
980 obj = valuePop(ctxt);
981 if (obj == NULL) {
982 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
983 return(0);
984 }
985 ret = xmlXPathCastToNumber(obj);
986 xmlXPathFreeObject(obj);
987 return(ret);
988}
989
990/**
991 * xmlXPathPopString:
992 * @ctxt: an XPath parser context
993 *
994 * Pops a string from the stack, handling conversion if needed.
995 * Check error with #xmlXPathCheckError.
996 *
997 * Returns the string
998 */
999xmlChar *
1000xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1001 xmlXPathObjectPtr obj;
1002 xmlChar * ret;
1003
1004 obj = valuePop(ctxt);
1005 if (obj == NULL) {
1006 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1007 return(NULL);
1008 }
1009 ret = xmlXPathCastToString(obj);
1010 /* TODO: needs refactoring somewhere else */
1011 if (obj->stringval == ret)
1012 obj->stringval = NULL;
1013 xmlXPathFreeObject(obj);
1014 return(ret);
1015}
1016
1017/**
1018 * xmlXPathPopNodeSet:
1019 * @ctxt: an XPath parser context
1020 *
1021 * Pops a node-set from the stack, handling conversion if needed.
1022 * Check error with #xmlXPathCheckError.
1023 *
1024 * Returns the node-set
1025 */
1026xmlNodeSetPtr
1027xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1028 xmlXPathObjectPtr obj;
1029 xmlNodeSetPtr ret;
1030
1031 if (ctxt->value == NULL) {
1032 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1033 return(NULL);
1034 }
1035 if (!xmlXPathStackIsNodeSet(ctxt)) {
1036 xmlXPathSetTypeError(ctxt);
1037 return(NULL);
1038 }
1039 obj = valuePop(ctxt);
1040 ret = obj->nodesetval;
Daniel Veillard9deb2422003-07-28 20:40:59 +00001041 /* to fix memory leak of not clearing obj->user */
1042 if (obj->boolval && obj->user != NULL)
1043 xmlFreeNodeList((xmlNodePtr) obj->user);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001044 xmlXPathFreeNodeSetList(obj);
1045 return(ret);
1046}
1047
1048/**
1049 * xmlXPathPopExternal:
1050 * @ctxt: an XPath parser context
1051 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001052 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001053 * Check error with #xmlXPathCheckError.
1054 *
1055 * Returns the object
1056 */
1057void *
1058xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1059 xmlXPathObjectPtr obj;
1060 void * ret;
1061
1062 if (ctxt->value == NULL) {
1063 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1064 return(NULL);
1065 }
1066 if (ctxt->value->type != XPATH_USERS) {
1067 xmlXPathSetTypeError(ctxt);
1068 return(NULL);
1069 }
1070 obj = valuePop(ctxt);
1071 ret = obj->user;
1072 xmlXPathFreeObject(obj);
1073 return(ret);
1074}
1075
Owen Taylor3473f882001-02-23 17:55:21 +00001076/*
1077 * Macros for accessing the content. Those should be used only by the parser,
1078 * and not exported.
1079 *
1080 * Dirty macros, i.e. one need to make assumption on the context to use them
1081 *
1082 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1083 * CUR returns the current xmlChar value, i.e. a 8 bit value
1084 * in ISO-Latin or UTF-8.
1085 * This should be used internally by the parser
1086 * only to compare to ASCII values otherwise it would break when
1087 * running with UTF-8 encoding.
1088 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1089 * to compare on ASCII based substring.
1090 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1091 * strings within the parser.
1092 * CURRENT Returns the current char value, with the full decoding of
1093 * UTF-8 if we are using this mode. It returns an int.
1094 * NEXT Skip to the next character, this does the proper decoding
1095 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1096 * It returns the pointer to the current xmlChar.
1097 */
1098
1099#define CUR (*ctxt->cur)
1100#define SKIP(val) ctxt->cur += (val)
1101#define NXT(val) ctxt->cur[(val)]
1102#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001103#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1104
1105#define COPY_BUF(l,b,i,v) \
1106 if (l == 1) b[i++] = (xmlChar) v; \
1107 else i += xmlCopyChar(l,&b[i],v)
1108
1109#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001110
1111#define SKIP_BLANKS \
1112 while (IS_BLANK(*(ctxt->cur))) NEXT
1113
1114#define CURRENT (*ctxt->cur)
1115#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1116
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001117
1118#ifndef DBL_DIG
1119#define DBL_DIG 16
1120#endif
1121#ifndef DBL_EPSILON
1122#define DBL_EPSILON 1E-9
1123#endif
1124
1125#define UPPER_DOUBLE 1E9
1126#define LOWER_DOUBLE 1E-5
1127
1128#define INTEGER_DIGITS DBL_DIG
1129#define FRACTION_DIGITS (DBL_DIG + 1)
1130#define EXPONENT_DIGITS (3 + 2)
1131
1132/**
1133 * xmlXPathFormatNumber:
1134 * @number: number to format
1135 * @buffer: output buffer
1136 * @buffersize: size of output buffer
1137 *
1138 * Convert the number into a string representation.
1139 */
1140static void
1141xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1142{
Daniel Veillardcda96922001-08-21 10:56:31 +00001143 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001144 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001145 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001146 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001147 break;
1148 case -1:
1149 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001150 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001151 break;
1152 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001153 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001154 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001155 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001156 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001157 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001158 } else if (number == ((int) number)) {
1159 char work[30];
1160 char *ptr, *cur;
1161 int res, value = (int) number;
1162
1163 ptr = &buffer[0];
1164 if (value < 0) {
1165 *ptr++ = '-';
1166 value = -value;
1167 }
1168 if (value == 0) {
1169 *ptr++ = '0';
1170 } else {
1171 cur = &work[0];
1172 while (value != 0) {
1173 res = value % 10;
1174 value = value / 10;
1175 *cur++ = '0' + res;
1176 }
1177 cur--;
1178 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1179 *ptr++ = *cur--;
1180 }
1181 }
1182 if (ptr - buffer < buffersize) {
1183 *ptr = 0;
1184 } else if (buffersize > 0) {
1185 ptr--;
1186 *ptr = 0;
1187 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001188 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001189 /* 3 is sign, decimal point, and terminating zero */
1190 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1191 int integer_place, fraction_place;
1192 char *ptr;
1193 char *after_fraction;
1194 double absolute_value;
1195 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001196
Bjorn Reese70a9da52001-04-21 16:57:29 +00001197 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001198
Bjorn Reese70a9da52001-04-21 16:57:29 +00001199 /*
1200 * First choose format - scientific or regular floating point.
1201 * In either case, result is in work, and after_fraction points
1202 * just past the fractional part.
1203 */
1204 if ( ((absolute_value > UPPER_DOUBLE) ||
1205 (absolute_value < LOWER_DOUBLE)) &&
1206 (absolute_value != 0.0) ) {
1207 /* Use scientific notation */
1208 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1209 fraction_place = DBL_DIG - 1;
1210 snprintf(work, sizeof(work),"%*.*e",
1211 integer_place, fraction_place, number);
1212 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001213 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001214 else {
1215 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001216 if (absolute_value > 0.0)
1217 integer_place = 1 + (int)log10(absolute_value);
1218 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001219 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001220 fraction_place = (integer_place > 0)
1221 ? DBL_DIG - integer_place
1222 : DBL_DIG;
1223 size = snprintf(work, sizeof(work), "%0.*f",
1224 fraction_place, number);
1225 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001226 }
1227
Bjorn Reese70a9da52001-04-21 16:57:29 +00001228 /* Remove fractional trailing zeroes */
1229 ptr = after_fraction;
1230 while (*(--ptr) == '0')
1231 ;
1232 if (*ptr != '.')
1233 ptr++;
1234 strcpy(ptr, after_fraction);
1235
1236 /* Finally copy result back to caller */
1237 size = strlen(work) + 1;
1238 if (size > buffersize) {
1239 work[buffersize - 1] = 0;
1240 size = buffersize;
1241 }
1242 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001243 }
1244 break;
1245 }
1246}
1247
Owen Taylor3473f882001-02-23 17:55:21 +00001248/************************************************************************
1249 * *
1250 * Error handling routines *
1251 * *
1252 ************************************************************************/
1253
1254
Daniel Veillardb44025c2001-10-11 22:55:55 +00001255static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001256 "Ok",
1257 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001258 "Unfinished literal",
1259 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001260 "Expected $ for variable reference",
1261 "Undefined variable",
1262 "Invalid predicate",
1263 "Invalid expression",
1264 "Missing closing curly brace",
1265 "Unregistered function",
1266 "Invalid operand",
1267 "Invalid type",
1268 "Invalid number of arguments",
1269 "Invalid context size",
1270 "Invalid context position",
1271 "Memory allocation error",
1272 "Syntax error",
1273 "Resource error",
1274 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001275 "Undefined namespace prefix",
1276 "Encoding error",
1277 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001278};
1279
1280/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001281 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001282 * @ctxt: the XPath Parser context
1283 * @file: the file name
1284 * @line: the line number
1285 * @no: the error number
1286 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001287 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001288 */
1289void
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001290xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1291 int line ATTRIBUTE_UNUSED, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001292 int n;
1293 const xmlChar *cur;
1294 const xmlChar *base;
1295
Owen Taylor3473f882001-02-23 17:55:21 +00001296 cur = ctxt->cur;
1297 base = ctxt->base;
Daniel Veillard118aed72002-09-24 14:13:13 +00001298 if ((cur == NULL) || (base == NULL)) {
1299 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1300 xmlGenericError(xmlGenericErrorContext,
1301 "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1302 ctxt->comp->expr);
1303 } else {
1304 xmlGenericError(xmlGenericErrorContext,
1305 "XPath error %s\n", xmlXPathErrorMessages[no]);
1306 }
1307
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001308 return;
Daniel Veillard118aed72002-09-24 14:13:13 +00001309 }
1310 xmlGenericError(xmlGenericErrorContext,
1311 "XPath error %s\n", xmlXPathErrorMessages[no]);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001312
Owen Taylor3473f882001-02-23 17:55:21 +00001313 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1314 cur--;
1315 }
1316 n = 0;
1317 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1318 cur--;
1319 if ((*cur == '\n') || (*cur == '\r')) cur++;
1320 base = cur;
1321 n = 0;
1322 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1323 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1324 n++;
1325 }
1326 xmlGenericError(xmlGenericErrorContext, "\n");
1327 cur = ctxt->cur;
1328 while ((*cur == '\n') || (*cur == '\r'))
1329 cur--;
1330 n = 0;
1331 while ((cur != base) && (n++ < 80)) {
1332 xmlGenericError(xmlGenericErrorContext, " ");
1333 base++;
1334 }
1335 xmlGenericError(xmlGenericErrorContext,"^\n");
1336}
1337
1338
1339/************************************************************************
1340 * *
1341 * Routines to handle NodeSets *
1342 * *
1343 ************************************************************************/
1344
1345/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001346 * xmlXPathOrderDocElems:
1347 * @doc: an input document
1348 *
1349 * Call this routine to speed up XPath computation on static documents.
1350 * This stamps all the element nodes with the document order
1351 * Like for line information, the order is kept in the element->content
1352 * field, the value stored is actually - the node number (startting at -1)
1353 * to be able to differenciate from line numbers.
1354 *
1355 * Returns the number of element found in the document or -1 in case
1356 * of error.
1357 */
1358long
1359xmlXPathOrderDocElems(xmlDocPtr doc) {
1360 long count = 0;
1361 xmlNodePtr cur;
1362
1363 if (doc == NULL)
1364 return(-1);
1365 cur = doc->children;
1366 while (cur != NULL) {
1367 if (cur->type == XML_ELEMENT_NODE) {
1368 cur->content = (void *) (-(++count));
1369 if (cur->children != NULL) {
1370 cur = cur->children;
1371 continue;
1372 }
1373 }
1374 if (cur->next != NULL) {
1375 cur = cur->next;
1376 continue;
1377 }
1378 do {
1379 cur = cur->parent;
1380 if (cur == NULL)
1381 break;
1382 if (cur == (xmlNodePtr) doc) {
1383 cur = NULL;
1384 break;
1385 }
1386 if (cur->next != NULL) {
1387 cur = cur->next;
1388 break;
1389 }
1390 } while (cur != NULL);
1391 }
1392 return(count);
1393}
1394
1395/**
Owen Taylor3473f882001-02-23 17:55:21 +00001396 * xmlXPathCmpNodes:
1397 * @node1: the first node
1398 * @node2: the second node
1399 *
1400 * Compare two nodes w.r.t document order
1401 *
1402 * Returns -2 in case of error 1 if first point < second point, 0 if
1403 * that's the same node, -1 otherwise
1404 */
1405int
1406xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1407 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001408 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001409 xmlNodePtr cur, root;
1410
1411 if ((node1 == NULL) || (node2 == NULL))
1412 return(-2);
1413 /*
1414 * a couple of optimizations which will avoid computations in most cases
1415 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001416 if (node1->type == XML_ATTRIBUTE_NODE) {
1417 attr1 = 1;
1418 node1 = node1->parent;
1419 }
1420 if (node2->type == XML_ATTRIBUTE_NODE) {
1421 attr2 = 1;
1422 node2 = node2->parent;
1423 }
1424 if (node1 == node2) {
1425 if (attr1 == attr2)
1426 return(0);
1427 if (attr2 == 1)
1428 return(1);
1429 return(-1);
1430 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001431 if ((node1->type == XML_NAMESPACE_DECL) ||
1432 (node2->type == XML_NAMESPACE_DECL))
1433 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001434 if (node1 == node2->prev)
1435 return(1);
1436 if (node1 == node2->next)
1437 return(-1);
1438
1439 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001440 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001441 */
1442 if ((node1->type == XML_ELEMENT_NODE) &&
1443 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001444 (0 > (long) node1->content) &&
1445 (0 > (long) node2->content) &&
1446 (node1->doc == node2->doc)) {
1447 long l1, l2;
1448
1449 l1 = -((long) node1->content);
1450 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001451 if (l1 < l2)
1452 return(1);
1453 if (l1 > l2)
1454 return(-1);
1455 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001456
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001457 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001458 * compute depth to root
1459 */
1460 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1461 if (cur == node1)
1462 return(1);
1463 depth2++;
1464 }
1465 root = cur;
1466 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1467 if (cur == node2)
1468 return(-1);
1469 depth1++;
1470 }
1471 /*
1472 * Distinct document (or distinct entities :-( ) case.
1473 */
1474 if (root != cur) {
1475 return(-2);
1476 }
1477 /*
1478 * get the nearest common ancestor.
1479 */
1480 while (depth1 > depth2) {
1481 depth1--;
1482 node1 = node1->parent;
1483 }
1484 while (depth2 > depth1) {
1485 depth2--;
1486 node2 = node2->parent;
1487 }
1488 while (node1->parent != node2->parent) {
1489 node1 = node1->parent;
1490 node2 = node2->parent;
1491 /* should not happen but just in case ... */
1492 if ((node1 == NULL) || (node2 == NULL))
1493 return(-2);
1494 }
1495 /*
1496 * Find who's first.
1497 */
1498 if (node1 == node2->next)
1499 return(-1);
1500 for (cur = node1->next;cur != NULL;cur = cur->next)
1501 if (cur == node2)
1502 return(1);
1503 return(-1); /* assume there is no sibling list corruption */
1504}
1505
1506/**
1507 * xmlXPathNodeSetSort:
1508 * @set: the node set
1509 *
1510 * Sort the node set in document order
1511 */
1512void
1513xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001514 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001515 xmlNodePtr tmp;
1516
1517 if (set == NULL)
1518 return;
1519
1520 /* Use Shell's sort to sort the node-set */
1521 len = set->nodeNr;
1522 for (incr = len / 2; incr > 0; incr /= 2) {
1523 for (i = incr; i < len; i++) {
1524 j = i - incr;
1525 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001526 if (xmlXPathCmpNodes(set->nodeTab[j],
1527 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001528 tmp = set->nodeTab[j];
1529 set->nodeTab[j] = set->nodeTab[j + incr];
1530 set->nodeTab[j + incr] = tmp;
1531 j -= incr;
1532 } else
1533 break;
1534 }
1535 }
1536 }
1537}
1538
1539#define XML_NODESET_DEFAULT 10
1540/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001541 * xmlXPathNodeSetDupNs:
1542 * @node: the parent node of the namespace XPath node
1543 * @ns: the libxml namespace declaration node.
1544 *
1545 * Namespace node in libxml don't match the XPath semantic. In a node set
1546 * the namespace nodes are duplicated and the next pointer is set to the
1547 * parent node in the XPath semantic.
1548 *
1549 * Returns the newly created object.
1550 */
1551static xmlNodePtr
1552xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1553 xmlNsPtr cur;
1554
1555 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1556 return(NULL);
1557 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1558 return((xmlNodePtr) ns);
1559
1560 /*
1561 * Allocate a new Namespace and fill the fields.
1562 */
1563 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1564 if (cur == NULL) {
1565 xmlGenericError(xmlGenericErrorContext,
1566 "xmlXPathNodeSetDupNs : malloc failed\n");
1567 return(NULL);
1568 }
1569 memset(cur, 0, sizeof(xmlNs));
1570 cur->type = XML_NAMESPACE_DECL;
1571 if (ns->href != NULL)
1572 cur->href = xmlStrdup(ns->href);
1573 if (ns->prefix != NULL)
1574 cur->prefix = xmlStrdup(ns->prefix);
1575 cur->next = (xmlNsPtr) node;
1576 return((xmlNodePtr) cur);
1577}
1578
1579/**
1580 * xmlXPathNodeSetFreeNs:
1581 * @ns: the XPath namespace node found in a nodeset.
1582 *
1583 * Namespace node in libxml don't match the XPath semantic. In a node set
1584 * the namespace nodes are duplicated and the next pointer is set to the
1585 * parent node in the XPath semantic. Check if such a node need to be freed
1586 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001587void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001588xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1589 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1590 return;
1591
1592 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1593 if (ns->href != NULL)
1594 xmlFree((xmlChar *)ns->href);
1595 if (ns->prefix != NULL)
1596 xmlFree((xmlChar *)ns->prefix);
1597 xmlFree(ns);
1598 }
1599}
1600
1601/**
Owen Taylor3473f882001-02-23 17:55:21 +00001602 * xmlXPathNodeSetCreate:
1603 * @val: an initial xmlNodePtr, or NULL
1604 *
1605 * Create a new xmlNodeSetPtr of type double and of value @val
1606 *
1607 * Returns the newly created object.
1608 */
1609xmlNodeSetPtr
1610xmlXPathNodeSetCreate(xmlNodePtr val) {
1611 xmlNodeSetPtr ret;
1612
1613 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1614 if (ret == NULL) {
1615 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001616 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001617 return(NULL);
1618 }
1619 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1620 if (val != NULL) {
1621 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1622 sizeof(xmlNodePtr));
1623 if (ret->nodeTab == NULL) {
1624 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001625 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001626 return(NULL);
1627 }
1628 memset(ret->nodeTab, 0 ,
1629 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1630 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001631 if (val->type == XML_NAMESPACE_DECL) {
1632 xmlNsPtr ns = (xmlNsPtr) val;
1633
1634 ret->nodeTab[ret->nodeNr++] =
1635 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1636 } else
1637 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001638 }
1639 return(ret);
1640}
1641
1642/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001643 * xmlXPathNodeSetContains:
1644 * @cur: the node-set
1645 * @val: the node
1646 *
1647 * checks whether @cur contains @val
1648 *
1649 * Returns true (1) if @cur contains @val, false (0) otherwise
1650 */
1651int
1652xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1653 int i;
1654
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001655 if (val->type == XML_NAMESPACE_DECL) {
1656 for (i = 0; i < cur->nodeNr; i++) {
1657 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1658 xmlNsPtr ns1, ns2;
1659
1660 ns1 = (xmlNsPtr) val;
1661 ns2 = (xmlNsPtr) cur->nodeTab[i];
1662 if (ns1 == ns2)
1663 return(1);
1664 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1665 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1666 return(1);
1667 }
1668 }
1669 } else {
1670 for (i = 0; i < cur->nodeNr; i++) {
1671 if (cur->nodeTab[i] == val)
1672 return(1);
1673 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001674 }
1675 return(0);
1676}
1677
1678/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001679 * xmlXPathNodeSetAddNs:
1680 * @cur: the initial node set
1681 * @node: the hosting node
1682 * @ns: a the namespace node
1683 *
1684 * add a new namespace node to an existing NodeSet
1685 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001686void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001687xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1688 int i;
1689
1690 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1691 (node->type != XML_ELEMENT_NODE))
1692 return;
1693
1694 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1695 /*
1696 * check against doublons
1697 */
1698 for (i = 0;i < cur->nodeNr;i++) {
1699 if ((cur->nodeTab[i] != NULL) &&
1700 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001701 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001702 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1703 return;
1704 }
1705
1706 /*
1707 * grow the nodeTab if needed
1708 */
1709 if (cur->nodeMax == 0) {
1710 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1711 sizeof(xmlNodePtr));
1712 if (cur->nodeTab == NULL) {
1713 xmlGenericError(xmlGenericErrorContext,
1714 "xmlXPathNodeSetAdd: out of memory\n");
1715 return;
1716 }
1717 memset(cur->nodeTab, 0 ,
1718 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1719 cur->nodeMax = XML_NODESET_DEFAULT;
1720 } else if (cur->nodeNr == cur->nodeMax) {
1721 xmlNodePtr *temp;
1722
1723 cur->nodeMax *= 2;
1724 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1725 sizeof(xmlNodePtr));
1726 if (temp == NULL) {
1727 xmlGenericError(xmlGenericErrorContext,
1728 "xmlXPathNodeSetAdd: out of memory\n");
1729 return;
1730 }
1731 cur->nodeTab = temp;
1732 }
1733 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1734}
1735
1736/**
Owen Taylor3473f882001-02-23 17:55:21 +00001737 * xmlXPathNodeSetAdd:
1738 * @cur: the initial node set
1739 * @val: a new xmlNodePtr
1740 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001741 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001742 */
1743void
1744xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1745 int i;
1746
1747 if (val == NULL) return;
1748
Daniel Veillardef0b4502003-03-24 13:57:34 +00001749#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001750 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1751 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001752#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001753
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001754 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001755 /*
1756 * check against doublons
1757 */
1758 for (i = 0;i < cur->nodeNr;i++)
1759 if (cur->nodeTab[i] == val) return;
1760
1761 /*
1762 * grow the nodeTab if needed
1763 */
1764 if (cur->nodeMax == 0) {
1765 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1766 sizeof(xmlNodePtr));
1767 if (cur->nodeTab == NULL) {
1768 xmlGenericError(xmlGenericErrorContext,
1769 "xmlXPathNodeSetAdd: out of memory\n");
1770 return;
1771 }
1772 memset(cur->nodeTab, 0 ,
1773 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1774 cur->nodeMax = XML_NODESET_DEFAULT;
1775 } else if (cur->nodeNr == cur->nodeMax) {
1776 xmlNodePtr *temp;
1777
1778 cur->nodeMax *= 2;
1779 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1780 sizeof(xmlNodePtr));
1781 if (temp == NULL) {
1782 xmlGenericError(xmlGenericErrorContext,
1783 "xmlXPathNodeSetAdd: out of memory\n");
1784 return;
1785 }
1786 cur->nodeTab = temp;
1787 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001788 if (val->type == XML_NAMESPACE_DECL) {
1789 xmlNsPtr ns = (xmlNsPtr) val;
1790
1791 cur->nodeTab[cur->nodeNr++] =
1792 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1793 } else
1794 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001795}
1796
1797/**
1798 * xmlXPathNodeSetAddUnique:
1799 * @cur: the initial node set
1800 * @val: a new xmlNodePtr
1801 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001802 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001803 * when we are sure the node is not already in the set.
1804 */
1805void
1806xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1807 if (val == NULL) return;
1808
Daniel Veillardef0b4502003-03-24 13:57:34 +00001809#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001810 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1811 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001812#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001813
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001814 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001815 /*
1816 * grow the nodeTab if needed
1817 */
1818 if (cur->nodeMax == 0) {
1819 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1820 sizeof(xmlNodePtr));
1821 if (cur->nodeTab == NULL) {
1822 xmlGenericError(xmlGenericErrorContext,
1823 "xmlXPathNodeSetAddUnique: out of memory\n");
1824 return;
1825 }
1826 memset(cur->nodeTab, 0 ,
1827 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1828 cur->nodeMax = XML_NODESET_DEFAULT;
1829 } else if (cur->nodeNr == cur->nodeMax) {
1830 xmlNodePtr *temp;
1831
1832 cur->nodeMax *= 2;
1833 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1834 sizeof(xmlNodePtr));
1835 if (temp == NULL) {
1836 xmlGenericError(xmlGenericErrorContext,
1837 "xmlXPathNodeSetAddUnique: out of memory\n");
1838 return;
1839 }
1840 cur->nodeTab = temp;
1841 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001842 if (val->type == XML_NAMESPACE_DECL) {
1843 xmlNsPtr ns = (xmlNsPtr) val;
1844
1845 cur->nodeTab[cur->nodeNr++] =
1846 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1847 } else
1848 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001849}
1850
1851/**
1852 * xmlXPathNodeSetMerge:
1853 * @val1: the first NodeSet or NULL
1854 * @val2: the second NodeSet
1855 *
1856 * Merges two nodesets, all nodes from @val2 are added to @val1
1857 * if @val1 is NULL, a new set is created and copied from @val2
1858 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001859 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001860 */
1861xmlNodeSetPtr
1862xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001863 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001864
1865 if (val2 == NULL) return(val1);
1866 if (val1 == NULL) {
1867 val1 = xmlXPathNodeSetCreate(NULL);
1868 }
1869
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001870 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001871 initNr = val1->nodeNr;
1872
1873 for (i = 0;i < val2->nodeNr;i++) {
1874 /*
1875 * check against doublons
1876 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001877 skip = 0;
1878 for (j = 0; j < initNr; j++) {
1879 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1880 skip = 1;
1881 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001882 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1883 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1884 xmlNsPtr ns1, ns2;
1885 ns1 = (xmlNsPtr) val1->nodeTab[j];
1886 ns2 = (xmlNsPtr) val2->nodeTab[i];
1887 if ((ns1->next == ns2->next) &&
1888 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1889 skip = 1;
1890 break;
1891 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001892 }
1893 }
1894 if (skip)
1895 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001896
1897 /*
1898 * grow the nodeTab if needed
1899 */
1900 if (val1->nodeMax == 0) {
1901 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1902 sizeof(xmlNodePtr));
1903 if (val1->nodeTab == NULL) {
1904 xmlGenericError(xmlGenericErrorContext,
1905 "xmlXPathNodeSetMerge: out of memory\n");
1906 return(NULL);
1907 }
1908 memset(val1->nodeTab, 0 ,
1909 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1910 val1->nodeMax = XML_NODESET_DEFAULT;
1911 } else if (val1->nodeNr == val1->nodeMax) {
1912 xmlNodePtr *temp;
1913
1914 val1->nodeMax *= 2;
1915 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1916 sizeof(xmlNodePtr));
1917 if (temp == NULL) {
1918 xmlGenericError(xmlGenericErrorContext,
1919 "xmlXPathNodeSetMerge: out of memory\n");
1920 return(NULL);
1921 }
1922 val1->nodeTab = temp;
1923 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001924 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1925 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1926
1927 val1->nodeTab[val1->nodeNr++] =
1928 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1929 } else
1930 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001931 }
1932
1933 return(val1);
1934}
1935
1936/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001937 * xmlXPathNodeSetMergeUnique:
1938 * @val1: the first NodeSet or NULL
1939 * @val2: the second NodeSet
1940 *
1941 * Merges two nodesets, all nodes from @val2 are added to @val1
1942 * if @val1 is NULL, a new set is created and copied from @val2
1943 *
1944 * Returns @val1 once extended or NULL in case of error.
1945 */
1946static xmlNodeSetPtr
1947xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00001948 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00001949
1950 if (val2 == NULL) return(val1);
1951 if (val1 == NULL) {
1952 val1 = xmlXPathNodeSetCreate(NULL);
1953 }
1954
1955 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00001956
1957 for (i = 0;i < val2->nodeNr;i++) {
1958 /*
1959 * grow the nodeTab if needed
1960 */
1961 if (val1->nodeMax == 0) {
1962 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1963 sizeof(xmlNodePtr));
1964 if (val1->nodeTab == NULL) {
1965 xmlGenericError(xmlGenericErrorContext,
1966 "xmlXPathNodeSetMerge: out of memory\n");
1967 return(NULL);
1968 }
1969 memset(val1->nodeTab, 0 ,
1970 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1971 val1->nodeMax = XML_NODESET_DEFAULT;
1972 } else if (val1->nodeNr == val1->nodeMax) {
1973 xmlNodePtr *temp;
1974
1975 val1->nodeMax *= 2;
1976 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1977 sizeof(xmlNodePtr));
1978 if (temp == NULL) {
1979 xmlGenericError(xmlGenericErrorContext,
1980 "xmlXPathNodeSetMerge: out of memory\n");
1981 return(NULL);
1982 }
1983 val1->nodeTab = temp;
1984 }
1985 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1986 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1987
1988 val1->nodeTab[val1->nodeNr++] =
1989 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1990 } else
1991 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1992 }
1993
1994 return(val1);
1995}
1996
1997/**
Owen Taylor3473f882001-02-23 17:55:21 +00001998 * xmlXPathNodeSetDel:
1999 * @cur: the initial node set
2000 * @val: an xmlNodePtr
2001 *
2002 * Removes an xmlNodePtr from an existing NodeSet
2003 */
2004void
2005xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2006 int i;
2007
2008 if (cur == NULL) return;
2009 if (val == NULL) return;
2010
2011 /*
2012 * check against doublons
2013 */
2014 for (i = 0;i < cur->nodeNr;i++)
2015 if (cur->nodeTab[i] == val) break;
2016
2017 if (i >= cur->nodeNr) {
2018#ifdef DEBUG
2019 xmlGenericError(xmlGenericErrorContext,
2020 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2021 val->name);
2022#endif
2023 return;
2024 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002025 if ((cur->nodeTab[i] != NULL) &&
2026 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2027 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002028 cur->nodeNr--;
2029 for (;i < cur->nodeNr;i++)
2030 cur->nodeTab[i] = cur->nodeTab[i + 1];
2031 cur->nodeTab[cur->nodeNr] = NULL;
2032}
2033
2034/**
2035 * xmlXPathNodeSetRemove:
2036 * @cur: the initial node set
2037 * @val: the index to remove
2038 *
2039 * Removes an entry from an existing NodeSet list.
2040 */
2041void
2042xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2043 if (cur == NULL) return;
2044 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002045 if ((cur->nodeTab[val] != NULL) &&
2046 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2047 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002048 cur->nodeNr--;
2049 for (;val < cur->nodeNr;val++)
2050 cur->nodeTab[val] = cur->nodeTab[val + 1];
2051 cur->nodeTab[cur->nodeNr] = NULL;
2052}
2053
2054/**
2055 * xmlXPathFreeNodeSet:
2056 * @obj: the xmlNodeSetPtr to free
2057 *
2058 * Free the NodeSet compound (not the actual nodes !).
2059 */
2060void
2061xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2062 if (obj == NULL) return;
2063 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002064 int i;
2065
2066 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2067 for (i = 0;i < obj->nodeNr;i++)
2068 if ((obj->nodeTab[i] != NULL) &&
2069 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2070 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002071 xmlFree(obj->nodeTab);
2072 }
Owen Taylor3473f882001-02-23 17:55:21 +00002073 xmlFree(obj);
2074}
2075
2076/**
2077 * xmlXPathFreeValueTree:
2078 * @obj: the xmlNodeSetPtr to free
2079 *
2080 * Free the NodeSet compound and the actual tree, this is different
2081 * from xmlXPathFreeNodeSet()
2082 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002083static void
Owen Taylor3473f882001-02-23 17:55:21 +00002084xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2085 int i;
2086
2087 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002088
2089 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002090 for (i = 0;i < obj->nodeNr;i++) {
2091 if (obj->nodeTab[i] != NULL) {
2092 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2093 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2094 } else {
2095 xmlFreeNodeList(obj->nodeTab[i]);
2096 }
2097 }
2098 }
Owen Taylor3473f882001-02-23 17:55:21 +00002099 xmlFree(obj->nodeTab);
2100 }
Owen Taylor3473f882001-02-23 17:55:21 +00002101 xmlFree(obj);
2102}
2103
2104#if defined(DEBUG) || defined(DEBUG_STEP)
2105/**
2106 * xmlGenericErrorContextNodeSet:
2107 * @output: a FILE * for the output
2108 * @obj: the xmlNodeSetPtr to free
2109 *
2110 * Quick display of a NodeSet
2111 */
2112void
2113xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2114 int i;
2115
2116 if (output == NULL) output = xmlGenericErrorContext;
2117 if (obj == NULL) {
2118 fprintf(output, "NodeSet == NULL !\n");
2119 return;
2120 }
2121 if (obj->nodeNr == 0) {
2122 fprintf(output, "NodeSet is empty\n");
2123 return;
2124 }
2125 if (obj->nodeTab == NULL) {
2126 fprintf(output, " nodeTab == NULL !\n");
2127 return;
2128 }
2129 for (i = 0; i < obj->nodeNr; i++) {
2130 if (obj->nodeTab[i] == NULL) {
2131 fprintf(output, " NULL !\n");
2132 return;
2133 }
2134 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2135 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2136 fprintf(output, " /");
2137 else if (obj->nodeTab[i]->name == NULL)
2138 fprintf(output, " noname!");
2139 else fprintf(output, " %s", obj->nodeTab[i]->name);
2140 }
2141 fprintf(output, "\n");
2142}
2143#endif
2144
2145/**
2146 * xmlXPathNewNodeSet:
2147 * @val: the NodePtr value
2148 *
2149 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2150 * it with the single Node @val
2151 *
2152 * Returns the newly created object.
2153 */
2154xmlXPathObjectPtr
2155xmlXPathNewNodeSet(xmlNodePtr val) {
2156 xmlXPathObjectPtr ret;
2157
2158 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2159 if (ret == NULL) {
2160 xmlGenericError(xmlGenericErrorContext,
2161 "xmlXPathNewNodeSet: out of memory\n");
2162 return(NULL);
2163 }
2164 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2165 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002166 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002167 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002168 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002169 return(ret);
2170}
2171
2172/**
2173 * xmlXPathNewValueTree:
2174 * @val: the NodePtr value
2175 *
2176 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2177 * it with the tree root @val
2178 *
2179 * Returns the newly created object.
2180 */
2181xmlXPathObjectPtr
2182xmlXPathNewValueTree(xmlNodePtr val) {
2183 xmlXPathObjectPtr ret;
2184
2185 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2186 if (ret == NULL) {
2187 xmlGenericError(xmlGenericErrorContext,
2188 "xmlXPathNewNodeSet: out of memory\n");
2189 return(NULL);
2190 }
2191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2192 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002193 ret->boolval = 1;
2194 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002195 ret->nodesetval = xmlXPathNodeSetCreate(val);
2196 return(ret);
2197}
2198
2199/**
2200 * xmlXPathNewNodeSetList:
2201 * @val: an existing NodeSet
2202 *
2203 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2204 * it with the Nodeset @val
2205 *
2206 * Returns the newly created object.
2207 */
2208xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002209xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2210{
Owen Taylor3473f882001-02-23 17:55:21 +00002211 xmlXPathObjectPtr ret;
2212 int i;
2213
2214 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002215 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002216 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002217 ret = xmlXPathNewNodeSet(NULL);
2218 else {
2219 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2220 for (i = 1; i < val->nodeNr; ++i)
2221 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2222 }
Owen Taylor3473f882001-02-23 17:55:21 +00002223
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002224 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002225}
2226
2227/**
2228 * xmlXPathWrapNodeSet:
2229 * @val: the NodePtr value
2230 *
2231 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2232 *
2233 * Returns the newly created object.
2234 */
2235xmlXPathObjectPtr
2236xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2237 xmlXPathObjectPtr ret;
2238
2239 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2240 if (ret == NULL) {
2241 xmlGenericError(xmlGenericErrorContext,
2242 "xmlXPathWrapNodeSet: out of memory\n");
2243 return(NULL);
2244 }
2245 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2246 ret->type = XPATH_NODESET;
2247 ret->nodesetval = val;
2248 return(ret);
2249}
2250
2251/**
2252 * xmlXPathFreeNodeSetList:
2253 * @obj: an existing NodeSetList object
2254 *
2255 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2256 * the list contrary to xmlXPathFreeObject().
2257 */
2258void
2259xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2260 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002261 xmlFree(obj);
2262}
2263
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002264/**
2265 * xmlXPathDifference:
2266 * @nodes1: a node-set
2267 * @nodes2: a node-set
2268 *
2269 * Implements the EXSLT - Sets difference() function:
2270 * node-set set:difference (node-set, node-set)
2271 *
2272 * Returns the difference between the two node sets, or nodes1 if
2273 * nodes2 is empty
2274 */
2275xmlNodeSetPtr
2276xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2277 xmlNodeSetPtr ret;
2278 int i, l1;
2279 xmlNodePtr cur;
2280
2281 if (xmlXPathNodeSetIsEmpty(nodes2))
2282 return(nodes1);
2283
2284 ret = xmlXPathNodeSetCreate(NULL);
2285 if (xmlXPathNodeSetIsEmpty(nodes1))
2286 return(ret);
2287
2288 l1 = xmlXPathNodeSetGetLength(nodes1);
2289
2290 for (i = 0; i < l1; i++) {
2291 cur = xmlXPathNodeSetItem(nodes1, i);
2292 if (!xmlXPathNodeSetContains(nodes2, cur))
2293 xmlXPathNodeSetAddUnique(ret, cur);
2294 }
2295 return(ret);
2296}
2297
2298/**
2299 * xmlXPathIntersection:
2300 * @nodes1: a node-set
2301 * @nodes2: a node-set
2302 *
2303 * Implements the EXSLT - Sets intersection() function:
2304 * node-set set:intersection (node-set, node-set)
2305 *
2306 * Returns a node set comprising the nodes that are within both the
2307 * node sets passed as arguments
2308 */
2309xmlNodeSetPtr
2310xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2311 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2312 int i, l1;
2313 xmlNodePtr cur;
2314
2315 if (xmlXPathNodeSetIsEmpty(nodes1))
2316 return(ret);
2317 if (xmlXPathNodeSetIsEmpty(nodes2))
2318 return(ret);
2319
2320 l1 = xmlXPathNodeSetGetLength(nodes1);
2321
2322 for (i = 0; i < l1; i++) {
2323 cur = xmlXPathNodeSetItem(nodes1, i);
2324 if (xmlXPathNodeSetContains(nodes2, cur))
2325 xmlXPathNodeSetAddUnique(ret, cur);
2326 }
2327 return(ret);
2328}
2329
2330/**
2331 * xmlXPathDistinctSorted:
2332 * @nodes: a node-set, sorted by document order
2333 *
2334 * Implements the EXSLT - Sets distinct() function:
2335 * node-set set:distinct (node-set)
2336 *
2337 * Returns a subset of the nodes contained in @nodes, or @nodes if
2338 * it is empty
2339 */
2340xmlNodeSetPtr
2341xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2342 xmlNodeSetPtr ret;
2343 xmlHashTablePtr hash;
2344 int i, l;
2345 xmlChar * strval;
2346 xmlNodePtr cur;
2347
2348 if (xmlXPathNodeSetIsEmpty(nodes))
2349 return(nodes);
2350
2351 ret = xmlXPathNodeSetCreate(NULL);
2352 l = xmlXPathNodeSetGetLength(nodes);
2353 hash = xmlHashCreate (l);
2354 for (i = 0; i < l; i++) {
2355 cur = xmlXPathNodeSetItem(nodes, i);
2356 strval = xmlXPathCastNodeToString(cur);
2357 if (xmlHashLookup(hash, strval) == NULL) {
2358 xmlHashAddEntry(hash, strval, strval);
2359 xmlXPathNodeSetAddUnique(ret, cur);
2360 } else {
2361 xmlFree(strval);
2362 }
2363 }
2364 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2365 return(ret);
2366}
2367
2368/**
2369 * xmlXPathDistinct:
2370 * @nodes: a node-set
2371 *
2372 * Implements the EXSLT - Sets distinct() function:
2373 * node-set set:distinct (node-set)
2374 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2375 * is called with the sorted node-set
2376 *
2377 * Returns a subset of the nodes contained in @nodes, or @nodes if
2378 * it is empty
2379 */
2380xmlNodeSetPtr
2381xmlXPathDistinct (xmlNodeSetPtr nodes) {
2382 if (xmlXPathNodeSetIsEmpty(nodes))
2383 return(nodes);
2384
2385 xmlXPathNodeSetSort(nodes);
2386 return(xmlXPathDistinctSorted(nodes));
2387}
2388
2389/**
2390 * xmlXPathHasSameNodes:
2391 * @nodes1: a node-set
2392 * @nodes2: a node-set
2393 *
2394 * Implements the EXSLT - Sets has-same-nodes function:
2395 * boolean set:has-same-node(node-set, node-set)
2396 *
2397 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2398 * otherwise
2399 */
2400int
2401xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2402 int i, l;
2403 xmlNodePtr cur;
2404
2405 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2406 xmlXPathNodeSetIsEmpty(nodes2))
2407 return(0);
2408
2409 l = xmlXPathNodeSetGetLength(nodes1);
2410 for (i = 0; i < l; i++) {
2411 cur = xmlXPathNodeSetItem(nodes1, i);
2412 if (xmlXPathNodeSetContains(nodes2, cur))
2413 return(1);
2414 }
2415 return(0);
2416}
2417
2418/**
2419 * xmlXPathNodeLeadingSorted:
2420 * @nodes: a node-set, sorted by document order
2421 * @node: a node
2422 *
2423 * Implements the EXSLT - Sets leading() function:
2424 * node-set set:leading (node-set, node-set)
2425 *
2426 * Returns the nodes in @nodes that precede @node in document order,
2427 * @nodes if @node is NULL or an empty node-set if @nodes
2428 * doesn't contain @node
2429 */
2430xmlNodeSetPtr
2431xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2432 int i, l;
2433 xmlNodePtr cur;
2434 xmlNodeSetPtr ret;
2435
2436 if (node == NULL)
2437 return(nodes);
2438
2439 ret = xmlXPathNodeSetCreate(NULL);
2440 if (xmlXPathNodeSetIsEmpty(nodes) ||
2441 (!xmlXPathNodeSetContains(nodes, node)))
2442 return(ret);
2443
2444 l = xmlXPathNodeSetGetLength(nodes);
2445 for (i = 0; i < l; i++) {
2446 cur = xmlXPathNodeSetItem(nodes, i);
2447 if (cur == node)
2448 break;
2449 xmlXPathNodeSetAddUnique(ret, cur);
2450 }
2451 return(ret);
2452}
2453
2454/**
2455 * xmlXPathNodeLeading:
2456 * @nodes: a node-set
2457 * @node: a node
2458 *
2459 * Implements the EXSLT - Sets leading() function:
2460 * node-set set:leading (node-set, node-set)
2461 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2462 * is called.
2463 *
2464 * Returns the nodes in @nodes that precede @node in document order,
2465 * @nodes if @node is NULL or an empty node-set if @nodes
2466 * doesn't contain @node
2467 */
2468xmlNodeSetPtr
2469xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2470 xmlXPathNodeSetSort(nodes);
2471 return(xmlXPathNodeLeadingSorted(nodes, node));
2472}
2473
2474/**
2475 * xmlXPathLeadingSorted:
2476 * @nodes1: a node-set, sorted by document order
2477 * @nodes2: a node-set, sorted by document order
2478 *
2479 * Implements the EXSLT - Sets leading() function:
2480 * node-set set:leading (node-set, node-set)
2481 *
2482 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2483 * in document order, @nodes1 if @nodes2 is NULL or empty or
2484 * an empty node-set if @nodes1 doesn't contain @nodes2
2485 */
2486xmlNodeSetPtr
2487xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2488 if (xmlXPathNodeSetIsEmpty(nodes2))
2489 return(nodes1);
2490 return(xmlXPathNodeLeadingSorted(nodes1,
2491 xmlXPathNodeSetItem(nodes2, 1)));
2492}
2493
2494/**
2495 * xmlXPathLeading:
2496 * @nodes1: a node-set
2497 * @nodes2: a node-set
2498 *
2499 * Implements the EXSLT - Sets leading() function:
2500 * node-set set:leading (node-set, node-set)
2501 * @nodes1 and @nodes2 are sorted by document order, then
2502 * #exslSetsLeadingSorted is called.
2503 *
2504 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2505 * in document order, @nodes1 if @nodes2 is NULL or empty or
2506 * an empty node-set if @nodes1 doesn't contain @nodes2
2507 */
2508xmlNodeSetPtr
2509xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2510 if (xmlXPathNodeSetIsEmpty(nodes2))
2511 return(nodes1);
2512 if (xmlXPathNodeSetIsEmpty(nodes1))
2513 return(xmlXPathNodeSetCreate(NULL));
2514 xmlXPathNodeSetSort(nodes1);
2515 xmlXPathNodeSetSort(nodes2);
2516 return(xmlXPathNodeLeadingSorted(nodes1,
2517 xmlXPathNodeSetItem(nodes2, 1)));
2518}
2519
2520/**
2521 * xmlXPathNodeTrailingSorted:
2522 * @nodes: a node-set, sorted by document order
2523 * @node: a node
2524 *
2525 * Implements the EXSLT - Sets trailing() function:
2526 * node-set set:trailing (node-set, node-set)
2527 *
2528 * Returns the nodes in @nodes that follow @node in document order,
2529 * @nodes if @node is NULL or an empty node-set if @nodes
2530 * doesn't contain @node
2531 */
2532xmlNodeSetPtr
2533xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2534 int i, l;
2535 xmlNodePtr cur;
2536 xmlNodeSetPtr ret;
2537
2538 if (node == NULL)
2539 return(nodes);
2540
2541 ret = xmlXPathNodeSetCreate(NULL);
2542 if (xmlXPathNodeSetIsEmpty(nodes) ||
2543 (!xmlXPathNodeSetContains(nodes, node)))
2544 return(ret);
2545
2546 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002547 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002548 cur = xmlXPathNodeSetItem(nodes, i);
2549 if (cur == node)
2550 break;
2551 xmlXPathNodeSetAddUnique(ret, cur);
2552 }
2553 return(ret);
2554}
2555
2556/**
2557 * xmlXPathNodeTrailing:
2558 * @nodes: a node-set
2559 * @node: a node
2560 *
2561 * Implements the EXSLT - Sets trailing() function:
2562 * node-set set:trailing (node-set, node-set)
2563 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2564 * is called.
2565 *
2566 * Returns the nodes in @nodes that follow @node in document order,
2567 * @nodes if @node is NULL or an empty node-set if @nodes
2568 * doesn't contain @node
2569 */
2570xmlNodeSetPtr
2571xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2572 xmlXPathNodeSetSort(nodes);
2573 return(xmlXPathNodeTrailingSorted(nodes, node));
2574}
2575
2576/**
2577 * xmlXPathTrailingSorted:
2578 * @nodes1: a node-set, sorted by document order
2579 * @nodes2: a node-set, sorted by document order
2580 *
2581 * Implements the EXSLT - Sets trailing() function:
2582 * node-set set:trailing (node-set, node-set)
2583 *
2584 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2585 * in document order, @nodes1 if @nodes2 is NULL or empty or
2586 * an empty node-set if @nodes1 doesn't contain @nodes2
2587 */
2588xmlNodeSetPtr
2589xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2590 if (xmlXPathNodeSetIsEmpty(nodes2))
2591 return(nodes1);
2592 return(xmlXPathNodeTrailingSorted(nodes1,
2593 xmlXPathNodeSetItem(nodes2, 0)));
2594}
2595
2596/**
2597 * xmlXPathTrailing:
2598 * @nodes1: a node-set
2599 * @nodes2: a node-set
2600 *
2601 * Implements the EXSLT - Sets trailing() function:
2602 * node-set set:trailing (node-set, node-set)
2603 * @nodes1 and @nodes2 are sorted by document order, then
2604 * #xmlXPathTrailingSorted is called.
2605 *
2606 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2607 * in document order, @nodes1 if @nodes2 is NULL or empty or
2608 * an empty node-set if @nodes1 doesn't contain @nodes2
2609 */
2610xmlNodeSetPtr
2611xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2612 if (xmlXPathNodeSetIsEmpty(nodes2))
2613 return(nodes1);
2614 if (xmlXPathNodeSetIsEmpty(nodes1))
2615 return(xmlXPathNodeSetCreate(NULL));
2616 xmlXPathNodeSetSort(nodes1);
2617 xmlXPathNodeSetSort(nodes2);
2618 return(xmlXPathNodeTrailingSorted(nodes1,
2619 xmlXPathNodeSetItem(nodes2, 0)));
2620}
2621
Owen Taylor3473f882001-02-23 17:55:21 +00002622/************************************************************************
2623 * *
2624 * Routines to handle extra functions *
2625 * *
2626 ************************************************************************/
2627
2628/**
2629 * xmlXPathRegisterFunc:
2630 * @ctxt: the XPath context
2631 * @name: the function name
2632 * @f: the function implementation or NULL
2633 *
2634 * Register a new function. If @f is NULL it unregisters the function
2635 *
2636 * Returns 0 in case of success, -1 in case of error
2637 */
2638int
2639xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2640 xmlXPathFunction f) {
2641 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2642}
2643
2644/**
2645 * xmlXPathRegisterFuncNS:
2646 * @ctxt: the XPath context
2647 * @name: the function name
2648 * @ns_uri: the function namespace URI
2649 * @f: the function implementation or NULL
2650 *
2651 * Register a new function. If @f is NULL it unregisters the function
2652 *
2653 * Returns 0 in case of success, -1 in case of error
2654 */
2655int
2656xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2657 const xmlChar *ns_uri, xmlXPathFunction f) {
2658 if (ctxt == NULL)
2659 return(-1);
2660 if (name == NULL)
2661 return(-1);
2662
2663 if (ctxt->funcHash == NULL)
2664 ctxt->funcHash = xmlHashCreate(0);
2665 if (ctxt->funcHash == NULL)
2666 return(-1);
2667 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2668}
2669
2670/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002671 * xmlXPathRegisterFuncLookup:
2672 * @ctxt: the XPath context
2673 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002674 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002675 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002676 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002677 */
2678void
2679xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2680 xmlXPathFuncLookupFunc f,
2681 void *funcCtxt) {
2682 if (ctxt == NULL)
2683 return;
2684 ctxt->funcLookupFunc = (void *) f;
2685 ctxt->funcLookupData = funcCtxt;
2686}
2687
2688/**
Owen Taylor3473f882001-02-23 17:55:21 +00002689 * xmlXPathFunctionLookup:
2690 * @ctxt: the XPath context
2691 * @name: the function name
2692 *
2693 * Search in the Function array of the context for the given
2694 * function.
2695 *
2696 * Returns the xmlXPathFunction or NULL if not found
2697 */
2698xmlXPathFunction
2699xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002700 if (ctxt == NULL)
2701 return (NULL);
2702
2703 if (ctxt->funcLookupFunc != NULL) {
2704 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002705 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002706
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002707 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002708 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002709 if (ret != NULL)
2710 return(ret);
2711 }
Owen Taylor3473f882001-02-23 17:55:21 +00002712 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2713}
2714
2715/**
2716 * xmlXPathFunctionLookupNS:
2717 * @ctxt: the XPath context
2718 * @name: the function name
2719 * @ns_uri: the function namespace URI
2720 *
2721 * Search in the Function array of the context for the given
2722 * function.
2723 *
2724 * Returns the xmlXPathFunction or NULL if not found
2725 */
2726xmlXPathFunction
2727xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2728 const xmlChar *ns_uri) {
2729 if (ctxt == NULL)
2730 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002731 if (name == NULL)
2732 return(NULL);
2733
Thomas Broyerba4ad322001-07-26 16:55:21 +00002734 if (ctxt->funcLookupFunc != NULL) {
2735 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002736 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002737
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002738 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002739 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002740 if (ret != NULL)
2741 return(ret);
2742 }
2743
2744 if (ctxt->funcHash == NULL)
2745 return(NULL);
2746
Owen Taylor3473f882001-02-23 17:55:21 +00002747 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2748}
2749
2750/**
2751 * xmlXPathRegisteredFuncsCleanup:
2752 * @ctxt: the XPath context
2753 *
2754 * Cleanup the XPath context data associated to registered functions
2755 */
2756void
2757xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2758 if (ctxt == NULL)
2759 return;
2760
2761 xmlHashFree(ctxt->funcHash, NULL);
2762 ctxt->funcHash = NULL;
2763}
2764
2765/************************************************************************
2766 * *
2767 * Routines to handle Variable *
2768 * *
2769 ************************************************************************/
2770
2771/**
2772 * xmlXPathRegisterVariable:
2773 * @ctxt: the XPath context
2774 * @name: the variable name
2775 * @value: the variable value or NULL
2776 *
2777 * Register a new variable value. If @value is NULL it unregisters
2778 * the variable
2779 *
2780 * Returns 0 in case of success, -1 in case of error
2781 */
2782int
2783xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2784 xmlXPathObjectPtr value) {
2785 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2786}
2787
2788/**
2789 * xmlXPathRegisterVariableNS:
2790 * @ctxt: the XPath context
2791 * @name: the variable name
2792 * @ns_uri: the variable namespace URI
2793 * @value: the variable value or NULL
2794 *
2795 * Register a new variable value. If @value is NULL it unregisters
2796 * the variable
2797 *
2798 * Returns 0 in case of success, -1 in case of error
2799 */
2800int
2801xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2802 const xmlChar *ns_uri,
2803 xmlXPathObjectPtr value) {
2804 if (ctxt == NULL)
2805 return(-1);
2806 if (name == NULL)
2807 return(-1);
2808
2809 if (ctxt->varHash == NULL)
2810 ctxt->varHash = xmlHashCreate(0);
2811 if (ctxt->varHash == NULL)
2812 return(-1);
2813 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2814 (void *) value,
2815 (xmlHashDeallocator)xmlXPathFreeObject));
2816}
2817
2818/**
2819 * xmlXPathRegisterVariableLookup:
2820 * @ctxt: the XPath context
2821 * @f: the lookup function
2822 * @data: the lookup data
2823 *
2824 * register an external mechanism to do variable lookup
2825 */
2826void
2827xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2828 xmlXPathVariableLookupFunc f, void *data) {
2829 if (ctxt == NULL)
2830 return;
2831 ctxt->varLookupFunc = (void *) f;
2832 ctxt->varLookupData = data;
2833}
2834
2835/**
2836 * xmlXPathVariableLookup:
2837 * @ctxt: the XPath context
2838 * @name: the variable name
2839 *
2840 * Search in the Variable array of the context for the given
2841 * variable value.
2842 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002843 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002844 */
2845xmlXPathObjectPtr
2846xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2847 if (ctxt == NULL)
2848 return(NULL);
2849
2850 if (ctxt->varLookupFunc != NULL) {
2851 xmlXPathObjectPtr ret;
2852
2853 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2854 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002855 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002856 }
2857 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2858}
2859
2860/**
2861 * xmlXPathVariableLookupNS:
2862 * @ctxt: the XPath context
2863 * @name: the variable name
2864 * @ns_uri: the variable namespace URI
2865 *
2866 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002867 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002868 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002869 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002870 */
2871xmlXPathObjectPtr
2872xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2873 const xmlChar *ns_uri) {
2874 if (ctxt == NULL)
2875 return(NULL);
2876
2877 if (ctxt->varLookupFunc != NULL) {
2878 xmlXPathObjectPtr ret;
2879
2880 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2881 (ctxt->varLookupData, name, ns_uri);
2882 if (ret != NULL) return(ret);
2883 }
2884
2885 if (ctxt->varHash == NULL)
2886 return(NULL);
2887 if (name == NULL)
2888 return(NULL);
2889
Daniel Veillard8c357d52001-07-03 23:43:33 +00002890 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2891 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002892}
2893
2894/**
2895 * xmlXPathRegisteredVariablesCleanup:
2896 * @ctxt: the XPath context
2897 *
2898 * Cleanup the XPath context data associated to registered variables
2899 */
2900void
2901xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2902 if (ctxt == NULL)
2903 return;
2904
Daniel Veillard76d66f42001-05-16 21:05:17 +00002905 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002906 ctxt->varHash = NULL;
2907}
2908
2909/**
2910 * xmlXPathRegisterNs:
2911 * @ctxt: the XPath context
2912 * @prefix: the namespace prefix
2913 * @ns_uri: the namespace name
2914 *
2915 * Register a new namespace. If @ns_uri is NULL it unregisters
2916 * the namespace
2917 *
2918 * Returns 0 in case of success, -1 in case of error
2919 */
2920int
2921xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2922 const xmlChar *ns_uri) {
2923 if (ctxt == NULL)
2924 return(-1);
2925 if (prefix == NULL)
2926 return(-1);
2927
2928 if (ctxt->nsHash == NULL)
2929 ctxt->nsHash = xmlHashCreate(10);
2930 if (ctxt->nsHash == NULL)
2931 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002932 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002933 (xmlHashDeallocator)xmlFree));
2934}
2935
2936/**
2937 * xmlXPathNsLookup:
2938 * @ctxt: the XPath context
2939 * @prefix: the namespace prefix value
2940 *
2941 * Search in the namespace declaration array of the context for the given
2942 * namespace name associated to the given prefix
2943 *
2944 * Returns the value or NULL if not found
2945 */
2946const xmlChar *
2947xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2948 if (ctxt == NULL)
2949 return(NULL);
2950 if (prefix == NULL)
2951 return(NULL);
2952
2953#ifdef XML_XML_NAMESPACE
2954 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2955 return(XML_XML_NAMESPACE);
2956#endif
2957
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002958 if (ctxt->namespaces != NULL) {
2959 int i;
2960
2961 for (i = 0;i < ctxt->nsNr;i++) {
2962 if ((ctxt->namespaces[i] != NULL) &&
2963 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2964 return(ctxt->namespaces[i]->href);
2965 }
2966 }
Owen Taylor3473f882001-02-23 17:55:21 +00002967
2968 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2969}
2970
2971/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002972 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002973 * @ctxt: the XPath context
2974 *
2975 * Cleanup the XPath context data associated to registered variables
2976 */
2977void
2978xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2979 if (ctxt == NULL)
2980 return;
2981
Daniel Veillard42766c02002-08-22 20:52:17 +00002982 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002983 ctxt->nsHash = NULL;
2984}
2985
2986/************************************************************************
2987 * *
2988 * Routines to handle Values *
2989 * *
2990 ************************************************************************/
2991
2992/* Allocations are terrible, one need to optimize all this !!! */
2993
2994/**
2995 * xmlXPathNewFloat:
2996 * @val: the double value
2997 *
2998 * Create a new xmlXPathObjectPtr of type double and of value @val
2999 *
3000 * Returns the newly created object.
3001 */
3002xmlXPathObjectPtr
3003xmlXPathNewFloat(double val) {
3004 xmlXPathObjectPtr ret;
3005
3006 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3007 if (ret == NULL) {
3008 xmlGenericError(xmlGenericErrorContext,
3009 "xmlXPathNewFloat: out of memory\n");
3010 return(NULL);
3011 }
3012 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3013 ret->type = XPATH_NUMBER;
3014 ret->floatval = val;
3015 return(ret);
3016}
3017
3018/**
3019 * xmlXPathNewBoolean:
3020 * @val: the boolean value
3021 *
3022 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3023 *
3024 * Returns the newly created object.
3025 */
3026xmlXPathObjectPtr
3027xmlXPathNewBoolean(int val) {
3028 xmlXPathObjectPtr ret;
3029
3030 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3031 if (ret == NULL) {
3032 xmlGenericError(xmlGenericErrorContext,
3033 "xmlXPathNewBoolean: out of memory\n");
3034 return(NULL);
3035 }
3036 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3037 ret->type = XPATH_BOOLEAN;
3038 ret->boolval = (val != 0);
3039 return(ret);
3040}
3041
3042/**
3043 * xmlXPathNewString:
3044 * @val: the xmlChar * value
3045 *
3046 * Create a new xmlXPathObjectPtr of type string and of value @val
3047 *
3048 * Returns the newly created object.
3049 */
3050xmlXPathObjectPtr
3051xmlXPathNewString(const xmlChar *val) {
3052 xmlXPathObjectPtr ret;
3053
3054 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3055 if (ret == NULL) {
3056 xmlGenericError(xmlGenericErrorContext,
3057 "xmlXPathNewString: out of memory\n");
3058 return(NULL);
3059 }
3060 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3061 ret->type = XPATH_STRING;
3062 if (val != NULL)
3063 ret->stringval = xmlStrdup(val);
3064 else
3065 ret->stringval = xmlStrdup((const xmlChar *)"");
3066 return(ret);
3067}
3068
3069/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003070 * xmlXPathWrapString:
3071 * @val: the xmlChar * value
3072 *
3073 * Wraps the @val string into an XPath object.
3074 *
3075 * Returns the newly created object.
3076 */
3077xmlXPathObjectPtr
3078xmlXPathWrapString (xmlChar *val) {
3079 xmlXPathObjectPtr ret;
3080
3081 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3082 if (ret == NULL) {
3083 xmlGenericError(xmlGenericErrorContext,
3084 "xmlXPathWrapString: out of memory\n");
3085 return(NULL);
3086 }
3087 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3088 ret->type = XPATH_STRING;
3089 ret->stringval = val;
3090 return(ret);
3091}
3092
3093/**
Owen Taylor3473f882001-02-23 17:55:21 +00003094 * xmlXPathNewCString:
3095 * @val: the char * value
3096 *
3097 * Create a new xmlXPathObjectPtr of type string and of value @val
3098 *
3099 * Returns the newly created object.
3100 */
3101xmlXPathObjectPtr
3102xmlXPathNewCString(const char *val) {
3103 xmlXPathObjectPtr ret;
3104
3105 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3106 if (ret == NULL) {
3107 xmlGenericError(xmlGenericErrorContext,
3108 "xmlXPathNewCString: out of memory\n");
3109 return(NULL);
3110 }
3111 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3112 ret->type = XPATH_STRING;
3113 ret->stringval = xmlStrdup(BAD_CAST val);
3114 return(ret);
3115}
3116
3117/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003118 * xmlXPathWrapCString:
3119 * @val: the char * value
3120 *
3121 * Wraps a string into an XPath object.
3122 *
3123 * Returns the newly created object.
3124 */
3125xmlXPathObjectPtr
3126xmlXPathWrapCString (char * val) {
3127 return(xmlXPathWrapString((xmlChar *)(val)));
3128}
3129
3130/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003131 * xmlXPathWrapExternal:
3132 * @val: the user data
3133 *
3134 * Wraps the @val data into an XPath object.
3135 *
3136 * Returns the newly created object.
3137 */
3138xmlXPathObjectPtr
3139xmlXPathWrapExternal (void *val) {
3140 xmlXPathObjectPtr ret;
3141
3142 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3143 if (ret == NULL) {
3144 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003145 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003146 return(NULL);
3147 }
3148 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3149 ret->type = XPATH_USERS;
3150 ret->user = val;
3151 return(ret);
3152}
3153
3154/**
Owen Taylor3473f882001-02-23 17:55:21 +00003155 * xmlXPathObjectCopy:
3156 * @val: the original object
3157 *
3158 * allocate a new copy of a given object
3159 *
3160 * Returns the newly created object.
3161 */
3162xmlXPathObjectPtr
3163xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3164 xmlXPathObjectPtr ret;
3165
3166 if (val == NULL)
3167 return(NULL);
3168
3169 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3170 if (ret == NULL) {
3171 xmlGenericError(xmlGenericErrorContext,
3172 "xmlXPathObjectCopy: out of memory\n");
3173 return(NULL);
3174 }
3175 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3176 switch (val->type) {
3177 case XPATH_BOOLEAN:
3178 case XPATH_NUMBER:
3179 case XPATH_POINT:
3180 case XPATH_RANGE:
3181 break;
3182 case XPATH_STRING:
3183 ret->stringval = xmlStrdup(val->stringval);
3184 break;
3185 case XPATH_XSLT_TREE:
3186 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003187 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003188 xmlNodePtr cur, tmp;
3189 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003190
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003191 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003192 top = xmlNewDoc(NULL);
3193 top->name = (char *)
3194 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003195 ret->user = top;
3196 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003197 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003198 cur = val->nodesetval->nodeTab[0]->children;
3199 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003200 tmp = xmlDocCopyNode(cur, top, 1);
3201 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003202 cur = cur->next;
3203 }
3204 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003205 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003206 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003207 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003208 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003209 break;
3210 case XPATH_NODESET:
3211 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003212 /* Do not deallocate the copied tree value */
3213 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003214 break;
3215 case XPATH_LOCATIONSET:
3216#ifdef LIBXML_XPTR_ENABLED
3217 {
3218 xmlLocationSetPtr loc = val->user;
3219 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3220 break;
3221 }
3222#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003223 case XPATH_USERS:
3224 ret->user = val->user;
3225 break;
3226 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003227 xmlGenericError(xmlGenericErrorContext,
3228 "xmlXPathObjectCopy: unsupported type %d\n",
3229 val->type);
3230 break;
3231 }
3232 return(ret);
3233}
3234
3235/**
3236 * xmlXPathFreeObject:
3237 * @obj: the object to free
3238 *
3239 * Free up an xmlXPathObjectPtr object.
3240 */
3241void
3242xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3243 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003244 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003245 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003246 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003247 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003248 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003249 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003250 xmlXPathFreeValueTree(obj->nodesetval);
3251 } else {
3252 if (obj->nodesetval != NULL)
3253 xmlXPathFreeNodeSet(obj->nodesetval);
3254 }
Owen Taylor3473f882001-02-23 17:55:21 +00003255#ifdef LIBXML_XPTR_ENABLED
3256 } else if (obj->type == XPATH_LOCATIONSET) {
3257 if (obj->user != NULL)
3258 xmlXPtrFreeLocationSet(obj->user);
3259#endif
3260 } else if (obj->type == XPATH_STRING) {
3261 if (obj->stringval != NULL)
3262 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003263 }
3264
Owen Taylor3473f882001-02-23 17:55:21 +00003265 xmlFree(obj);
3266}
3267
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003268
3269/************************************************************************
3270 * *
3271 * Type Casting Routines *
3272 * *
3273 ************************************************************************/
3274
3275/**
3276 * xmlXPathCastBooleanToString:
3277 * @val: a boolean
3278 *
3279 * Converts a boolean to its string value.
3280 *
3281 * Returns a newly allocated string.
3282 */
3283xmlChar *
3284xmlXPathCastBooleanToString (int val) {
3285 xmlChar *ret;
3286 if (val)
3287 ret = xmlStrdup((const xmlChar *) "true");
3288 else
3289 ret = xmlStrdup((const xmlChar *) "false");
3290 return(ret);
3291}
3292
3293/**
3294 * xmlXPathCastNumberToString:
3295 * @val: a number
3296 *
3297 * Converts a number to its string value.
3298 *
3299 * Returns a newly allocated string.
3300 */
3301xmlChar *
3302xmlXPathCastNumberToString (double val) {
3303 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003304 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003305 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003306 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003307 break;
3308 case -1:
3309 ret = xmlStrdup((const xmlChar *) "-Infinity");
3310 break;
3311 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003312 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003313 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003314 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3315 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003316 } else {
3317 /* could be improved */
3318 char buf[100];
3319 xmlXPathFormatNumber(val, buf, 100);
3320 ret = xmlStrdup((const xmlChar *) buf);
3321 }
3322 }
3323 return(ret);
3324}
3325
3326/**
3327 * xmlXPathCastNodeToString:
3328 * @node: a node
3329 *
3330 * Converts a node to its string value.
3331 *
3332 * Returns a newly allocated string.
3333 */
3334xmlChar *
3335xmlXPathCastNodeToString (xmlNodePtr node) {
3336 return(xmlNodeGetContent(node));
3337}
3338
3339/**
3340 * xmlXPathCastNodeSetToString:
3341 * @ns: a node-set
3342 *
3343 * Converts a node-set to its string value.
3344 *
3345 * Returns a newly allocated string.
3346 */
3347xmlChar *
3348xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3349 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3350 return(xmlStrdup((const xmlChar *) ""));
3351
3352 xmlXPathNodeSetSort(ns);
3353 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3354}
3355
3356/**
3357 * xmlXPathCastToString:
3358 * @val: an XPath object
3359 *
3360 * Converts an existing object to its string() equivalent
3361 *
3362 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003363 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003364 * string object).
3365 */
3366xmlChar *
3367xmlXPathCastToString(xmlXPathObjectPtr val) {
3368 xmlChar *ret = NULL;
3369
3370 if (val == NULL)
3371 return(xmlStrdup((const xmlChar *) ""));
3372 switch (val->type) {
3373 case XPATH_UNDEFINED:
3374#ifdef DEBUG_EXPR
3375 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3376#endif
3377 ret = xmlStrdup((const xmlChar *) "");
3378 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003379 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003380 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003381 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3382 break;
3383 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003384 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003385 case XPATH_BOOLEAN:
3386 ret = xmlXPathCastBooleanToString(val->boolval);
3387 break;
3388 case XPATH_NUMBER: {
3389 ret = xmlXPathCastNumberToString(val->floatval);
3390 break;
3391 }
3392 case XPATH_USERS:
3393 case XPATH_POINT:
3394 case XPATH_RANGE:
3395 case XPATH_LOCATIONSET:
3396 TODO
3397 ret = xmlStrdup((const xmlChar *) "");
3398 break;
3399 }
3400 return(ret);
3401}
3402
3403/**
3404 * xmlXPathConvertString:
3405 * @val: an XPath object
3406 *
3407 * Converts an existing object to its string() equivalent
3408 *
3409 * Returns the new object, the old one is freed (or the operation
3410 * is done directly on @val)
3411 */
3412xmlXPathObjectPtr
3413xmlXPathConvertString(xmlXPathObjectPtr val) {
3414 xmlChar *res = NULL;
3415
3416 if (val == NULL)
3417 return(xmlXPathNewCString(""));
3418
3419 switch (val->type) {
3420 case XPATH_UNDEFINED:
3421#ifdef DEBUG_EXPR
3422 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3423#endif
3424 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003425 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003426 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003427 res = xmlXPathCastNodeSetToString(val->nodesetval);
3428 break;
3429 case XPATH_STRING:
3430 return(val);
3431 case XPATH_BOOLEAN:
3432 res = xmlXPathCastBooleanToString(val->boolval);
3433 break;
3434 case XPATH_NUMBER:
3435 res = xmlXPathCastNumberToString(val->floatval);
3436 break;
3437 case XPATH_USERS:
3438 case XPATH_POINT:
3439 case XPATH_RANGE:
3440 case XPATH_LOCATIONSET:
3441 TODO;
3442 break;
3443 }
3444 xmlXPathFreeObject(val);
3445 if (res == NULL)
3446 return(xmlXPathNewCString(""));
3447 return(xmlXPathWrapString(res));
3448}
3449
3450/**
3451 * xmlXPathCastBooleanToNumber:
3452 * @val: a boolean
3453 *
3454 * Converts a boolean to its number value
3455 *
3456 * Returns the number value
3457 */
3458double
3459xmlXPathCastBooleanToNumber(int val) {
3460 if (val)
3461 return(1.0);
3462 return(0.0);
3463}
3464
3465/**
3466 * xmlXPathCastStringToNumber:
3467 * @val: a string
3468 *
3469 * Converts a string to its number value
3470 *
3471 * Returns the number value
3472 */
3473double
3474xmlXPathCastStringToNumber(const xmlChar * val) {
3475 return(xmlXPathStringEvalNumber(val));
3476}
3477
3478/**
3479 * xmlXPathCastNodeToNumber:
3480 * @node: a node
3481 *
3482 * Converts a node to its number value
3483 *
3484 * Returns the number value
3485 */
3486double
3487xmlXPathCastNodeToNumber (xmlNodePtr node) {
3488 xmlChar *strval;
3489 double ret;
3490
3491 if (node == NULL)
3492 return(xmlXPathNAN);
3493 strval = xmlXPathCastNodeToString(node);
3494 if (strval == NULL)
3495 return(xmlXPathNAN);
3496 ret = xmlXPathCastStringToNumber(strval);
3497 xmlFree(strval);
3498
3499 return(ret);
3500}
3501
3502/**
3503 * xmlXPathCastNodeSetToNumber:
3504 * @ns: a node-set
3505 *
3506 * Converts a node-set to its number value
3507 *
3508 * Returns the number value
3509 */
3510double
3511xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3512 xmlChar *str;
3513 double ret;
3514
3515 if (ns == NULL)
3516 return(xmlXPathNAN);
3517 str = xmlXPathCastNodeSetToString(ns);
3518 ret = xmlXPathCastStringToNumber(str);
3519 xmlFree(str);
3520 return(ret);
3521}
3522
3523/**
3524 * xmlXPathCastToNumber:
3525 * @val: an XPath object
3526 *
3527 * Converts an XPath object to its number value
3528 *
3529 * Returns the number value
3530 */
3531double
3532xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3533 double ret = 0.0;
3534
3535 if (val == NULL)
3536 return(xmlXPathNAN);
3537 switch (val->type) {
3538 case XPATH_UNDEFINED:
3539#ifdef DEGUB_EXPR
3540 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3541#endif
3542 ret = xmlXPathNAN;
3543 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003544 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003545 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003546 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3547 break;
3548 case XPATH_STRING:
3549 ret = xmlXPathCastStringToNumber(val->stringval);
3550 break;
3551 case XPATH_NUMBER:
3552 ret = val->floatval;
3553 break;
3554 case XPATH_BOOLEAN:
3555 ret = xmlXPathCastBooleanToNumber(val->boolval);
3556 break;
3557 case XPATH_USERS:
3558 case XPATH_POINT:
3559 case XPATH_RANGE:
3560 case XPATH_LOCATIONSET:
3561 TODO;
3562 ret = xmlXPathNAN;
3563 break;
3564 }
3565 return(ret);
3566}
3567
3568/**
3569 * xmlXPathConvertNumber:
3570 * @val: an XPath object
3571 *
3572 * Converts an existing object to its number() equivalent
3573 *
3574 * Returns the new object, the old one is freed (or the operation
3575 * is done directly on @val)
3576 */
3577xmlXPathObjectPtr
3578xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3579 xmlXPathObjectPtr ret;
3580
3581 if (val == NULL)
3582 return(xmlXPathNewFloat(0.0));
3583 if (val->type == XPATH_NUMBER)
3584 return(val);
3585 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3586 xmlXPathFreeObject(val);
3587 return(ret);
3588}
3589
3590/**
3591 * xmlXPathCastNumberToBoolean:
3592 * @val: a number
3593 *
3594 * Converts a number to its boolean value
3595 *
3596 * Returns the boolean value
3597 */
3598int
3599xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003600 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003601 return(0);
3602 return(1);
3603}
3604
3605/**
3606 * xmlXPathCastStringToBoolean:
3607 * @val: a string
3608 *
3609 * Converts a string to its boolean value
3610 *
3611 * Returns the boolean value
3612 */
3613int
3614xmlXPathCastStringToBoolean (const xmlChar *val) {
3615 if ((val == NULL) || (xmlStrlen(val) == 0))
3616 return(0);
3617 return(1);
3618}
3619
3620/**
3621 * xmlXPathCastNodeSetToBoolean:
3622 * @ns: a node-set
3623 *
3624 * Converts a node-set to its boolean value
3625 *
3626 * Returns the boolean value
3627 */
3628int
3629xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3630 if ((ns == NULL) || (ns->nodeNr == 0))
3631 return(0);
3632 return(1);
3633}
3634
3635/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003636 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003637 * @val: an XPath object
3638 *
3639 * Converts an XPath object to its boolean value
3640 *
3641 * Returns the boolean value
3642 */
3643int
3644xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3645 int ret = 0;
3646
3647 if (val == NULL)
3648 return(0);
3649 switch (val->type) {
3650 case XPATH_UNDEFINED:
3651#ifdef DEBUG_EXPR
3652 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3653#endif
3654 ret = 0;
3655 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003656 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003657 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003658 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3659 break;
3660 case XPATH_STRING:
3661 ret = xmlXPathCastStringToBoolean(val->stringval);
3662 break;
3663 case XPATH_NUMBER:
3664 ret = xmlXPathCastNumberToBoolean(val->floatval);
3665 break;
3666 case XPATH_BOOLEAN:
3667 ret = val->boolval;
3668 break;
3669 case XPATH_USERS:
3670 case XPATH_POINT:
3671 case XPATH_RANGE:
3672 case XPATH_LOCATIONSET:
3673 TODO;
3674 ret = 0;
3675 break;
3676 }
3677 return(ret);
3678}
3679
3680
3681/**
3682 * xmlXPathConvertBoolean:
3683 * @val: an XPath object
3684 *
3685 * Converts an existing object to its boolean() equivalent
3686 *
3687 * Returns the new object, the old one is freed (or the operation
3688 * is done directly on @val)
3689 */
3690xmlXPathObjectPtr
3691xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3692 xmlXPathObjectPtr ret;
3693
3694 if (val == NULL)
3695 return(xmlXPathNewBoolean(0));
3696 if (val->type == XPATH_BOOLEAN)
3697 return(val);
3698 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3699 xmlXPathFreeObject(val);
3700 return(ret);
3701}
3702
Owen Taylor3473f882001-02-23 17:55:21 +00003703/************************************************************************
3704 * *
3705 * Routines to handle XPath contexts *
3706 * *
3707 ************************************************************************/
3708
3709/**
3710 * xmlXPathNewContext:
3711 * @doc: the XML document
3712 *
3713 * Create a new xmlXPathContext
3714 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003715 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003716 */
3717xmlXPathContextPtr
3718xmlXPathNewContext(xmlDocPtr doc) {
3719 xmlXPathContextPtr ret;
3720
3721 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3722 if (ret == NULL) {
3723 xmlGenericError(xmlGenericErrorContext,
3724 "xmlXPathNewContext: out of memory\n");
3725 return(NULL);
3726 }
3727 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3728 ret->doc = doc;
3729 ret->node = NULL;
3730
3731 ret->varHash = NULL;
3732
3733 ret->nb_types = 0;
3734 ret->max_types = 0;
3735 ret->types = NULL;
3736
3737 ret->funcHash = xmlHashCreate(0);
3738
3739 ret->nb_axis = 0;
3740 ret->max_axis = 0;
3741 ret->axis = NULL;
3742
3743 ret->nsHash = NULL;
3744 ret->user = NULL;
3745
3746 ret->contextSize = -1;
3747 ret->proximityPosition = -1;
3748
3749 xmlXPathRegisterAllFunctions(ret);
3750
3751 return(ret);
3752}
3753
3754/**
3755 * xmlXPathFreeContext:
3756 * @ctxt: the context to free
3757 *
3758 * Free up an xmlXPathContext
3759 */
3760void
3761xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3762 xmlXPathRegisteredNsCleanup(ctxt);
3763 xmlXPathRegisteredFuncsCleanup(ctxt);
3764 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003765 xmlFree(ctxt);
3766}
3767
3768/************************************************************************
3769 * *
3770 * Routines to handle XPath parser contexts *
3771 * *
3772 ************************************************************************/
3773
3774#define CHECK_CTXT(ctxt) \
3775 if (ctxt == NULL) { \
3776 xmlGenericError(xmlGenericErrorContext, \
3777 "%s:%d Internal error: ctxt == NULL\n", \
3778 __FILE__, __LINE__); \
3779 } \
3780
3781
3782#define CHECK_CONTEXT(ctxt) \
3783 if (ctxt == NULL) { \
3784 xmlGenericError(xmlGenericErrorContext, \
3785 "%s:%d Internal error: no context\n", \
3786 __FILE__, __LINE__); \
3787 } \
3788 else if (ctxt->doc == NULL) { \
3789 xmlGenericError(xmlGenericErrorContext, \
3790 "%s:%d Internal error: no document\n", \
3791 __FILE__, __LINE__); \
3792 } \
3793 else if (ctxt->doc->children == NULL) { \
3794 xmlGenericError(xmlGenericErrorContext, \
3795 "%s:%d Internal error: document without root\n", \
3796 __FILE__, __LINE__); \
3797 } \
3798
3799
3800/**
3801 * xmlXPathNewParserContext:
3802 * @str: the XPath expression
3803 * @ctxt: the XPath context
3804 *
3805 * Create a new xmlXPathParserContext
3806 *
3807 * Returns the xmlXPathParserContext just allocated.
3808 */
3809xmlXPathParserContextPtr
3810xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3811 xmlXPathParserContextPtr ret;
3812
3813 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3814 if (ret == NULL) {
3815 xmlGenericError(xmlGenericErrorContext,
3816 "xmlXPathNewParserContext: out of memory\n");
3817 return(NULL);
3818 }
3819 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3820 ret->cur = ret->base = str;
3821 ret->context = ctxt;
3822
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003823 ret->comp = xmlXPathNewCompExpr();
3824 if (ret->comp == NULL) {
3825 xmlFree(ret->valueTab);
3826 xmlFree(ret);
3827 return(NULL);
3828 }
3829
3830 return(ret);
3831}
3832
3833/**
3834 * xmlXPathCompParserContext:
3835 * @comp: the XPath compiled expression
3836 * @ctxt: the XPath context
3837 *
3838 * Create a new xmlXPathParserContext when processing a compiled expression
3839 *
3840 * Returns the xmlXPathParserContext just allocated.
3841 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003842static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003843xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3844 xmlXPathParserContextPtr ret;
3845
3846 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3847 if (ret == NULL) {
3848 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003849 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003850 return(NULL);
3851 }
3852 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3853
Owen Taylor3473f882001-02-23 17:55:21 +00003854 /* Allocate the value stack */
3855 ret->valueTab = (xmlXPathObjectPtr *)
3856 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003857 if (ret->valueTab == NULL) {
3858 xmlFree(ret);
3859 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003860 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003861 return(NULL);
3862 }
Owen Taylor3473f882001-02-23 17:55:21 +00003863 ret->valueNr = 0;
3864 ret->valueMax = 10;
3865 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003866
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003867 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003868 ret->comp = comp;
3869
Owen Taylor3473f882001-02-23 17:55:21 +00003870 return(ret);
3871}
3872
3873/**
3874 * xmlXPathFreeParserContext:
3875 * @ctxt: the context to free
3876 *
3877 * Free up an xmlXPathParserContext
3878 */
3879void
3880xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3881 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003882 xmlFree(ctxt->valueTab);
3883 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003884 if (ctxt->comp)
3885 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003886 xmlFree(ctxt);
3887}
3888
3889/************************************************************************
3890 * *
3891 * The implicit core function library *
3892 * *
3893 ************************************************************************/
3894
Owen Taylor3473f882001-02-23 17:55:21 +00003895/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003896 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003897 * @node: a node pointer
3898 *
3899 * Function computing the beginning of the string value of the node,
3900 * used to speed up comparisons
3901 *
3902 * Returns an int usable as a hash
3903 */
3904static unsigned int
3905xmlXPathNodeValHash(xmlNodePtr node) {
3906 int len = 2;
3907 const xmlChar * string = NULL;
3908 xmlNodePtr tmp = NULL;
3909 unsigned int ret = 0;
3910
3911 if (node == NULL)
3912 return(0);
3913
Daniel Veillard9adc0462003-03-24 18:39:54 +00003914 if (node->type == XML_DOCUMENT_NODE) {
3915 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3916 if (tmp == NULL)
3917 node = node->children;
3918 else
3919 node = tmp;
3920
3921 if (node == NULL)
3922 return(0);
3923 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003924
3925 switch (node->type) {
3926 case XML_COMMENT_NODE:
3927 case XML_PI_NODE:
3928 case XML_CDATA_SECTION_NODE:
3929 case XML_TEXT_NODE:
3930 string = node->content;
3931 if (string == NULL)
3932 return(0);
3933 if (string[0] == 0)
3934 return(0);
3935 return(((unsigned int) string[0]) +
3936 (((unsigned int) string[1]) << 8));
3937 case XML_NAMESPACE_DECL:
3938 string = ((xmlNsPtr)node)->href;
3939 if (string == NULL)
3940 return(0);
3941 if (string[0] == 0)
3942 return(0);
3943 return(((unsigned int) string[0]) +
3944 (((unsigned int) string[1]) << 8));
3945 case XML_ATTRIBUTE_NODE:
3946 tmp = ((xmlAttrPtr) node)->children;
3947 break;
3948 case XML_ELEMENT_NODE:
3949 tmp = node->children;
3950 break;
3951 default:
3952 return(0);
3953 }
3954 while (tmp != NULL) {
3955 switch (tmp->type) {
3956 case XML_COMMENT_NODE:
3957 case XML_PI_NODE:
3958 case XML_CDATA_SECTION_NODE:
3959 case XML_TEXT_NODE:
3960 string = tmp->content;
3961 break;
3962 case XML_NAMESPACE_DECL:
3963 string = ((xmlNsPtr)tmp)->href;
3964 break;
3965 default:
3966 break;
3967 }
3968 if ((string != NULL) && (string[0] != 0)) {
3969 if (string[0] == 0)
3970 return(0);
3971 if (len == 1) {
3972 return(ret + (((unsigned int) string[0]) << 8));
3973 }
3974 if (string[1] == 0) {
3975 len = 1;
3976 ret = (unsigned int) string[0];
3977 } else {
3978 return(((unsigned int) string[0]) +
3979 (((unsigned int) string[1]) << 8));
3980 }
3981 }
3982 /*
3983 * Skip to next node
3984 */
3985 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3986 if (tmp->children->type != XML_ENTITY_DECL) {
3987 tmp = tmp->children;
3988 continue;
3989 }
3990 }
3991 if (tmp == node)
3992 break;
3993
3994 if (tmp->next != NULL) {
3995 tmp = tmp->next;
3996 continue;
3997 }
3998
3999 do {
4000 tmp = tmp->parent;
4001 if (tmp == NULL)
4002 break;
4003 if (tmp == node) {
4004 tmp = NULL;
4005 break;
4006 }
4007 if (tmp->next != NULL) {
4008 tmp = tmp->next;
4009 break;
4010 }
4011 } while (tmp != NULL);
4012 }
4013 return(ret);
4014}
4015
4016/**
4017 * xmlXPathStringHash:
4018 * @string: a string
4019 *
4020 * Function computing the beginning of the string value of the node,
4021 * used to speed up comparisons
4022 *
4023 * Returns an int usable as a hash
4024 */
4025static unsigned int
4026xmlXPathStringHash(const xmlChar * string) {
4027 if (string == NULL)
4028 return((unsigned int) 0);
4029 if (string[0] == 0)
4030 return(0);
4031 return(((unsigned int) string[0]) +
4032 (((unsigned int) string[1]) << 8));
4033}
4034
4035/**
Owen Taylor3473f882001-02-23 17:55:21 +00004036 * xmlXPathCompareNodeSetFloat:
4037 * @ctxt: the XPath Parser context
4038 * @inf: less than (1) or greater than (0)
4039 * @strict: is the comparison strict
4040 * @arg: the node set
4041 * @f: the value
4042 *
4043 * Implement the compare operation between a nodeset and a number
4044 * @ns < @val (1, 1, ...
4045 * @ns <= @val (1, 0, ...
4046 * @ns > @val (0, 1, ...
4047 * @ns >= @val (0, 0, ...
4048 *
4049 * If one object to be compared is a node-set and the other is a number,
4050 * then the comparison will be true if and only if there is a node in the
4051 * node-set such that the result of performing the comparison on the number
4052 * to be compared and on the result of converting the string-value of that
4053 * node to a number using the number function is true.
4054 *
4055 * Returns 0 or 1 depending on the results of the test.
4056 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004057static int
Owen Taylor3473f882001-02-23 17:55:21 +00004058xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4059 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4060 int i, ret = 0;
4061 xmlNodeSetPtr ns;
4062 xmlChar *str2;
4063
4064 if ((f == NULL) || (arg == NULL) ||
4065 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4066 xmlXPathFreeObject(arg);
4067 xmlXPathFreeObject(f);
4068 return(0);
4069 }
4070 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004071 if (ns != NULL) {
4072 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004073 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004074 if (str2 != NULL) {
4075 valuePush(ctxt,
4076 xmlXPathNewString(str2));
4077 xmlFree(str2);
4078 xmlXPathNumberFunction(ctxt, 1);
4079 valuePush(ctxt, xmlXPathObjectCopy(f));
4080 ret = xmlXPathCompareValues(ctxt, inf, strict);
4081 if (ret)
4082 break;
4083 }
4084 }
Owen Taylor3473f882001-02-23 17:55:21 +00004085 }
4086 xmlXPathFreeObject(arg);
4087 xmlXPathFreeObject(f);
4088 return(ret);
4089}
4090
4091/**
4092 * xmlXPathCompareNodeSetString:
4093 * @ctxt: the XPath Parser context
4094 * @inf: less than (1) or greater than (0)
4095 * @strict: is the comparison strict
4096 * @arg: the node set
4097 * @s: the value
4098 *
4099 * Implement the compare operation between a nodeset and a string
4100 * @ns < @val (1, 1, ...
4101 * @ns <= @val (1, 0, ...
4102 * @ns > @val (0, 1, ...
4103 * @ns >= @val (0, 0, ...
4104 *
4105 * If one object to be compared is a node-set and the other is a string,
4106 * then the comparison will be true if and only if there is a node in
4107 * the node-set such that the result of performing the comparison on the
4108 * string-value of the node and the other string is true.
4109 *
4110 * Returns 0 or 1 depending on the results of the test.
4111 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004112static int
Owen Taylor3473f882001-02-23 17:55:21 +00004113xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4114 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4115 int i, ret = 0;
4116 xmlNodeSetPtr ns;
4117 xmlChar *str2;
4118
4119 if ((s == NULL) || (arg == NULL) ||
4120 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4121 xmlXPathFreeObject(arg);
4122 xmlXPathFreeObject(s);
4123 return(0);
4124 }
4125 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004126 if (ns != NULL) {
4127 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004128 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004129 if (str2 != NULL) {
4130 valuePush(ctxt,
4131 xmlXPathNewString(str2));
4132 xmlFree(str2);
4133 valuePush(ctxt, xmlXPathObjectCopy(s));
4134 ret = xmlXPathCompareValues(ctxt, inf, strict);
4135 if (ret)
4136 break;
4137 }
4138 }
Owen Taylor3473f882001-02-23 17:55:21 +00004139 }
4140 xmlXPathFreeObject(arg);
4141 xmlXPathFreeObject(s);
4142 return(ret);
4143}
4144
4145/**
4146 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004147 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004148 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004149 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004150 * @arg2: the second node set object
4151 *
4152 * Implement the compare operation on nodesets:
4153 *
4154 * If both objects to be compared are node-sets, then the comparison
4155 * will be true if and only if there is a node in the first node-set
4156 * and a node in the second node-set such that the result of performing
4157 * the comparison on the string-values of the two nodes is true.
4158 * ....
4159 * When neither object to be compared is a node-set and the operator
4160 * is <=, <, >= or >, then the objects are compared by converting both
4161 * objects to numbers and comparing the numbers according to IEEE 754.
4162 * ....
4163 * The number function converts its argument to a number as follows:
4164 * - a string that consists of optional whitespace followed by an
4165 * optional minus sign followed by a Number followed by whitespace
4166 * is converted to the IEEE 754 number that is nearest (according
4167 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4168 * represented by the string; any other string is converted to NaN
4169 *
4170 * Conclusion all nodes need to be converted first to their string value
4171 * and then the comparison must be done when possible
4172 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004173static int
4174xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004175 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4176 int i, j, init = 0;
4177 double val1;
4178 double *values2;
4179 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004180 xmlNodeSetPtr ns1;
4181 xmlNodeSetPtr ns2;
4182
4183 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004184 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4185 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004186 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004187 }
Owen Taylor3473f882001-02-23 17:55:21 +00004188 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004189 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4190 xmlXPathFreeObject(arg1);
4191 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004192 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004193 }
Owen Taylor3473f882001-02-23 17:55:21 +00004194
4195 ns1 = arg1->nodesetval;
4196 ns2 = arg2->nodesetval;
4197
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004198 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004199 xmlXPathFreeObject(arg1);
4200 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004201 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004202 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004203 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004204 xmlXPathFreeObject(arg1);
4205 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004206 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004207 }
Owen Taylor3473f882001-02-23 17:55:21 +00004208
4209 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4210 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004211 xmlXPathFreeObject(arg1);
4212 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004213 return(0);
4214 }
4215 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004216 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004217 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004218 continue;
4219 for (j = 0;j < ns2->nodeNr;j++) {
4220 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004221 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004222 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004223 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004224 continue;
4225 if (inf && strict)
4226 ret = (val1 < values2[j]);
4227 else if (inf && !strict)
4228 ret = (val1 <= values2[j]);
4229 else if (!inf && strict)
4230 ret = (val1 > values2[j]);
4231 else if (!inf && !strict)
4232 ret = (val1 >= values2[j]);
4233 if (ret)
4234 break;
4235 }
4236 if (ret)
4237 break;
4238 init = 1;
4239 }
4240 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004241 xmlXPathFreeObject(arg1);
4242 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004243 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004244}
4245
4246/**
4247 * xmlXPathCompareNodeSetValue:
4248 * @ctxt: the XPath Parser context
4249 * @inf: less than (1) or greater than (0)
4250 * @strict: is the comparison strict
4251 * @arg: the node set
4252 * @val: the value
4253 *
4254 * Implement the compare operation between a nodeset and a value
4255 * @ns < @val (1, 1, ...
4256 * @ns <= @val (1, 0, ...
4257 * @ns > @val (0, 1, ...
4258 * @ns >= @val (0, 0, ...
4259 *
4260 * If one object to be compared is a node-set and the other is a boolean,
4261 * then the comparison will be true if and only if the result of performing
4262 * the comparison on the boolean and on the result of converting
4263 * the node-set to a boolean using the boolean function is true.
4264 *
4265 * Returns 0 or 1 depending on the results of the test.
4266 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004267static int
Owen Taylor3473f882001-02-23 17:55:21 +00004268xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4269 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4270 if ((val == NULL) || (arg == NULL) ||
4271 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4272 return(0);
4273
4274 switch(val->type) {
4275 case XPATH_NUMBER:
4276 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4277 case XPATH_NODESET:
4278 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004279 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004280 case XPATH_STRING:
4281 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4282 case XPATH_BOOLEAN:
4283 valuePush(ctxt, arg);
4284 xmlXPathBooleanFunction(ctxt, 1);
4285 valuePush(ctxt, val);
4286 return(xmlXPathCompareValues(ctxt, inf, strict));
4287 default:
4288 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004289 }
4290 return(0);
4291}
4292
4293/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004294 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004295 * @arg: the nodeset object argument
4296 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004297 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004298 *
4299 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4300 * If one object to be compared is a node-set and the other is a string,
4301 * then the comparison will be true if and only if there is a node in
4302 * the node-set such that the result of performing the comparison on the
4303 * string-value of the node and the other string is true.
4304 *
4305 * Returns 0 or 1 depending on the results of the test.
4306 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004307static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004308xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004309{
Owen Taylor3473f882001-02-23 17:55:21 +00004310 int i;
4311 xmlNodeSetPtr ns;
4312 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004313 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004314
4315 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004316 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4317 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004318 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004319 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004320 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004321 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004322 if (ns->nodeNr <= 0) {
4323 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004324 return(neq ^ 1);
4325 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004326 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004327 for (i = 0; i < ns->nodeNr; i++) {
4328 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4329 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4330 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4331 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004332 if (neq)
4333 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004334 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004335 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4336 if (neq)
4337 continue;
4338 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004339 } else if (neq) {
4340 if (str2 != NULL)
4341 xmlFree(str2);
4342 return (1);
4343 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004344 if (str2 != NULL)
4345 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004346 } else if (neq)
4347 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004348 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004349 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004350}
4351
4352/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004353 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004354 * @arg: the nodeset object argument
4355 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004356 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004357 *
4358 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4359 * If one object to be compared is a node-set and the other is a number,
4360 * then the comparison will be true if and only if there is a node in
4361 * the node-set such that the result of performing the comparison on the
4362 * number to be compared and on the result of converting the string-value
4363 * of that node to a number using the number function is true.
4364 *
4365 * Returns 0 or 1 depending on the results of the test.
4366 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004367static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004368xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4369 xmlXPathObjectPtr arg, double f, int neq) {
4370 int i, ret=0;
4371 xmlNodeSetPtr ns;
4372 xmlChar *str2;
4373 xmlXPathObjectPtr val;
4374 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004375
4376 if ((arg == NULL) ||
4377 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4378 return(0);
4379
William M. Brack0c022ad2002-07-12 00:56:01 +00004380 ns = arg->nodesetval;
4381 if (ns != NULL) {
4382 for (i=0;i<ns->nodeNr;i++) {
4383 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4384 if (str2 != NULL) {
4385 valuePush(ctxt, xmlXPathNewString(str2));
4386 xmlFree(str2);
4387 xmlXPathNumberFunction(ctxt, 1);
4388 val = valuePop(ctxt);
4389 v = val->floatval;
4390 xmlXPathFreeObject(val);
4391 if (!xmlXPathIsNaN(v)) {
4392 if ((!neq) && (v==f)) {
4393 ret = 1;
4394 break;
4395 } else if ((neq) && (v!=f)) {
4396 ret = 1;
4397 break;
4398 }
4399 }
4400 }
4401 }
4402 }
4403
4404 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004405}
4406
4407
4408/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004409 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004410 * @arg1: first nodeset object argument
4411 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004412 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004413 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004414 * Implement the equal / not equal operation on XPath nodesets:
4415 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004416 * If both objects to be compared are node-sets, then the comparison
4417 * will be true if and only if there is a node in the first node-set and
4418 * a node in the second node-set such that the result of performing the
4419 * comparison on the string-values of the two nodes is true.
4420 *
4421 * (needless to say, this is a costly operation)
4422 *
4423 * Returns 0 or 1 depending on the results of the test.
4424 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004425static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004426xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004427 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004428 unsigned int *hashs1;
4429 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004430 xmlChar **values1;
4431 xmlChar **values2;
4432 int ret = 0;
4433 xmlNodeSetPtr ns1;
4434 xmlNodeSetPtr ns2;
4435
4436 if ((arg1 == NULL) ||
4437 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4438 return(0);
4439 if ((arg2 == NULL) ||
4440 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4441 return(0);
4442
4443 ns1 = arg1->nodesetval;
4444 ns2 = arg2->nodesetval;
4445
Daniel Veillard911f49a2001-04-07 15:39:35 +00004446 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004447 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004448 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004449 return(0);
4450
4451 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004452 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004453 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004454 if (neq == 0)
4455 for (i = 0;i < ns1->nodeNr;i++)
4456 for (j = 0;j < ns2->nodeNr;j++)
4457 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4458 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004459
4460 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4461 if (values1 == NULL)
4462 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004463 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4464 if (hashs1 == NULL) {
4465 xmlFree(values1);
4466 return(0);
4467 }
Owen Taylor3473f882001-02-23 17:55:21 +00004468 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4469 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4470 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004471 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004472 xmlFree(values1);
4473 return(0);
4474 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004475 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4476 if (hashs2 == NULL) {
4477 xmlFree(hashs1);
4478 xmlFree(values1);
4479 xmlFree(values2);
4480 return(0);
4481 }
Owen Taylor3473f882001-02-23 17:55:21 +00004482 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4483 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004484 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004485 for (j = 0;j < ns2->nodeNr;j++) {
4486 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004487 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004488 if (hashs1[i] != hashs2[j]) {
4489 if (neq) {
4490 ret = 1;
4491 break;
4492 }
4493 }
4494 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004495 if (values1[i] == NULL)
4496 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4497 if (values2[j] == NULL)
4498 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004499 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004500 if (ret)
4501 break;
4502 }
Owen Taylor3473f882001-02-23 17:55:21 +00004503 }
4504 if (ret)
4505 break;
4506 }
4507 for (i = 0;i < ns1->nodeNr;i++)
4508 if (values1[i] != NULL)
4509 xmlFree(values1[i]);
4510 for (j = 0;j < ns2->nodeNr;j++)
4511 if (values2[j] != NULL)
4512 xmlFree(values2[j]);
4513 xmlFree(values1);
4514 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004515 xmlFree(hashs1);
4516 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004517 return(ret);
4518}
4519
William M. Brack0c022ad2002-07-12 00:56:01 +00004520static int
4521xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4522 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004523 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004524 /*
4525 *At this point we are assured neither arg1 nor arg2
4526 *is a nodeset, so we can just pick the appropriate routine.
4527 */
Owen Taylor3473f882001-02-23 17:55:21 +00004528 switch (arg1->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 switch (arg2->type) {
4537 case XPATH_UNDEFINED:
4538#ifdef DEBUG_EXPR
4539 xmlGenericError(xmlGenericErrorContext,
4540 "Equal: undefined\n");
4541#endif
4542 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004543 case XPATH_BOOLEAN:
4544#ifdef DEBUG_EXPR
4545 xmlGenericError(xmlGenericErrorContext,
4546 "Equal: %d boolean %d \n",
4547 arg1->boolval, arg2->boolval);
4548#endif
4549 ret = (arg1->boolval == arg2->boolval);
4550 break;
4551 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004552 ret = (arg1->boolval ==
4553 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004554 break;
4555 case XPATH_STRING:
4556 if ((arg2->stringval == NULL) ||
4557 (arg2->stringval[0] == 0)) ret = 0;
4558 else
4559 ret = 1;
4560 ret = (arg1->boolval == ret);
4561 break;
4562 case XPATH_USERS:
4563 case XPATH_POINT:
4564 case XPATH_RANGE:
4565 case XPATH_LOCATIONSET:
4566 TODO
4567 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004568 case XPATH_NODESET:
4569 case XPATH_XSLT_TREE:
4570 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004571 }
4572 break;
4573 case XPATH_NUMBER:
4574 switch (arg2->type) {
4575 case XPATH_UNDEFINED:
4576#ifdef DEBUG_EXPR
4577 xmlGenericError(xmlGenericErrorContext,
4578 "Equal: undefined\n");
4579#endif
4580 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004581 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004582 ret = (arg2->boolval==
4583 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004584 break;
4585 case XPATH_STRING:
4586 valuePush(ctxt, arg2);
4587 xmlXPathNumberFunction(ctxt, 1);
4588 arg2 = valuePop(ctxt);
4589 /* no break on purpose */
4590 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004591 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004592 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4593 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004594 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4595 if (xmlXPathIsInf(arg2->floatval) == 1)
4596 ret = 1;
4597 else
4598 ret = 0;
4599 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4600 if (xmlXPathIsInf(arg2->floatval) == -1)
4601 ret = 1;
4602 else
4603 ret = 0;
4604 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4605 if (xmlXPathIsInf(arg1->floatval) == 1)
4606 ret = 1;
4607 else
4608 ret = 0;
4609 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4610 if (xmlXPathIsInf(arg1->floatval) == -1)
4611 ret = 1;
4612 else
4613 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004614 } else {
4615 ret = (arg1->floatval == arg2->floatval);
4616 }
Owen Taylor3473f882001-02-23 17:55:21 +00004617 break;
4618 case XPATH_USERS:
4619 case XPATH_POINT:
4620 case XPATH_RANGE:
4621 case XPATH_LOCATIONSET:
4622 TODO
4623 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004624 case XPATH_NODESET:
4625 case XPATH_XSLT_TREE:
4626 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004627 }
4628 break;
4629 case XPATH_STRING:
4630 switch (arg2->type) {
4631 case XPATH_UNDEFINED:
4632#ifdef DEBUG_EXPR
4633 xmlGenericError(xmlGenericErrorContext,
4634 "Equal: undefined\n");
4635#endif
4636 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004637 case XPATH_BOOLEAN:
4638 if ((arg1->stringval == NULL) ||
4639 (arg1->stringval[0] == 0)) ret = 0;
4640 else
4641 ret = 1;
4642 ret = (arg2->boolval == ret);
4643 break;
4644 case XPATH_STRING:
4645 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4646 break;
4647 case XPATH_NUMBER:
4648 valuePush(ctxt, arg1);
4649 xmlXPathNumberFunction(ctxt, 1);
4650 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004651 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004652 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4653 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004654 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4655 if (xmlXPathIsInf(arg2->floatval) == 1)
4656 ret = 1;
4657 else
4658 ret = 0;
4659 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4660 if (xmlXPathIsInf(arg2->floatval) == -1)
4661 ret = 1;
4662 else
4663 ret = 0;
4664 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4665 if (xmlXPathIsInf(arg1->floatval) == 1)
4666 ret = 1;
4667 else
4668 ret = 0;
4669 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4670 if (xmlXPathIsInf(arg1->floatval) == -1)
4671 ret = 1;
4672 else
4673 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004674 } else {
4675 ret = (arg1->floatval == arg2->floatval);
4676 }
Owen Taylor3473f882001-02-23 17:55:21 +00004677 break;
4678 case XPATH_USERS:
4679 case XPATH_POINT:
4680 case XPATH_RANGE:
4681 case XPATH_LOCATIONSET:
4682 TODO
4683 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004684 case XPATH_NODESET:
4685 case XPATH_XSLT_TREE:
4686 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004687 }
4688 break;
4689 case XPATH_USERS:
4690 case XPATH_POINT:
4691 case XPATH_RANGE:
4692 case XPATH_LOCATIONSET:
4693 TODO
4694 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004695 case XPATH_NODESET:
4696 case XPATH_XSLT_TREE:
4697 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004698 }
4699 xmlXPathFreeObject(arg1);
4700 xmlXPathFreeObject(arg2);
4701 return(ret);
4702}
4703
William M. Brack0c022ad2002-07-12 00:56:01 +00004704/**
4705 * xmlXPathEqualValues:
4706 * @ctxt: the XPath Parser context
4707 *
4708 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4709 *
4710 * Returns 0 or 1 depending on the results of the test.
4711 */
4712int
4713xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4714 xmlXPathObjectPtr arg1, arg2, argtmp;
4715 int ret = 0;
4716
4717 arg2 = valuePop(ctxt);
4718 arg1 = valuePop(ctxt);
4719 if ((arg1 == NULL) || (arg2 == NULL)) {
4720 if (arg1 != NULL)
4721 xmlXPathFreeObject(arg1);
4722 else
4723 xmlXPathFreeObject(arg2);
4724 XP_ERROR0(XPATH_INVALID_OPERAND);
4725 }
4726
4727 if (arg1 == arg2) {
4728#ifdef DEBUG_EXPR
4729 xmlGenericError(xmlGenericErrorContext,
4730 "Equal: by pointer\n");
4731#endif
4732 return(1);
4733 }
4734
4735 /*
4736 *If either argument is a nodeset, it's a 'special case'
4737 */
4738 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4739 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4740 /*
4741 *Hack it to assure arg1 is the nodeset
4742 */
4743 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4744 argtmp = arg2;
4745 arg2 = arg1;
4746 arg1 = argtmp;
4747 }
4748 switch (arg2->type) {
4749 case XPATH_UNDEFINED:
4750#ifdef DEBUG_EXPR
4751 xmlGenericError(xmlGenericErrorContext,
4752 "Equal: undefined\n");
4753#endif
4754 break;
4755 case XPATH_NODESET:
4756 case XPATH_XSLT_TREE:
4757 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4758 break;
4759 case XPATH_BOOLEAN:
4760 if ((arg1->nodesetval == NULL) ||
4761 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4762 else
4763 ret = 1;
4764 ret = (ret == arg2->boolval);
4765 break;
4766 case XPATH_NUMBER:
4767 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4768 break;
4769 case XPATH_STRING:
4770 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4771 break;
4772 case XPATH_USERS:
4773 case XPATH_POINT:
4774 case XPATH_RANGE:
4775 case XPATH_LOCATIONSET:
4776 TODO
4777 break;
4778 }
4779 xmlXPathFreeObject(arg1);
4780 xmlXPathFreeObject(arg2);
4781 return(ret);
4782 }
4783
4784 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4785}
4786
4787/**
4788 * xmlXPathNotEqualValues:
4789 * @ctxt: the XPath Parser context
4790 *
4791 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4792 *
4793 * Returns 0 or 1 depending on the results of the test.
4794 */
4795int
4796xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4797 xmlXPathObjectPtr arg1, arg2, argtmp;
4798 int ret = 0;
4799
4800 arg2 = valuePop(ctxt);
4801 arg1 = valuePop(ctxt);
4802 if ((arg1 == NULL) || (arg2 == NULL)) {
4803 if (arg1 != NULL)
4804 xmlXPathFreeObject(arg1);
4805 else
4806 xmlXPathFreeObject(arg2);
4807 XP_ERROR0(XPATH_INVALID_OPERAND);
4808 }
4809
4810 if (arg1 == arg2) {
4811#ifdef DEBUG_EXPR
4812 xmlGenericError(xmlGenericErrorContext,
4813 "NotEqual: by pointer\n");
4814#endif
4815 return(0);
4816 }
4817
4818 /*
4819 *If either argument is a nodeset, it's a 'special case'
4820 */
4821 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4822 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4823 /*
4824 *Hack it to assure arg1 is the nodeset
4825 */
4826 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4827 argtmp = arg2;
4828 arg2 = arg1;
4829 arg1 = argtmp;
4830 }
4831 switch (arg2->type) {
4832 case XPATH_UNDEFINED:
4833#ifdef DEBUG_EXPR
4834 xmlGenericError(xmlGenericErrorContext,
4835 "NotEqual: undefined\n");
4836#endif
4837 break;
4838 case XPATH_NODESET:
4839 case XPATH_XSLT_TREE:
4840 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4841 break;
4842 case XPATH_BOOLEAN:
4843 if ((arg1->nodesetval == NULL) ||
4844 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4845 else
4846 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004847 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004848 break;
4849 case XPATH_NUMBER:
4850 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4851 break;
4852 case XPATH_STRING:
4853 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4854 break;
4855 case XPATH_USERS:
4856 case XPATH_POINT:
4857 case XPATH_RANGE:
4858 case XPATH_LOCATIONSET:
4859 TODO
4860 break;
4861 }
4862 xmlXPathFreeObject(arg1);
4863 xmlXPathFreeObject(arg2);
4864 return(ret);
4865 }
4866
4867 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4868}
Owen Taylor3473f882001-02-23 17:55:21 +00004869
4870/**
4871 * xmlXPathCompareValues:
4872 * @ctxt: the XPath Parser context
4873 * @inf: less than (1) or greater than (0)
4874 * @strict: is the comparison strict
4875 *
4876 * Implement the compare operation on XPath objects:
4877 * @arg1 < @arg2 (1, 1, ...
4878 * @arg1 <= @arg2 (1, 0, ...
4879 * @arg1 > @arg2 (0, 1, ...
4880 * @arg1 >= @arg2 (0, 0, ...
4881 *
4882 * When neither object to be compared is a node-set and the operator is
4883 * <=, <, >=, >, then the objects are compared by converted both objects
4884 * to numbers and comparing the numbers according to IEEE 754. The <
4885 * comparison will be true if and only if the first number is less than the
4886 * second number. The <= comparison will be true if and only if the first
4887 * number is less than or equal to the second number. The > comparison
4888 * will be true if and only if the first number is greater than the second
4889 * number. The >= comparison will be true if and only if the first number
4890 * is greater than or equal to the second number.
4891 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004892 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004893 */
4894int
4895xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004896 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004897 xmlXPathObjectPtr arg1, arg2;
4898
William M. Brack0c022ad2002-07-12 00:56:01 +00004899 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004900 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004901 if ((arg1 == NULL) || (arg2 == NULL)) {
4902 if (arg1 != NULL)
4903 xmlXPathFreeObject(arg1);
4904 else
4905 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004906 XP_ERROR0(XPATH_INVALID_OPERAND);
4907 }
4908
William M. Brack0c022ad2002-07-12 00:56:01 +00004909 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4910 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4911 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4912 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004913 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004914 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004915 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004916 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4917 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004918 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004919 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4920 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004921 }
4922 }
4923 return(ret);
4924 }
4925
4926 if (arg1->type != XPATH_NUMBER) {
4927 valuePush(ctxt, arg1);
4928 xmlXPathNumberFunction(ctxt, 1);
4929 arg1 = valuePop(ctxt);
4930 }
4931 if (arg1->type != XPATH_NUMBER) {
4932 xmlXPathFreeObject(arg1);
4933 xmlXPathFreeObject(arg2);
4934 XP_ERROR0(XPATH_INVALID_OPERAND);
4935 }
4936 if (arg2->type != XPATH_NUMBER) {
4937 valuePush(ctxt, arg2);
4938 xmlXPathNumberFunction(ctxt, 1);
4939 arg2 = valuePop(ctxt);
4940 }
4941 if (arg2->type != XPATH_NUMBER) {
4942 xmlXPathFreeObject(arg1);
4943 xmlXPathFreeObject(arg2);
4944 XP_ERROR0(XPATH_INVALID_OPERAND);
4945 }
4946 /*
4947 * Add tests for infinity and nan
4948 * => feedback on 3.4 for Inf and NaN
4949 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004950 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004951 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004952 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004953 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004954 arg1i=xmlXPathIsInf(arg1->floatval);
4955 arg2i=xmlXPathIsInf(arg2->floatval);
4956 if (inf && strict) {
4957 if ((arg1i == -1 && arg2i != -1) ||
4958 (arg2i == 1 && arg1i != 1)) {
4959 ret = 1;
4960 } else if (arg1i == 0 && arg2i == 0) {
4961 ret = (arg1->floatval < arg2->floatval);
4962 } else {
4963 ret = 0;
4964 }
4965 }
4966 else if (inf && !strict) {
4967 if (arg1i == -1 || arg2i == 1) {
4968 ret = 1;
4969 } else if (arg1i == 0 && arg2i == 0) {
4970 ret = (arg1->floatval <= arg2->floatval);
4971 } else {
4972 ret = 0;
4973 }
4974 }
4975 else if (!inf && strict) {
4976 if ((arg1i == 1 && arg2i != 1) ||
4977 (arg2i == -1 && arg1i != -1)) {
4978 ret = 1;
4979 } else if (arg1i == 0 && arg2i == 0) {
4980 ret = (arg1->floatval > arg2->floatval);
4981 } else {
4982 ret = 0;
4983 }
4984 }
4985 else if (!inf && !strict) {
4986 if (arg1i == 1 || arg2i == -1) {
4987 ret = 1;
4988 } else if (arg1i == 0 && arg2i == 0) {
4989 ret = (arg1->floatval >= arg2->floatval);
4990 } else {
4991 ret = 0;
4992 }
4993 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004994 }
Owen Taylor3473f882001-02-23 17:55:21 +00004995 xmlXPathFreeObject(arg1);
4996 xmlXPathFreeObject(arg2);
4997 return(ret);
4998}
4999
5000/**
5001 * xmlXPathValueFlipSign:
5002 * @ctxt: the XPath Parser context
5003 *
5004 * Implement the unary - operation on an XPath object
5005 * The numeric operators convert their operands to numbers as if
5006 * by calling the number function.
5007 */
5008void
5009xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005010 CAST_TO_NUMBER;
5011 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005012 if (xmlXPathIsNaN(ctxt->value->floatval))
5013 ctxt->value->floatval=xmlXPathNAN;
5014 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5015 ctxt->value->floatval=xmlXPathNINF;
5016 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5017 ctxt->value->floatval=xmlXPathPINF;
5018 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005019 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5020 ctxt->value->floatval = xmlXPathNZERO;
5021 else
5022 ctxt->value->floatval = 0;
5023 }
5024 else
5025 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005026}
5027
5028/**
5029 * xmlXPathAddValues:
5030 * @ctxt: the XPath Parser context
5031 *
5032 * Implement the add operation on XPath objects:
5033 * The numeric operators convert their operands to numbers as if
5034 * by calling the number function.
5035 */
5036void
5037xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5038 xmlXPathObjectPtr arg;
5039 double val;
5040
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005041 arg = valuePop(ctxt);
5042 if (arg == NULL)
5043 XP_ERROR(XPATH_INVALID_OPERAND);
5044 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005045 xmlXPathFreeObject(arg);
5046
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005047 CAST_TO_NUMBER;
5048 CHECK_TYPE(XPATH_NUMBER);
5049 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005050}
5051
5052/**
5053 * xmlXPathSubValues:
5054 * @ctxt: the XPath Parser context
5055 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005056 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005057 * The numeric operators convert their operands to numbers as if
5058 * by calling the number function.
5059 */
5060void
5061xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5062 xmlXPathObjectPtr arg;
5063 double val;
5064
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005065 arg = valuePop(ctxt);
5066 if (arg == NULL)
5067 XP_ERROR(XPATH_INVALID_OPERAND);
5068 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005069 xmlXPathFreeObject(arg);
5070
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005071 CAST_TO_NUMBER;
5072 CHECK_TYPE(XPATH_NUMBER);
5073 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005074}
5075
5076/**
5077 * xmlXPathMultValues:
5078 * @ctxt: the XPath Parser context
5079 *
5080 * Implement the multiply operation on XPath objects:
5081 * The numeric operators convert their operands to numbers as if
5082 * by calling the number function.
5083 */
5084void
5085xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5086 xmlXPathObjectPtr arg;
5087 double val;
5088
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005089 arg = valuePop(ctxt);
5090 if (arg == NULL)
5091 XP_ERROR(XPATH_INVALID_OPERAND);
5092 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005093 xmlXPathFreeObject(arg);
5094
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005095 CAST_TO_NUMBER;
5096 CHECK_TYPE(XPATH_NUMBER);
5097 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005098}
5099
5100/**
5101 * xmlXPathDivValues:
5102 * @ctxt: the XPath Parser context
5103 *
5104 * Implement the div operation on XPath objects @arg1 / @arg2:
5105 * The numeric operators convert their operands to numbers as if
5106 * by calling the number function.
5107 */
5108void
5109xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5110 xmlXPathObjectPtr arg;
5111 double val;
5112
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005113 arg = valuePop(ctxt);
5114 if (arg == NULL)
5115 XP_ERROR(XPATH_INVALID_OPERAND);
5116 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005117 xmlXPathFreeObject(arg);
5118
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005119 CAST_TO_NUMBER;
5120 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005121 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5122 ctxt->value->floatval = xmlXPathNAN;
5123 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005124 if (ctxt->value->floatval == 0)
5125 ctxt->value->floatval = xmlXPathNAN;
5126 else if (ctxt->value->floatval > 0)
5127 ctxt->value->floatval = xmlXPathNINF;
5128 else if (ctxt->value->floatval < 0)
5129 ctxt->value->floatval = xmlXPathPINF;
5130 }
5131 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005132 if (ctxt->value->floatval == 0)
5133 ctxt->value->floatval = xmlXPathNAN;
5134 else if (ctxt->value->floatval > 0)
5135 ctxt->value->floatval = xmlXPathPINF;
5136 else if (ctxt->value->floatval < 0)
5137 ctxt->value->floatval = xmlXPathNINF;
5138 } else
5139 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005140}
5141
5142/**
5143 * xmlXPathModValues:
5144 * @ctxt: the XPath Parser context
5145 *
5146 * Implement the mod operation on XPath objects: @arg1 / @arg2
5147 * The numeric operators convert their operands to numbers as if
5148 * by calling the number function.
5149 */
5150void
5151xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5152 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005153 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005154
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005155 arg = valuePop(ctxt);
5156 if (arg == NULL)
5157 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005158 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005159 xmlXPathFreeObject(arg);
5160
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005161 CAST_TO_NUMBER;
5162 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005163 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005164 if (arg2 == 0)
5165 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005166 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005167 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005168 }
Owen Taylor3473f882001-02-23 17:55:21 +00005169}
5170
5171/************************************************************************
5172 * *
5173 * The traversal functions *
5174 * *
5175 ************************************************************************/
5176
Owen Taylor3473f882001-02-23 17:55:21 +00005177/*
5178 * A traversal function enumerates nodes along an axis.
5179 * Initially it must be called with NULL, and it indicates
5180 * termination on the axis by returning NULL.
5181 */
5182typedef xmlNodePtr (*xmlXPathTraversalFunction)
5183 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5184
5185/**
5186 * xmlXPathNextSelf:
5187 * @ctxt: the XPath Parser context
5188 * @cur: the current node in the traversal
5189 *
5190 * Traversal function for the "self" direction
5191 * The self axis contains just the context node itself
5192 *
5193 * Returns the next element following that axis
5194 */
5195xmlNodePtr
5196xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5197 if (cur == NULL)
5198 return(ctxt->context->node);
5199 return(NULL);
5200}
5201
5202/**
5203 * xmlXPathNextChild:
5204 * @ctxt: the XPath Parser context
5205 * @cur: the current node in the traversal
5206 *
5207 * Traversal function for the "child" direction
5208 * The child axis contains the children of the context node in document order.
5209 *
5210 * Returns the next element following that axis
5211 */
5212xmlNodePtr
5213xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5214 if (cur == NULL) {
5215 if (ctxt->context->node == NULL) return(NULL);
5216 switch (ctxt->context->node->type) {
5217 case XML_ELEMENT_NODE:
5218 case XML_TEXT_NODE:
5219 case XML_CDATA_SECTION_NODE:
5220 case XML_ENTITY_REF_NODE:
5221 case XML_ENTITY_NODE:
5222 case XML_PI_NODE:
5223 case XML_COMMENT_NODE:
5224 case XML_NOTATION_NODE:
5225 case XML_DTD_NODE:
5226 return(ctxt->context->node->children);
5227 case XML_DOCUMENT_NODE:
5228 case XML_DOCUMENT_TYPE_NODE:
5229 case XML_DOCUMENT_FRAG_NODE:
5230 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005231#ifdef LIBXML_DOCB_ENABLED
5232 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005233#endif
5234 return(((xmlDocPtr) ctxt->context->node)->children);
5235 case XML_ELEMENT_DECL:
5236 case XML_ATTRIBUTE_DECL:
5237 case XML_ENTITY_DECL:
5238 case XML_ATTRIBUTE_NODE:
5239 case XML_NAMESPACE_DECL:
5240 case XML_XINCLUDE_START:
5241 case XML_XINCLUDE_END:
5242 return(NULL);
5243 }
5244 return(NULL);
5245 }
5246 if ((cur->type == XML_DOCUMENT_NODE) ||
5247 (cur->type == XML_HTML_DOCUMENT_NODE))
5248 return(NULL);
5249 return(cur->next);
5250}
5251
5252/**
5253 * xmlXPathNextDescendant:
5254 * @ctxt: the XPath Parser context
5255 * @cur: the current node in the traversal
5256 *
5257 * Traversal function for the "descendant" direction
5258 * the descendant axis contains the descendants of the context node in document
5259 * order; a descendant is a child or a child of a child and so on.
5260 *
5261 * Returns the next element following that axis
5262 */
5263xmlNodePtr
5264xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5265 if (cur == NULL) {
5266 if (ctxt->context->node == NULL)
5267 return(NULL);
5268 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5269 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5270 return(NULL);
5271
5272 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5273 return(ctxt->context->doc->children);
5274 return(ctxt->context->node->children);
5275 }
5276
Daniel Veillard567e1b42001-08-01 15:53:47 +00005277 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005278 /*
5279 * Do not descend on entities declarations
5280 */
5281 if (cur->children->type != XML_ENTITY_DECL) {
5282 cur = cur->children;
5283 /*
5284 * Skip DTDs
5285 */
5286 if (cur->type != XML_DTD_NODE)
5287 return(cur);
5288 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005289 }
5290
5291 if (cur == ctxt->context->node) return(NULL);
5292
Daniel Veillard68e9e742002-11-16 15:35:11 +00005293 while (cur->next != NULL) {
5294 cur = cur->next;
5295 if ((cur->type != XML_ENTITY_DECL) &&
5296 (cur->type != XML_DTD_NODE))
5297 return(cur);
5298 }
Owen Taylor3473f882001-02-23 17:55:21 +00005299
5300 do {
5301 cur = cur->parent;
5302 if (cur == NULL) return(NULL);
5303 if (cur == ctxt->context->node) return(NULL);
5304 if (cur->next != NULL) {
5305 cur = cur->next;
5306 return(cur);
5307 }
5308 } while (cur != NULL);
5309 return(cur);
5310}
5311
5312/**
5313 * xmlXPathNextDescendantOrSelf:
5314 * @ctxt: the XPath Parser context
5315 * @cur: the current node in the traversal
5316 *
5317 * Traversal function for the "descendant-or-self" direction
5318 * the descendant-or-self axis contains the context node and the descendants
5319 * of the context node in document order; thus the context node is the first
5320 * node on the axis, and the first child of the context node is the second node
5321 * on the axis
5322 *
5323 * Returns the next element following that axis
5324 */
5325xmlNodePtr
5326xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5327 if (cur == NULL) {
5328 if (ctxt->context->node == NULL)
5329 return(NULL);
5330 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5331 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5332 return(NULL);
5333 return(ctxt->context->node);
5334 }
5335
5336 return(xmlXPathNextDescendant(ctxt, cur));
5337}
5338
5339/**
5340 * xmlXPathNextParent:
5341 * @ctxt: the XPath Parser context
5342 * @cur: the current node in the traversal
5343 *
5344 * Traversal function for the "parent" direction
5345 * The parent axis contains the parent of the context node, if there is one.
5346 *
5347 * Returns the next element following that axis
5348 */
5349xmlNodePtr
5350xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5351 /*
5352 * the parent of an attribute or namespace node is the element
5353 * to which the attribute or namespace node is attached
5354 * Namespace handling !!!
5355 */
5356 if (cur == NULL) {
5357 if (ctxt->context->node == NULL) return(NULL);
5358 switch (ctxt->context->node->type) {
5359 case XML_ELEMENT_NODE:
5360 case XML_TEXT_NODE:
5361 case XML_CDATA_SECTION_NODE:
5362 case XML_ENTITY_REF_NODE:
5363 case XML_ENTITY_NODE:
5364 case XML_PI_NODE:
5365 case XML_COMMENT_NODE:
5366 case XML_NOTATION_NODE:
5367 case XML_DTD_NODE:
5368 case XML_ELEMENT_DECL:
5369 case XML_ATTRIBUTE_DECL:
5370 case XML_XINCLUDE_START:
5371 case XML_XINCLUDE_END:
5372 case XML_ENTITY_DECL:
5373 if (ctxt->context->node->parent == NULL)
5374 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005375 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005376 ((ctxt->context->node->parent->name[0] == ' ') ||
5377 (xmlStrEqual(ctxt->context->node->parent->name,
5378 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005379 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005380 return(ctxt->context->node->parent);
5381 case XML_ATTRIBUTE_NODE: {
5382 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5383
5384 return(att->parent);
5385 }
5386 case XML_DOCUMENT_NODE:
5387 case XML_DOCUMENT_TYPE_NODE:
5388 case XML_DOCUMENT_FRAG_NODE:
5389 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005390#ifdef LIBXML_DOCB_ENABLED
5391 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005392#endif
5393 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005394 case XML_NAMESPACE_DECL: {
5395 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5396
5397 if ((ns->next != NULL) &&
5398 (ns->next->type != XML_NAMESPACE_DECL))
5399 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005400 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005401 }
Owen Taylor3473f882001-02-23 17:55:21 +00005402 }
5403 }
5404 return(NULL);
5405}
5406
5407/**
5408 * xmlXPathNextAncestor:
5409 * @ctxt: the XPath Parser context
5410 * @cur: the current node in the traversal
5411 *
5412 * Traversal function for the "ancestor" direction
5413 * the ancestor axis contains the ancestors of the context node; the ancestors
5414 * of the context node consist of the parent of context node and the parent's
5415 * parent and so on; the nodes are ordered in reverse document order; thus the
5416 * parent is the first node on the axis, and the parent's parent is the second
5417 * node on the axis
5418 *
5419 * Returns the next element following that axis
5420 */
5421xmlNodePtr
5422xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5423 /*
5424 * the parent of an attribute or namespace node is the element
5425 * to which the attribute or namespace node is attached
5426 * !!!!!!!!!!!!!
5427 */
5428 if (cur == NULL) {
5429 if (ctxt->context->node == NULL) return(NULL);
5430 switch (ctxt->context->node->type) {
5431 case XML_ELEMENT_NODE:
5432 case XML_TEXT_NODE:
5433 case XML_CDATA_SECTION_NODE:
5434 case XML_ENTITY_REF_NODE:
5435 case XML_ENTITY_NODE:
5436 case XML_PI_NODE:
5437 case XML_COMMENT_NODE:
5438 case XML_DTD_NODE:
5439 case XML_ELEMENT_DECL:
5440 case XML_ATTRIBUTE_DECL:
5441 case XML_ENTITY_DECL:
5442 case XML_NOTATION_NODE:
5443 case XML_XINCLUDE_START:
5444 case XML_XINCLUDE_END:
5445 if (ctxt->context->node->parent == NULL)
5446 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005447 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005448 ((ctxt->context->node->parent->name[0] == ' ') ||
5449 (xmlStrEqual(ctxt->context->node->parent->name,
5450 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005451 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005452 return(ctxt->context->node->parent);
5453 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005454 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005455
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005456 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005457 }
5458 case XML_DOCUMENT_NODE:
5459 case XML_DOCUMENT_TYPE_NODE:
5460 case XML_DOCUMENT_FRAG_NODE:
5461 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005462#ifdef LIBXML_DOCB_ENABLED
5463 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005464#endif
5465 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005466 case XML_NAMESPACE_DECL: {
5467 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5468
5469 if ((ns->next != NULL) &&
5470 (ns->next->type != XML_NAMESPACE_DECL))
5471 return((xmlNodePtr) ns->next);
5472 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005473 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005474 }
Owen Taylor3473f882001-02-23 17:55:21 +00005475 }
5476 return(NULL);
5477 }
5478 if (cur == ctxt->context->doc->children)
5479 return((xmlNodePtr) ctxt->context->doc);
5480 if (cur == (xmlNodePtr) ctxt->context->doc)
5481 return(NULL);
5482 switch (cur->type) {
5483 case XML_ELEMENT_NODE:
5484 case XML_TEXT_NODE:
5485 case XML_CDATA_SECTION_NODE:
5486 case XML_ENTITY_REF_NODE:
5487 case XML_ENTITY_NODE:
5488 case XML_PI_NODE:
5489 case XML_COMMENT_NODE:
5490 case XML_NOTATION_NODE:
5491 case XML_DTD_NODE:
5492 case XML_ELEMENT_DECL:
5493 case XML_ATTRIBUTE_DECL:
5494 case XML_ENTITY_DECL:
5495 case XML_XINCLUDE_START:
5496 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005497 if (cur->parent == NULL)
5498 return(NULL);
5499 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005500 ((cur->parent->name[0] == ' ') ||
5501 (xmlStrEqual(cur->parent->name,
5502 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005503 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005504 return(cur->parent);
5505 case XML_ATTRIBUTE_NODE: {
5506 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5507
5508 return(att->parent);
5509 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005510 case XML_NAMESPACE_DECL: {
5511 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5512
5513 if ((ns->next != NULL) &&
5514 (ns->next->type != XML_NAMESPACE_DECL))
5515 return((xmlNodePtr) ns->next);
5516 /* Bad, how did that namespace ended-up there ? */
5517 return(NULL);
5518 }
Owen Taylor3473f882001-02-23 17:55:21 +00005519 case XML_DOCUMENT_NODE:
5520 case XML_DOCUMENT_TYPE_NODE:
5521 case XML_DOCUMENT_FRAG_NODE:
5522 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005523#ifdef LIBXML_DOCB_ENABLED
5524 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005525#endif
5526 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005527 }
5528 return(NULL);
5529}
5530
5531/**
5532 * xmlXPathNextAncestorOrSelf:
5533 * @ctxt: the XPath Parser context
5534 * @cur: the current node in the traversal
5535 *
5536 * Traversal function for the "ancestor-or-self" direction
5537 * he ancestor-or-self axis contains the context node and ancestors of
5538 * the context node in reverse document order; thus the context node is
5539 * the first node on the axis, and the context node's parent the second;
5540 * parent here is defined the same as with the parent axis.
5541 *
5542 * Returns the next element following that axis
5543 */
5544xmlNodePtr
5545xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5546 if (cur == NULL)
5547 return(ctxt->context->node);
5548 return(xmlXPathNextAncestor(ctxt, cur));
5549}
5550
5551/**
5552 * xmlXPathNextFollowingSibling:
5553 * @ctxt: the XPath Parser context
5554 * @cur: the current node in the traversal
5555 *
5556 * Traversal function for the "following-sibling" direction
5557 * The following-sibling axis contains the following siblings of the context
5558 * node in document order.
5559 *
5560 * Returns the next element following that axis
5561 */
5562xmlNodePtr
5563xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5564 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5565 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5566 return(NULL);
5567 if (cur == (xmlNodePtr) ctxt->context->doc)
5568 return(NULL);
5569 if (cur == NULL)
5570 return(ctxt->context->node->next);
5571 return(cur->next);
5572}
5573
5574/**
5575 * xmlXPathNextPrecedingSibling:
5576 * @ctxt: the XPath Parser context
5577 * @cur: the current node in the traversal
5578 *
5579 * Traversal function for the "preceding-sibling" direction
5580 * The preceding-sibling axis contains the preceding siblings of the context
5581 * node in reverse document order; the first preceding sibling is first on the
5582 * axis; the sibling preceding that node is the second on the axis and so on.
5583 *
5584 * Returns the next element following that axis
5585 */
5586xmlNodePtr
5587xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5588 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5589 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5590 return(NULL);
5591 if (cur == (xmlNodePtr) ctxt->context->doc)
5592 return(NULL);
5593 if (cur == NULL)
5594 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005595 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5596 cur = cur->prev;
5597 if (cur == NULL)
5598 return(ctxt->context->node->prev);
5599 }
Owen Taylor3473f882001-02-23 17:55:21 +00005600 return(cur->prev);
5601}
5602
5603/**
5604 * xmlXPathNextFollowing:
5605 * @ctxt: the XPath Parser context
5606 * @cur: the current node in the traversal
5607 *
5608 * Traversal function for the "following" direction
5609 * The following axis contains all nodes in the same document as the context
5610 * node that are after the context node in document order, excluding any
5611 * descendants and excluding attribute nodes and namespace nodes; the nodes
5612 * are ordered in document order
5613 *
5614 * Returns the next element following that axis
5615 */
5616xmlNodePtr
5617xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5618 if (cur != NULL && cur->children != NULL)
5619 return cur->children ;
5620 if (cur == NULL) cur = ctxt->context->node;
5621 if (cur == NULL) return(NULL) ; /* ERROR */
5622 if (cur->next != NULL) return(cur->next) ;
5623 do {
5624 cur = cur->parent;
5625 if (cur == NULL) return(NULL);
5626 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5627 if (cur->next != NULL) return(cur->next);
5628 } while (cur != NULL);
5629 return(cur);
5630}
5631
5632/*
5633 * xmlXPathIsAncestor:
5634 * @ancestor: the ancestor node
5635 * @node: the current node
5636 *
5637 * Check that @ancestor is a @node's ancestor
5638 *
5639 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5640 */
5641static int
5642xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5643 if ((ancestor == NULL) || (node == NULL)) return(0);
5644 /* nodes need to be in the same document */
5645 if (ancestor->doc != node->doc) return(0);
5646 /* avoid searching if ancestor or node is the root node */
5647 if (ancestor == (xmlNodePtr) node->doc) return(1);
5648 if (node == (xmlNodePtr) ancestor->doc) return(0);
5649 while (node->parent != NULL) {
5650 if (node->parent == ancestor)
5651 return(1);
5652 node = node->parent;
5653 }
5654 return(0);
5655}
5656
5657/**
5658 * xmlXPathNextPreceding:
5659 * @ctxt: the XPath Parser context
5660 * @cur: the current node in the traversal
5661 *
5662 * Traversal function for the "preceding" direction
5663 * the preceding axis contains all nodes in the same document as the context
5664 * node that are before the context node in document order, excluding any
5665 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5666 * ordered in reverse document order
5667 *
5668 * Returns the next element following that axis
5669 */
5670xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005671xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5672{
Owen Taylor3473f882001-02-23 17:55:21 +00005673 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005674 cur = ctxt->context->node;
5675 if (cur == NULL)
5676 return (NULL);
5677 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5678 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005679 do {
5680 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005681 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5682 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005683 }
5684
5685 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005686 if (cur == NULL)
5687 return (NULL);
5688 if (cur == ctxt->context->doc->children)
5689 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005690 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005691 return (cur);
5692}
5693
5694/**
5695 * xmlXPathNextPrecedingInternal:
5696 * @ctxt: the XPath Parser context
5697 * @cur: the current node in the traversal
5698 *
5699 * Traversal function for the "preceding" direction
5700 * the preceding axis contains all nodes in the same document as the context
5701 * node that are before the context node in document order, excluding any
5702 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5703 * ordered in reverse document order
5704 * This is a faster implementation but internal only since it requires a
5705 * state kept in the parser context: ctxt->ancestor.
5706 *
5707 * Returns the next element following that axis
5708 */
5709static xmlNodePtr
5710xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5711 xmlNodePtr cur)
5712{
5713 if (cur == NULL) {
5714 cur = ctxt->context->node;
5715 if (cur == NULL)
5716 return (NULL);
5717 ctxt->ancestor = cur->parent;
5718 }
5719 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5720 cur = cur->prev;
5721 while (cur->prev == NULL) {
5722 cur = cur->parent;
5723 if (cur == NULL)
5724 return (NULL);
5725 if (cur == ctxt->context->doc->children)
5726 return (NULL);
5727 if (cur != ctxt->ancestor)
5728 return (cur);
5729 ctxt->ancestor = cur->parent;
5730 }
5731 cur = cur->prev;
5732 while (cur->last != NULL)
5733 cur = cur->last;
5734 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005735}
5736
5737/**
5738 * xmlXPathNextNamespace:
5739 * @ctxt: the XPath Parser context
5740 * @cur: the current attribute in the traversal
5741 *
5742 * Traversal function for the "namespace" direction
5743 * the namespace axis contains the namespace nodes of the context node;
5744 * the order of nodes on this axis is implementation-defined; the axis will
5745 * be empty unless the context node is an element
5746 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005747 * We keep the XML namespace node at the end of the list.
5748 *
Owen Taylor3473f882001-02-23 17:55:21 +00005749 * Returns the next element following that axis
5750 */
5751xmlNodePtr
5752xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5753 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005754 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005755 if (ctxt->context->tmpNsList != NULL)
5756 xmlFree(ctxt->context->tmpNsList);
5757 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005758 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005759 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005760 if (ctxt->context->tmpNsList != NULL) {
5761 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5762 ctxt->context->tmpNsNr++;
5763 }
5764 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005765 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005766 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005767 if (ctxt->context->tmpNsNr > 0) {
5768 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5769 } else {
5770 if (ctxt->context->tmpNsList != NULL)
5771 xmlFree(ctxt->context->tmpNsList);
5772 ctxt->context->tmpNsList = NULL;
5773 return(NULL);
5774 }
Owen Taylor3473f882001-02-23 17:55:21 +00005775}
5776
5777/**
5778 * xmlXPathNextAttribute:
5779 * @ctxt: the XPath Parser context
5780 * @cur: the current attribute in the traversal
5781 *
5782 * Traversal function for the "attribute" direction
5783 * TODO: support DTD inherited default attributes
5784 *
5785 * Returns the next element following that axis
5786 */
5787xmlNodePtr
5788xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005789 if (ctxt->context->node == NULL)
5790 return(NULL);
5791 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5792 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005793 if (cur == NULL) {
5794 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5795 return(NULL);
5796 return((xmlNodePtr)ctxt->context->node->properties);
5797 }
5798 return((xmlNodePtr)cur->next);
5799}
5800
5801/************************************************************************
5802 * *
5803 * NodeTest Functions *
5804 * *
5805 ************************************************************************/
5806
Owen Taylor3473f882001-02-23 17:55:21 +00005807#define IS_FUNCTION 200
5808
Owen Taylor3473f882001-02-23 17:55:21 +00005809
5810/************************************************************************
5811 * *
5812 * Implicit tree core function library *
5813 * *
5814 ************************************************************************/
5815
5816/**
5817 * xmlXPathRoot:
5818 * @ctxt: the XPath Parser context
5819 *
5820 * Initialize the context to the root of the document
5821 */
5822void
5823xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5824 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5825 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5826}
5827
5828/************************************************************************
5829 * *
5830 * The explicit core function library *
5831 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5832 * *
5833 ************************************************************************/
5834
5835
5836/**
5837 * xmlXPathLastFunction:
5838 * @ctxt: the XPath Parser context
5839 * @nargs: the number of arguments
5840 *
5841 * Implement the last() XPath function
5842 * number last()
5843 * The last function returns the number of nodes in the context node list.
5844 */
5845void
5846xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5847 CHECK_ARITY(0);
5848 if (ctxt->context->contextSize >= 0) {
5849 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5850#ifdef DEBUG_EXPR
5851 xmlGenericError(xmlGenericErrorContext,
5852 "last() : %d\n", ctxt->context->contextSize);
5853#endif
5854 } else {
5855 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5856 }
5857}
5858
5859/**
5860 * xmlXPathPositionFunction:
5861 * @ctxt: the XPath Parser context
5862 * @nargs: the number of arguments
5863 *
5864 * Implement the position() XPath function
5865 * number position()
5866 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005867 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005868 * will be equal to last().
5869 */
5870void
5871xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5872 CHECK_ARITY(0);
5873 if (ctxt->context->proximityPosition >= 0) {
5874 valuePush(ctxt,
5875 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5876#ifdef DEBUG_EXPR
5877 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5878 ctxt->context->proximityPosition);
5879#endif
5880 } else {
5881 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5882 }
5883}
5884
5885/**
5886 * xmlXPathCountFunction:
5887 * @ctxt: the XPath Parser context
5888 * @nargs: the number of arguments
5889 *
5890 * Implement the count() XPath function
5891 * number count(node-set)
5892 */
5893void
5894xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5895 xmlXPathObjectPtr cur;
5896
5897 CHECK_ARITY(1);
5898 if ((ctxt->value == NULL) ||
5899 ((ctxt->value->type != XPATH_NODESET) &&
5900 (ctxt->value->type != XPATH_XSLT_TREE)))
5901 XP_ERROR(XPATH_INVALID_TYPE);
5902 cur = valuePop(ctxt);
5903
Daniel Veillard911f49a2001-04-07 15:39:35 +00005904 if ((cur == NULL) || (cur->nodesetval == NULL))
5905 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005906 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005907 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005908 } else {
5909 if ((cur->nodesetval->nodeNr != 1) ||
5910 (cur->nodesetval->nodeTab == NULL)) {
5911 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5912 } else {
5913 xmlNodePtr tmp;
5914 int i = 0;
5915
5916 tmp = cur->nodesetval->nodeTab[0];
5917 if (tmp != NULL) {
5918 tmp = tmp->children;
5919 while (tmp != NULL) {
5920 tmp = tmp->next;
5921 i++;
5922 }
5923 }
5924 valuePush(ctxt, xmlXPathNewFloat((double) i));
5925 }
5926 }
Owen Taylor3473f882001-02-23 17:55:21 +00005927 xmlXPathFreeObject(cur);
5928}
5929
5930/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005931 * xmlXPathGetElementsByIds:
5932 * @doc: the document
5933 * @ids: a whitespace separated list of IDs
5934 *
5935 * Selects elements by their unique ID.
5936 *
5937 * Returns a node-set of selected elements.
5938 */
5939static xmlNodeSetPtr
5940xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5941 xmlNodeSetPtr ret;
5942 const xmlChar *cur = ids;
5943 xmlChar *ID;
5944 xmlAttrPtr attr;
5945 xmlNodePtr elem = NULL;
5946
Daniel Veillard7a985a12003-07-06 17:57:42 +00005947 if (ids == NULL) return(NULL);
5948
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005949 ret = xmlXPathNodeSetCreate(NULL);
5950
5951 while (IS_BLANK(*cur)) cur++;
5952 while (*cur != 0) {
Daniel Veillarde209b332003-03-26 21:40:13 +00005953 while ((!IS_BLANK(*cur)) && (*cur != 0))
5954 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005955
5956 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00005957 if (ID != NULL) {
5958 if (xmlValidateNCName(ID, 1) == 0) {
5959 attr = xmlGetID(doc, ID);
5960 if (attr != NULL) {
5961 if (attr->type == XML_ATTRIBUTE_NODE)
5962 elem = attr->parent;
5963 else if (attr->type == XML_ELEMENT_NODE)
5964 elem = (xmlNodePtr) attr;
5965 else
5966 elem = NULL;
5967 if (elem != NULL)
5968 xmlXPathNodeSetAdd(ret, elem);
5969 }
5970 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005971 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00005972 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005973
5974 while (IS_BLANK(*cur)) cur++;
5975 ids = cur;
5976 }
5977 return(ret);
5978}
5979
5980/**
Owen Taylor3473f882001-02-23 17:55:21 +00005981 * xmlXPathIdFunction:
5982 * @ctxt: the XPath Parser context
5983 * @nargs: the number of arguments
5984 *
5985 * Implement the id() XPath function
5986 * node-set id(object)
5987 * The id function selects elements by their unique ID
5988 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5989 * then the result is the union of the result of applying id to the
5990 * string value of each of the nodes in the argument node-set. When the
5991 * argument to id is of any other type, the argument is converted to a
5992 * string as if by a call to the string function; the string is split
5993 * into a whitespace-separated list of tokens (whitespace is any sequence
5994 * of characters matching the production S); the result is a node-set
5995 * containing the elements in the same document as the context node that
5996 * have a unique ID equal to any of the tokens in the list.
5997 */
5998void
5999xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006000 xmlChar *tokens;
6001 xmlNodeSetPtr ret;
6002 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006003
6004 CHECK_ARITY(1);
6005 obj = valuePop(ctxt);
6006 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006007 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006008 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006009 int i;
6010
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006011 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006012
Daniel Veillard911f49a2001-04-07 15:39:35 +00006013 if (obj->nodesetval != NULL) {
6014 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006015 tokens =
6016 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6017 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6018 ret = xmlXPathNodeSetMerge(ret, ns);
6019 xmlXPathFreeNodeSet(ns);
6020 if (tokens != NULL)
6021 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006022 }
Owen Taylor3473f882001-02-23 17:55:21 +00006023 }
6024
6025 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006026 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006027 return;
6028 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006029 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006030
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006031 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6032 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006033
Owen Taylor3473f882001-02-23 17:55:21 +00006034 xmlXPathFreeObject(obj);
6035 return;
6036}
6037
6038/**
6039 * xmlXPathLocalNameFunction:
6040 * @ctxt: the XPath Parser context
6041 * @nargs: the number of arguments
6042 *
6043 * Implement the local-name() XPath function
6044 * string local-name(node-set?)
6045 * The local-name function returns a string containing the local part
6046 * of the name of the node in the argument node-set that is first in
6047 * document order. If the node-set is empty or the first node has no
6048 * name, an empty string is returned. If the argument is omitted it
6049 * defaults to the context node.
6050 */
6051void
6052xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6053 xmlXPathObjectPtr cur;
6054
6055 if (nargs == 0) {
6056 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6057 nargs = 1;
6058 }
6059
6060 CHECK_ARITY(1);
6061 if ((ctxt->value == NULL) ||
6062 ((ctxt->value->type != XPATH_NODESET) &&
6063 (ctxt->value->type != XPATH_XSLT_TREE)))
6064 XP_ERROR(XPATH_INVALID_TYPE);
6065 cur = valuePop(ctxt);
6066
Daniel Veillard911f49a2001-04-07 15:39:35 +00006067 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006068 valuePush(ctxt, xmlXPathNewCString(""));
6069 } else {
6070 int i = 0; /* Should be first in document order !!!!! */
6071 switch (cur->nodesetval->nodeTab[i]->type) {
6072 case XML_ELEMENT_NODE:
6073 case XML_ATTRIBUTE_NODE:
6074 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006075 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6076 valuePush(ctxt, xmlXPathNewCString(""));
6077 else
6078 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006079 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6080 break;
6081 case XML_NAMESPACE_DECL:
6082 valuePush(ctxt, xmlXPathNewString(
6083 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6084 break;
6085 default:
6086 valuePush(ctxt, xmlXPathNewCString(""));
6087 }
6088 }
6089 xmlXPathFreeObject(cur);
6090}
6091
6092/**
6093 * xmlXPathNamespaceURIFunction:
6094 * @ctxt: the XPath Parser context
6095 * @nargs: the number of arguments
6096 *
6097 * Implement the namespace-uri() XPath function
6098 * string namespace-uri(node-set?)
6099 * The namespace-uri function returns a string containing the
6100 * namespace URI of the expanded name of the node in the argument
6101 * node-set that is first in document order. If the node-set is empty,
6102 * the first node has no name, or the expanded name has no namespace
6103 * URI, an empty string is returned. If the argument is omitted it
6104 * defaults to the context node.
6105 */
6106void
6107xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6108 xmlXPathObjectPtr cur;
6109
6110 if (nargs == 0) {
6111 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6112 nargs = 1;
6113 }
6114 CHECK_ARITY(1);
6115 if ((ctxt->value == NULL) ||
6116 ((ctxt->value->type != XPATH_NODESET) &&
6117 (ctxt->value->type != XPATH_XSLT_TREE)))
6118 XP_ERROR(XPATH_INVALID_TYPE);
6119 cur = valuePop(ctxt);
6120
Daniel Veillard911f49a2001-04-07 15:39:35 +00006121 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006122 valuePush(ctxt, xmlXPathNewCString(""));
6123 } else {
6124 int i = 0; /* Should be first in document order !!!!! */
6125 switch (cur->nodesetval->nodeTab[i]->type) {
6126 case XML_ELEMENT_NODE:
6127 case XML_ATTRIBUTE_NODE:
6128 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6129 valuePush(ctxt, xmlXPathNewCString(""));
6130 else
6131 valuePush(ctxt, xmlXPathNewString(
6132 cur->nodesetval->nodeTab[i]->ns->href));
6133 break;
6134 default:
6135 valuePush(ctxt, xmlXPathNewCString(""));
6136 }
6137 }
6138 xmlXPathFreeObject(cur);
6139}
6140
6141/**
6142 * xmlXPathNameFunction:
6143 * @ctxt: the XPath Parser context
6144 * @nargs: the number of arguments
6145 *
6146 * Implement the name() XPath function
6147 * string name(node-set?)
6148 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006149 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006150 * order. The QName must represent the name with respect to the namespace
6151 * declarations in effect on the node whose name is being represented.
6152 * Typically, this will be the form in which the name occurred in the XML
6153 * source. This need not be the case if there are namespace declarations
6154 * in effect on the node that associate multiple prefixes with the same
6155 * namespace. However, an implementation may include information about
6156 * the original prefix in its representation of nodes; in this case, an
6157 * implementation can ensure that the returned string is always the same
6158 * as the QName used in the XML source. If the argument it omitted it
6159 * defaults to the context node.
6160 * Libxml keep the original prefix so the "real qualified name" used is
6161 * returned.
6162 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006163static void
Daniel Veillard04383752001-07-08 14:27:15 +00006164xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6165{
Owen Taylor3473f882001-02-23 17:55:21 +00006166 xmlXPathObjectPtr cur;
6167
6168 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006169 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6170 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006171 }
6172
6173 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006174 if ((ctxt->value == NULL) ||
6175 ((ctxt->value->type != XPATH_NODESET) &&
6176 (ctxt->value->type != XPATH_XSLT_TREE)))
6177 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006178 cur = valuePop(ctxt);
6179
Daniel Veillard911f49a2001-04-07 15:39:35 +00006180 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006181 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006182 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006183 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006184
Daniel Veillard04383752001-07-08 14:27:15 +00006185 switch (cur->nodesetval->nodeTab[i]->type) {
6186 case XML_ELEMENT_NODE:
6187 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006188 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6189 valuePush(ctxt, xmlXPathNewCString(""));
6190 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6191 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006192 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006193 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006194
Daniel Veillard652d8a92003-02-04 19:28:49 +00006195 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006196 xmlChar *fullname;
6197
6198 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6199 cur->nodesetval->nodeTab[i]->ns->prefix,
6200 NULL, 0);
6201 if (fullname == cur->nodesetval->nodeTab[i]->name)
6202 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6203 if (fullname == NULL) {
6204 XP_ERROR(XPATH_MEMORY_ERROR);
6205 }
6206 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006207 }
6208 break;
6209 default:
6210 valuePush(ctxt,
6211 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6212 xmlXPathLocalNameFunction(ctxt, 1);
6213 }
Owen Taylor3473f882001-02-23 17:55:21 +00006214 }
6215 xmlXPathFreeObject(cur);
6216}
6217
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006218
6219/**
Owen Taylor3473f882001-02-23 17:55:21 +00006220 * xmlXPathStringFunction:
6221 * @ctxt: the XPath Parser context
6222 * @nargs: the number of arguments
6223 *
6224 * Implement the string() XPath function
6225 * string string(object?)
6226 * he string function converts an object to a string as follows:
6227 * - A node-set is converted to a string by returning the value of
6228 * the node in the node-set that is first in document order.
6229 * If the node-set is empty, an empty string is returned.
6230 * - A number is converted to a string as follows
6231 * + NaN is converted to the string NaN
6232 * + positive zero is converted to the string 0
6233 * + negative zero is converted to the string 0
6234 * + positive infinity is converted to the string Infinity
6235 * + negative infinity is converted to the string -Infinity
6236 * + if the number is an integer, the number is represented in
6237 * decimal form as a Number with no decimal point and no leading
6238 * zeros, preceded by a minus sign (-) if the number is negative
6239 * + otherwise, the number is represented in decimal form as a
6240 * Number including a decimal point with at least one digit
6241 * before the decimal point and at least one digit after the
6242 * decimal point, preceded by a minus sign (-) if the number
6243 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006244 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006245 * before the decimal point; beyond the one required digit
6246 * after the decimal point there must be as many, but only as
6247 * many, more digits as are needed to uniquely distinguish the
6248 * number from all other IEEE 754 numeric values.
6249 * - The boolean false value is converted to the string false.
6250 * The boolean true value is converted to the string true.
6251 *
6252 * If the argument is omitted, it defaults to a node-set with the
6253 * context node as its only member.
6254 */
6255void
6256xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6257 xmlXPathObjectPtr cur;
6258
6259 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006260 valuePush(ctxt,
6261 xmlXPathWrapString(
6262 xmlXPathCastNodeToString(ctxt->context->node)));
6263 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006264 }
6265
6266 CHECK_ARITY(1);
6267 cur = valuePop(ctxt);
6268 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006269 cur = xmlXPathConvertString(cur);
6270 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006271}
6272
6273/**
6274 * xmlXPathStringLengthFunction:
6275 * @ctxt: the XPath Parser context
6276 * @nargs: the number of arguments
6277 *
6278 * Implement the string-length() XPath function
6279 * number string-length(string?)
6280 * The string-length returns the number of characters in the string
6281 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6282 * the context node converted to a string, in other words the value
6283 * of the context node.
6284 */
6285void
6286xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6287 xmlXPathObjectPtr cur;
6288
6289 if (nargs == 0) {
6290 if (ctxt->context->node == NULL) {
6291 valuePush(ctxt, xmlXPathNewFloat(0));
6292 } else {
6293 xmlChar *content;
6294
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006295 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006296 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006297 xmlFree(content);
6298 }
6299 return;
6300 }
6301 CHECK_ARITY(1);
6302 CAST_TO_STRING;
6303 CHECK_TYPE(XPATH_STRING);
6304 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006305 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006306 xmlXPathFreeObject(cur);
6307}
6308
6309/**
6310 * xmlXPathConcatFunction:
6311 * @ctxt: the XPath Parser context
6312 * @nargs: the number of arguments
6313 *
6314 * Implement the concat() XPath function
6315 * string concat(string, string, string*)
6316 * The concat function returns the concatenation of its arguments.
6317 */
6318void
6319xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6320 xmlXPathObjectPtr cur, newobj;
6321 xmlChar *tmp;
6322
6323 if (nargs < 2) {
6324 CHECK_ARITY(2);
6325 }
6326
6327 CAST_TO_STRING;
6328 cur = valuePop(ctxt);
6329 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6330 xmlXPathFreeObject(cur);
6331 return;
6332 }
6333 nargs--;
6334
6335 while (nargs > 0) {
6336 CAST_TO_STRING;
6337 newobj = valuePop(ctxt);
6338 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6339 xmlXPathFreeObject(newobj);
6340 xmlXPathFreeObject(cur);
6341 XP_ERROR(XPATH_INVALID_TYPE);
6342 }
6343 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6344 newobj->stringval = cur->stringval;
6345 cur->stringval = tmp;
6346
6347 xmlXPathFreeObject(newobj);
6348 nargs--;
6349 }
6350 valuePush(ctxt, cur);
6351}
6352
6353/**
6354 * xmlXPathContainsFunction:
6355 * @ctxt: the XPath Parser context
6356 * @nargs: the number of arguments
6357 *
6358 * Implement the contains() XPath function
6359 * boolean contains(string, string)
6360 * The contains function returns true if the first argument string
6361 * contains the second argument string, and otherwise returns false.
6362 */
6363void
6364xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6365 xmlXPathObjectPtr hay, needle;
6366
6367 CHECK_ARITY(2);
6368 CAST_TO_STRING;
6369 CHECK_TYPE(XPATH_STRING);
6370 needle = valuePop(ctxt);
6371 CAST_TO_STRING;
6372 hay = valuePop(ctxt);
6373 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6374 xmlXPathFreeObject(hay);
6375 xmlXPathFreeObject(needle);
6376 XP_ERROR(XPATH_INVALID_TYPE);
6377 }
6378 if (xmlStrstr(hay->stringval, needle->stringval))
6379 valuePush(ctxt, xmlXPathNewBoolean(1));
6380 else
6381 valuePush(ctxt, xmlXPathNewBoolean(0));
6382 xmlXPathFreeObject(hay);
6383 xmlXPathFreeObject(needle);
6384}
6385
6386/**
6387 * xmlXPathStartsWithFunction:
6388 * @ctxt: the XPath Parser context
6389 * @nargs: the number of arguments
6390 *
6391 * Implement the starts-with() XPath function
6392 * boolean starts-with(string, string)
6393 * The starts-with function returns true if the first argument string
6394 * starts with the second argument string, and otherwise returns false.
6395 */
6396void
6397xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6398 xmlXPathObjectPtr hay, needle;
6399 int n;
6400
6401 CHECK_ARITY(2);
6402 CAST_TO_STRING;
6403 CHECK_TYPE(XPATH_STRING);
6404 needle = valuePop(ctxt);
6405 CAST_TO_STRING;
6406 hay = valuePop(ctxt);
6407 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6408 xmlXPathFreeObject(hay);
6409 xmlXPathFreeObject(needle);
6410 XP_ERROR(XPATH_INVALID_TYPE);
6411 }
6412 n = xmlStrlen(needle->stringval);
6413 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6414 valuePush(ctxt, xmlXPathNewBoolean(0));
6415 else
6416 valuePush(ctxt, xmlXPathNewBoolean(1));
6417 xmlXPathFreeObject(hay);
6418 xmlXPathFreeObject(needle);
6419}
6420
6421/**
6422 * xmlXPathSubstringFunction:
6423 * @ctxt: the XPath Parser context
6424 * @nargs: the number of arguments
6425 *
6426 * Implement the substring() XPath function
6427 * string substring(string, number, number?)
6428 * The substring function returns the substring of the first argument
6429 * starting at the position specified in the second argument with
6430 * length specified in the third argument. For example,
6431 * substring("12345",2,3) returns "234". If the third argument is not
6432 * specified, it returns the substring starting at the position specified
6433 * in the second argument and continuing to the end of the string. For
6434 * example, substring("12345",2) returns "2345". More precisely, each
6435 * character in the string (see [3.6 Strings]) is considered to have a
6436 * numeric position: the position of the first character is 1, the position
6437 * of the second character is 2 and so on. The returned substring contains
6438 * those characters for which the position of the character is greater than
6439 * or equal to the second argument and, if the third argument is specified,
6440 * less than the sum of the second and third arguments; the comparisons
6441 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6442 * - substring("12345", 1.5, 2.6) returns "234"
6443 * - substring("12345", 0, 3) returns "12"
6444 * - substring("12345", 0 div 0, 3) returns ""
6445 * - substring("12345", 1, 0 div 0) returns ""
6446 * - substring("12345", -42, 1 div 0) returns "12345"
6447 * - substring("12345", -1 div 0, 1 div 0) returns ""
6448 */
6449void
6450xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6451 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006452 double le=0, in;
6453 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006454 xmlChar *ret;
6455
Owen Taylor3473f882001-02-23 17:55:21 +00006456 if (nargs < 2) {
6457 CHECK_ARITY(2);
6458 }
6459 if (nargs > 3) {
6460 CHECK_ARITY(3);
6461 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006462 /*
6463 * take care of possible last (position) argument
6464 */
Owen Taylor3473f882001-02-23 17:55:21 +00006465 if (nargs == 3) {
6466 CAST_TO_NUMBER;
6467 CHECK_TYPE(XPATH_NUMBER);
6468 len = valuePop(ctxt);
6469 le = len->floatval;
6470 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006471 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006472
Owen Taylor3473f882001-02-23 17:55:21 +00006473 CAST_TO_NUMBER;
6474 CHECK_TYPE(XPATH_NUMBER);
6475 start = valuePop(ctxt);
6476 in = start->floatval;
6477 xmlXPathFreeObject(start);
6478 CAST_TO_STRING;
6479 CHECK_TYPE(XPATH_STRING);
6480 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006481 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006482
Daniel Veillard97ac1312001-05-30 19:14:17 +00006483 /*
6484 * If last pos not present, calculate last position
6485 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006486 if (nargs != 3) {
6487 le = (double)m;
6488 if (in < 1.0)
6489 in = 1.0;
6490 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006491
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006492 /* Need to check for the special cases where either
6493 * the index is NaN, the length is NaN, or both
6494 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006495 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006496 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006497 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006498 * To meet the requirements of the spec, the arguments
6499 * must be converted to integer format before
6500 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006501 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006502 * First we go to integer form, rounding up
6503 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006504 */
6505 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006506 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006507
Daniel Veillard9e412302002-06-10 15:59:44 +00006508 if (xmlXPathIsInf(le) == 1) {
6509 l = m;
6510 if (i < 1)
6511 i = 1;
6512 }
6513 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6514 l = 0;
6515 else {
6516 l = (int) le;
6517 if (((double)l)+0.5 <= le) l++;
6518 }
6519
6520 /* Now we normalize inidices */
6521 i -= 1;
6522 l += i;
6523 if (i < 0)
6524 i = 0;
6525 if (l > m)
6526 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006527
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006528 /* number of chars to copy */
6529 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006530
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006531 ret = xmlUTF8Strsub(str->stringval, i, l);
6532 }
6533 else {
6534 ret = NULL;
6535 }
6536
Owen Taylor3473f882001-02-23 17:55:21 +00006537 if (ret == NULL)
6538 valuePush(ctxt, xmlXPathNewCString(""));
6539 else {
6540 valuePush(ctxt, xmlXPathNewString(ret));
6541 xmlFree(ret);
6542 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006543
Owen Taylor3473f882001-02-23 17:55:21 +00006544 xmlXPathFreeObject(str);
6545}
6546
6547/**
6548 * xmlXPathSubstringBeforeFunction:
6549 * @ctxt: the XPath Parser context
6550 * @nargs: the number of arguments
6551 *
6552 * Implement the substring-before() XPath function
6553 * string substring-before(string, string)
6554 * The substring-before function returns the substring of the first
6555 * argument string that precedes the first occurrence of the second
6556 * argument string in the first argument string, or the empty string
6557 * if the first argument string does not contain the second argument
6558 * string. For example, substring-before("1999/04/01","/") returns 1999.
6559 */
6560void
6561xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6562 xmlXPathObjectPtr str;
6563 xmlXPathObjectPtr find;
6564 xmlBufferPtr target;
6565 const xmlChar *point;
6566 int offset;
6567
6568 CHECK_ARITY(2);
6569 CAST_TO_STRING;
6570 find = valuePop(ctxt);
6571 CAST_TO_STRING;
6572 str = valuePop(ctxt);
6573
6574 target = xmlBufferCreate();
6575 if (target) {
6576 point = xmlStrstr(str->stringval, find->stringval);
6577 if (point) {
6578 offset = (int)(point - str->stringval);
6579 xmlBufferAdd(target, str->stringval, offset);
6580 }
6581 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6582 xmlBufferFree(target);
6583 }
6584
6585 xmlXPathFreeObject(str);
6586 xmlXPathFreeObject(find);
6587}
6588
6589/**
6590 * xmlXPathSubstringAfterFunction:
6591 * @ctxt: the XPath Parser context
6592 * @nargs: the number of arguments
6593 *
6594 * Implement the substring-after() XPath function
6595 * string substring-after(string, string)
6596 * The substring-after function returns the substring of the first
6597 * argument string that follows the first occurrence of the second
6598 * argument string in the first argument string, or the empty stringi
6599 * if the first argument string does not contain the second argument
6600 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6601 * and substring-after("1999/04/01","19") returns 99/04/01.
6602 */
6603void
6604xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6605 xmlXPathObjectPtr str;
6606 xmlXPathObjectPtr find;
6607 xmlBufferPtr target;
6608 const xmlChar *point;
6609 int offset;
6610
6611 CHECK_ARITY(2);
6612 CAST_TO_STRING;
6613 find = valuePop(ctxt);
6614 CAST_TO_STRING;
6615 str = valuePop(ctxt);
6616
6617 target = xmlBufferCreate();
6618 if (target) {
6619 point = xmlStrstr(str->stringval, find->stringval);
6620 if (point) {
6621 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6622 xmlBufferAdd(target, &str->stringval[offset],
6623 xmlStrlen(str->stringval) - offset);
6624 }
6625 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6626 xmlBufferFree(target);
6627 }
6628
6629 xmlXPathFreeObject(str);
6630 xmlXPathFreeObject(find);
6631}
6632
6633/**
6634 * xmlXPathNormalizeFunction:
6635 * @ctxt: the XPath Parser context
6636 * @nargs: the number of arguments
6637 *
6638 * Implement the normalize-space() XPath function
6639 * string normalize-space(string?)
6640 * The normalize-space function returns the argument string with white
6641 * space normalized by stripping leading and trailing whitespace
6642 * and replacing sequences of whitespace characters by a single
6643 * space. Whitespace characters are the same allowed by the S production
6644 * in XML. If the argument is omitted, it defaults to the context
6645 * node converted to a string, in other words the value of the context node.
6646 */
6647void
6648xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6649 xmlXPathObjectPtr obj = NULL;
6650 xmlChar *source = NULL;
6651 xmlBufferPtr target;
6652 xmlChar blank;
6653
6654 if (nargs == 0) {
6655 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006656 valuePush(ctxt,
6657 xmlXPathWrapString(
6658 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006659 nargs = 1;
6660 }
6661
6662 CHECK_ARITY(1);
6663 CAST_TO_STRING;
6664 CHECK_TYPE(XPATH_STRING);
6665 obj = valuePop(ctxt);
6666 source = obj->stringval;
6667
6668 target = xmlBufferCreate();
6669 if (target && source) {
6670
6671 /* Skip leading whitespaces */
6672 while (IS_BLANK(*source))
6673 source++;
6674
6675 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6676 blank = 0;
6677 while (*source) {
6678 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006679 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006680 } else {
6681 if (blank) {
6682 xmlBufferAdd(target, &blank, 1);
6683 blank = 0;
6684 }
6685 xmlBufferAdd(target, source, 1);
6686 }
6687 source++;
6688 }
6689
6690 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6691 xmlBufferFree(target);
6692 }
6693 xmlXPathFreeObject(obj);
6694}
6695
6696/**
6697 * xmlXPathTranslateFunction:
6698 * @ctxt: the XPath Parser context
6699 * @nargs: the number of arguments
6700 *
6701 * Implement the translate() XPath function
6702 * string translate(string, string, string)
6703 * The translate function returns the first argument string with
6704 * occurrences of characters in the second argument string replaced
6705 * by the character at the corresponding position in the third argument
6706 * string. For example, translate("bar","abc","ABC") returns the string
6707 * BAr. If there is a character in the second argument string with no
6708 * character at a corresponding position in the third argument string
6709 * (because the second argument string is longer than the third argument
6710 * string), then occurrences of that character in the first argument
6711 * string are removed. For example, translate("--aaa--","abc-","ABC")
6712 * returns "AAA". If a character occurs more than once in second
6713 * argument string, then the first occurrence determines the replacement
6714 * character. If the third argument string is longer than the second
6715 * argument string, then excess characters are ignored.
6716 */
6717void
6718xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006719 xmlXPathObjectPtr str;
6720 xmlXPathObjectPtr from;
6721 xmlXPathObjectPtr to;
6722 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006723 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006724 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006725 xmlChar *point;
6726 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006727
Daniel Veillarde043ee12001-04-16 14:08:07 +00006728 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006729
Daniel Veillarde043ee12001-04-16 14:08:07 +00006730 CAST_TO_STRING;
6731 to = valuePop(ctxt);
6732 CAST_TO_STRING;
6733 from = valuePop(ctxt);
6734 CAST_TO_STRING;
6735 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006736
Daniel Veillarde043ee12001-04-16 14:08:07 +00006737 target = xmlBufferCreate();
6738 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006739 max = xmlUTF8Strlen(to->stringval);
6740 for (cptr = str->stringval; (ch=*cptr); ) {
6741 offset = xmlUTF8Strloc(from->stringval, cptr);
6742 if (offset >= 0) {
6743 if (offset < max) {
6744 point = xmlUTF8Strpos(to->stringval, offset);
6745 if (point)
6746 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6747 }
6748 } else
6749 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6750
6751 /* Step to next character in input */
6752 cptr++;
6753 if ( ch & 0x80 ) {
6754 /* if not simple ascii, verify proper format */
6755 if ( (ch & 0xc0) != 0xc0 ) {
6756 xmlGenericError(xmlGenericErrorContext,
6757 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6758 break;
6759 }
6760 /* then skip over remaining bytes for this char */
6761 while ( (ch <<= 1) & 0x80 )
6762 if ( (*cptr++ & 0xc0) != 0x80 ) {
6763 xmlGenericError(xmlGenericErrorContext,
6764 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6765 break;
6766 }
6767 if (ch & 0x80) /* must have had error encountered */
6768 break;
6769 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006770 }
Owen Taylor3473f882001-02-23 17:55:21 +00006771 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006772 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6773 xmlBufferFree(target);
6774 xmlXPathFreeObject(str);
6775 xmlXPathFreeObject(from);
6776 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006777}
6778
6779/**
6780 * xmlXPathBooleanFunction:
6781 * @ctxt: the XPath Parser context
6782 * @nargs: the number of arguments
6783 *
6784 * Implement the boolean() XPath function
6785 * boolean boolean(object)
6786 * he boolean function converts its argument to a boolean as follows:
6787 * - a number is true if and only if it is neither positive or
6788 * negative zero nor NaN
6789 * - a node-set is true if and only if it is non-empty
6790 * - a string is true if and only if its length is non-zero
6791 */
6792void
6793xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6794 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006795
6796 CHECK_ARITY(1);
6797 cur = valuePop(ctxt);
6798 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006799 cur = xmlXPathConvertBoolean(cur);
6800 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006801}
6802
6803/**
6804 * xmlXPathNotFunction:
6805 * @ctxt: the XPath Parser context
6806 * @nargs: the number of arguments
6807 *
6808 * Implement the not() XPath function
6809 * boolean not(boolean)
6810 * The not function returns true if its argument is false,
6811 * and false otherwise.
6812 */
6813void
6814xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6815 CHECK_ARITY(1);
6816 CAST_TO_BOOLEAN;
6817 CHECK_TYPE(XPATH_BOOLEAN);
6818 ctxt->value->boolval = ! ctxt->value->boolval;
6819}
6820
6821/**
6822 * xmlXPathTrueFunction:
6823 * @ctxt: the XPath Parser context
6824 * @nargs: the number of arguments
6825 *
6826 * Implement the true() XPath function
6827 * boolean true()
6828 */
6829void
6830xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6831 CHECK_ARITY(0);
6832 valuePush(ctxt, xmlXPathNewBoolean(1));
6833}
6834
6835/**
6836 * xmlXPathFalseFunction:
6837 * @ctxt: the XPath Parser context
6838 * @nargs: the number of arguments
6839 *
6840 * Implement the false() XPath function
6841 * boolean false()
6842 */
6843void
6844xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6845 CHECK_ARITY(0);
6846 valuePush(ctxt, xmlXPathNewBoolean(0));
6847}
6848
6849/**
6850 * xmlXPathLangFunction:
6851 * @ctxt: the XPath Parser context
6852 * @nargs: the number of arguments
6853 *
6854 * Implement the lang() XPath function
6855 * boolean lang(string)
6856 * The lang function returns true or false depending on whether the
6857 * language of the context node as specified by xml:lang attributes
6858 * is the same as or is a sublanguage of the language specified by
6859 * the argument string. The language of the context node is determined
6860 * by the value of the xml:lang attribute on the context node, or, if
6861 * the context node has no xml:lang attribute, by the value of the
6862 * xml:lang attribute on the nearest ancestor of the context node that
6863 * has an xml:lang attribute. If there is no such attribute, then lang
6864 * returns false. If there is such an attribute, then lang returns
6865 * true if the attribute value is equal to the argument ignoring case,
6866 * or if there is some suffix starting with - such that the attribute
6867 * value is equal to the argument ignoring that suffix of the attribute
6868 * value and ignoring case.
6869 */
6870void
6871xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6872 xmlXPathObjectPtr val;
6873 const xmlChar *theLang;
6874 const xmlChar *lang;
6875 int ret = 0;
6876 int i;
6877
6878 CHECK_ARITY(1);
6879 CAST_TO_STRING;
6880 CHECK_TYPE(XPATH_STRING);
6881 val = valuePop(ctxt);
6882 lang = val->stringval;
6883 theLang = xmlNodeGetLang(ctxt->context->node);
6884 if ((theLang != NULL) && (lang != NULL)) {
6885 for (i = 0;lang[i] != 0;i++)
6886 if (toupper(lang[i]) != toupper(theLang[i]))
6887 goto not_equal;
6888 ret = 1;
6889 }
6890not_equal:
6891 xmlXPathFreeObject(val);
6892 valuePush(ctxt, xmlXPathNewBoolean(ret));
6893}
6894
6895/**
6896 * xmlXPathNumberFunction:
6897 * @ctxt: the XPath Parser context
6898 * @nargs: the number of arguments
6899 *
6900 * Implement the number() XPath function
6901 * number number(object?)
6902 */
6903void
6904xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6905 xmlXPathObjectPtr cur;
6906 double res;
6907
6908 if (nargs == 0) {
6909 if (ctxt->context->node == NULL) {
6910 valuePush(ctxt, xmlXPathNewFloat(0.0));
6911 } else {
6912 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6913
6914 res = xmlXPathStringEvalNumber(content);
6915 valuePush(ctxt, xmlXPathNewFloat(res));
6916 xmlFree(content);
6917 }
6918 return;
6919 }
6920
6921 CHECK_ARITY(1);
6922 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006923 cur = xmlXPathConvertNumber(cur);
6924 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006925}
6926
6927/**
6928 * xmlXPathSumFunction:
6929 * @ctxt: the XPath Parser context
6930 * @nargs: the number of arguments
6931 *
6932 * Implement the sum() XPath function
6933 * number sum(node-set)
6934 * The sum function returns the sum of the values of the nodes in
6935 * the argument node-set.
6936 */
6937void
6938xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6939 xmlXPathObjectPtr cur;
6940 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006941 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006942
6943 CHECK_ARITY(1);
6944 if ((ctxt->value == NULL) ||
6945 ((ctxt->value->type != XPATH_NODESET) &&
6946 (ctxt->value->type != XPATH_XSLT_TREE)))
6947 XP_ERROR(XPATH_INVALID_TYPE);
6948 cur = valuePop(ctxt);
6949
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006950 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006951 valuePush(ctxt, xmlXPathNewFloat(0.0));
6952 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006953 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6954 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006955 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006956 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006957 }
6958 xmlXPathFreeObject(cur);
6959}
6960
6961/**
6962 * xmlXPathFloorFunction:
6963 * @ctxt: the XPath Parser context
6964 * @nargs: the number of arguments
6965 *
6966 * Implement the floor() XPath function
6967 * number floor(number)
6968 * The floor function returns the largest (closest to positive infinity)
6969 * number that is not greater than the argument and that is an integer.
6970 */
6971void
6972xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006973 double f;
6974
Owen Taylor3473f882001-02-23 17:55:21 +00006975 CHECK_ARITY(1);
6976 CAST_TO_NUMBER;
6977 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006978
6979 f = (double)((int) ctxt->value->floatval);
6980 if (f != ctxt->value->floatval) {
6981 if (ctxt->value->floatval > 0)
6982 ctxt->value->floatval = f;
6983 else
6984 ctxt->value->floatval = f - 1;
6985 }
Owen Taylor3473f882001-02-23 17:55:21 +00006986}
6987
6988/**
6989 * xmlXPathCeilingFunction:
6990 * @ctxt: the XPath Parser context
6991 * @nargs: the number of arguments
6992 *
6993 * Implement the ceiling() XPath function
6994 * number ceiling(number)
6995 * The ceiling function returns the smallest (closest to negative infinity)
6996 * number that is not less than the argument and that is an integer.
6997 */
6998void
6999xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7000 double f;
7001
7002 CHECK_ARITY(1);
7003 CAST_TO_NUMBER;
7004 CHECK_TYPE(XPATH_NUMBER);
7005
7006#if 0
7007 ctxt->value->floatval = ceil(ctxt->value->floatval);
7008#else
7009 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007010 if (f != ctxt->value->floatval) {
7011 if (ctxt->value->floatval > 0)
7012 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007013 else {
7014 if (ctxt->value->floatval < 0 && f == 0)
7015 ctxt->value->floatval = xmlXPathNZERO;
7016 else
7017 ctxt->value->floatval = f;
7018 }
7019
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007020 }
Owen Taylor3473f882001-02-23 17:55:21 +00007021#endif
7022}
7023
7024/**
7025 * xmlXPathRoundFunction:
7026 * @ctxt: the XPath Parser context
7027 * @nargs: the number of arguments
7028 *
7029 * Implement the round() XPath function
7030 * number round(number)
7031 * The round function returns the number that is closest to the
7032 * argument and that is an integer. If there are two such numbers,
7033 * then the one that is even is returned.
7034 */
7035void
7036xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7037 double f;
7038
7039 CHECK_ARITY(1);
7040 CAST_TO_NUMBER;
7041 CHECK_TYPE(XPATH_NUMBER);
7042
Daniel Veillardcda96922001-08-21 10:56:31 +00007043 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7044 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7045 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007046 (ctxt->value->floatval == 0.0))
7047 return;
7048
Owen Taylor3473f882001-02-23 17:55:21 +00007049 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007050 if (ctxt->value->floatval < 0) {
7051 if (ctxt->value->floatval < f - 0.5)
7052 ctxt->value->floatval = f - 1;
7053 else
7054 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007055 if (ctxt->value->floatval == 0)
7056 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007057 } else {
7058 if (ctxt->value->floatval < f + 0.5)
7059 ctxt->value->floatval = f;
7060 else
7061 ctxt->value->floatval = f + 1;
7062 }
Owen Taylor3473f882001-02-23 17:55:21 +00007063}
7064
7065/************************************************************************
7066 * *
7067 * The Parser *
7068 * *
7069 ************************************************************************/
7070
7071/*
7072 * a couple of forward declarations since we use a recursive call based
7073 * implementation.
7074 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007075static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007076static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007077static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007078static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007079static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7080 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007081
7082/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007083 * xmlXPathCurrentChar:
7084 * @ctxt: the XPath parser context
7085 * @cur: pointer to the beginning of the char
7086 * @len: pointer to the length of the char read
7087 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007088 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007089 * bytes in the input buffer.
7090 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007091 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007092 */
7093
7094static int
7095xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7096 unsigned char c;
7097 unsigned int val;
7098 const xmlChar *cur;
7099
7100 if (ctxt == NULL)
7101 return(0);
7102 cur = ctxt->cur;
7103
7104 /*
7105 * We are supposed to handle UTF8, check it's valid
7106 * From rfc2044: encoding of the Unicode values on UTF-8:
7107 *
7108 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7109 * 0000 0000-0000 007F 0xxxxxxx
7110 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7111 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7112 *
7113 * Check for the 0x110000 limit too
7114 */
7115 c = *cur;
7116 if (c & 0x80) {
7117 if ((cur[1] & 0xc0) != 0x80)
7118 goto encoding_error;
7119 if ((c & 0xe0) == 0xe0) {
7120
7121 if ((cur[2] & 0xc0) != 0x80)
7122 goto encoding_error;
7123 if ((c & 0xf0) == 0xf0) {
7124 if (((c & 0xf8) != 0xf0) ||
7125 ((cur[3] & 0xc0) != 0x80))
7126 goto encoding_error;
7127 /* 4-byte code */
7128 *len = 4;
7129 val = (cur[0] & 0x7) << 18;
7130 val |= (cur[1] & 0x3f) << 12;
7131 val |= (cur[2] & 0x3f) << 6;
7132 val |= cur[3] & 0x3f;
7133 } else {
7134 /* 3-byte code */
7135 *len = 3;
7136 val = (cur[0] & 0xf) << 12;
7137 val |= (cur[1] & 0x3f) << 6;
7138 val |= cur[2] & 0x3f;
7139 }
7140 } else {
7141 /* 2-byte code */
7142 *len = 2;
7143 val = (cur[0] & 0x1f) << 6;
7144 val |= cur[1] & 0x3f;
7145 }
7146 if (!IS_CHAR(val)) {
7147 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7148 }
7149 return(val);
7150 } else {
7151 /* 1-byte code */
7152 *len = 1;
7153 return((int) *cur);
7154 }
7155encoding_error:
7156 /*
7157 * If we detect an UTF8 error that probably mean that the
7158 * input encoding didn't get properly advertized in the
7159 * declaration header. Report the error and switch the encoding
7160 * to ISO-Latin-1 (if you don't like this policy, just declare the
7161 * encoding !)
7162 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007163 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007164 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007165}
7166
7167/**
Owen Taylor3473f882001-02-23 17:55:21 +00007168 * xmlXPathParseNCName:
7169 * @ctxt: the XPath Parser context
7170 *
7171 * parse an XML namespace non qualified name.
7172 *
7173 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7174 *
7175 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7176 * CombiningChar | Extender
7177 *
7178 * Returns the namespace name or NULL
7179 */
7180
7181xmlChar *
7182xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007183 const xmlChar *in;
7184 xmlChar *ret;
7185 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007186
Daniel Veillard2156a562001-04-28 12:24:34 +00007187 /*
7188 * Accelerator for simple ASCII names
7189 */
7190 in = ctxt->cur;
7191 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7192 ((*in >= 0x41) && (*in <= 0x5A)) ||
7193 (*in == '_')) {
7194 in++;
7195 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7196 ((*in >= 0x41) && (*in <= 0x5A)) ||
7197 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007198 (*in == '_') || (*in == '.') ||
7199 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007200 in++;
7201 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7202 (*in == '[') || (*in == ']') || (*in == ':') ||
7203 (*in == '@') || (*in == '*')) {
7204 count = in - ctxt->cur;
7205 if (count == 0)
7206 return(NULL);
7207 ret = xmlStrndup(ctxt->cur, count);
7208 ctxt->cur = in;
7209 return(ret);
7210 }
7211 }
7212 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007213}
7214
Daniel Veillard2156a562001-04-28 12:24:34 +00007215
Owen Taylor3473f882001-02-23 17:55:21 +00007216/**
7217 * xmlXPathParseQName:
7218 * @ctxt: the XPath Parser context
7219 * @prefix: a xmlChar **
7220 *
7221 * parse an XML qualified name
7222 *
7223 * [NS 5] QName ::= (Prefix ':')? LocalPart
7224 *
7225 * [NS 6] Prefix ::= NCName
7226 *
7227 * [NS 7] LocalPart ::= NCName
7228 *
7229 * Returns the function returns the local part, and prefix is updated
7230 * to get the Prefix if any.
7231 */
7232
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007233static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007234xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7235 xmlChar *ret = NULL;
7236
7237 *prefix = NULL;
7238 ret = xmlXPathParseNCName(ctxt);
7239 if (CUR == ':') {
7240 *prefix = ret;
7241 NEXT;
7242 ret = xmlXPathParseNCName(ctxt);
7243 }
7244 return(ret);
7245}
7246
7247/**
7248 * xmlXPathParseName:
7249 * @ctxt: the XPath Parser context
7250 *
7251 * parse an XML name
7252 *
7253 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7254 * CombiningChar | Extender
7255 *
7256 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7257 *
7258 * Returns the namespace name or NULL
7259 */
7260
7261xmlChar *
7262xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007263 const xmlChar *in;
7264 xmlChar *ret;
7265 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007266
Daniel Veillard61d80a22001-04-27 17:13:01 +00007267 /*
7268 * Accelerator for simple ASCII names
7269 */
7270 in = ctxt->cur;
7271 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7272 ((*in >= 0x41) && (*in <= 0x5A)) ||
7273 (*in == '_') || (*in == ':')) {
7274 in++;
7275 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7276 ((*in >= 0x41) && (*in <= 0x5A)) ||
7277 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007278 (*in == '_') || (*in == '-') ||
7279 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007280 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007281 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007282 count = in - ctxt->cur;
7283 ret = xmlStrndup(ctxt->cur, count);
7284 ctxt->cur = in;
7285 return(ret);
7286 }
7287 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007288 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007289}
7290
Daniel Veillard61d80a22001-04-27 17:13:01 +00007291static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007292xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007293 xmlChar buf[XML_MAX_NAMELEN + 5];
7294 int len = 0, l;
7295 int c;
7296
7297 /*
7298 * Handler for more complex cases
7299 */
7300 c = CUR_CHAR(l);
7301 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007302 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7303 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007304 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007305 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007306 return(NULL);
7307 }
7308
7309 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7310 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7311 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007312 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007313 (IS_COMBINING(c)) ||
7314 (IS_EXTENDER(c)))) {
7315 COPY_BUF(l,buf,len,c);
7316 NEXTL(l);
7317 c = CUR_CHAR(l);
7318 if (len >= XML_MAX_NAMELEN) {
7319 /*
7320 * Okay someone managed to make a huge name, so he's ready to pay
7321 * for the processing speed.
7322 */
7323 xmlChar *buffer;
7324 int max = len * 2;
7325
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007326 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007327 if (buffer == NULL) {
7328 XP_ERROR0(XPATH_MEMORY_ERROR);
7329 }
7330 memcpy(buffer, buf, len);
7331 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7332 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007333 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007334 (IS_COMBINING(c)) ||
7335 (IS_EXTENDER(c))) {
7336 if (len + 10 > max) {
7337 max *= 2;
7338 buffer = (xmlChar *) xmlRealloc(buffer,
7339 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007340 if (buffer == NULL) {
7341 XP_ERROR0(XPATH_MEMORY_ERROR);
7342 }
7343 }
7344 COPY_BUF(l,buffer,len,c);
7345 NEXTL(l);
7346 c = CUR_CHAR(l);
7347 }
7348 buffer[len] = 0;
7349 return(buffer);
7350 }
7351 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007352 if (len == 0)
7353 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007354 return(xmlStrndup(buf, len));
7355}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007356
7357#define MAX_FRAC 20
7358
7359static double my_pow10[MAX_FRAC] = {
7360 1.0, 10.0, 100.0, 1000.0, 10000.0,
7361 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7362 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7363 100000000000000.0,
7364 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7365 1000000000000000000.0, 10000000000000000000.0
7366};
7367
Owen Taylor3473f882001-02-23 17:55:21 +00007368/**
7369 * xmlXPathStringEvalNumber:
7370 * @str: A string to scan
7371 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007372 * [30a] Float ::= Number ('e' Digits?)?
7373 *
Owen Taylor3473f882001-02-23 17:55:21 +00007374 * [30] Number ::= Digits ('.' Digits?)?
7375 * | '.' Digits
7376 * [31] Digits ::= [0-9]+
7377 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007378 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007379 * In complement of the Number expression, this function also handles
7380 * negative values : '-' Number.
7381 *
7382 * Returns the double value.
7383 */
7384double
7385xmlXPathStringEvalNumber(const xmlChar *str) {
7386 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007387 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007388 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007389 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007390 int exponent = 0;
7391 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007392#ifdef __GNUC__
7393 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007394 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007395#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007396 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007397 while (IS_BLANK(*cur)) cur++;
7398 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7399 return(xmlXPathNAN);
7400 }
7401 if (*cur == '-') {
7402 isneg = 1;
7403 cur++;
7404 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007405
7406#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007407 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007408 * tmp/temp is a workaround against a gcc compiler bug
7409 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007410 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007411 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007412 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007413 ret = ret * 10;
7414 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007415 ok = 1;
7416 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007417 temp = (double) tmp;
7418 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007419 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007420#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007421 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007422 while ((*cur >= '0') && (*cur <= '9')) {
7423 ret = ret * 10 + (*cur - '0');
7424 ok = 1;
7425 cur++;
7426 }
7427#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007428
Owen Taylor3473f882001-02-23 17:55:21 +00007429 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007430 int v, frac = 0;
7431 double fraction = 0;
7432
Owen Taylor3473f882001-02-23 17:55:21 +00007433 cur++;
7434 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7435 return(xmlXPathNAN);
7436 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007437 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7438 v = (*cur - '0');
7439 fraction = fraction * 10 + v;
7440 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007441 cur++;
7442 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007443 fraction /= my_pow10[frac];
7444 ret = ret + fraction;
7445 while ((*cur >= '0') && (*cur <= '9'))
7446 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007447 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007448 if ((*cur == 'e') || (*cur == 'E')) {
7449 cur++;
7450 if (*cur == '-') {
7451 is_exponent_negative = 1;
7452 cur++;
7453 }
7454 while ((*cur >= '0') && (*cur <= '9')) {
7455 exponent = exponent * 10 + (*cur - '0');
7456 cur++;
7457 }
7458 }
Owen Taylor3473f882001-02-23 17:55:21 +00007459 while (IS_BLANK(*cur)) cur++;
7460 if (*cur != 0) return(xmlXPathNAN);
7461 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007462 if (is_exponent_negative) exponent = -exponent;
7463 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007464 return(ret);
7465}
7466
7467/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007468 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007469 * @ctxt: the XPath Parser context
7470 *
7471 * [30] Number ::= Digits ('.' Digits?)?
7472 * | '.' Digits
7473 * [31] Digits ::= [0-9]+
7474 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007475 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007476 *
7477 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007478static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007479xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7480{
Owen Taylor3473f882001-02-23 17:55:21 +00007481 double ret = 0.0;
7482 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007483 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007484 int exponent = 0;
7485 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007486#ifdef __GNUC__
7487 unsigned long tmp = 0;
7488 double temp;
7489#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007490
7491 CHECK_ERROR;
7492 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7493 XP_ERROR(XPATH_NUMBER_ERROR);
7494 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007495#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007496 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007497 * tmp/temp is a workaround against a gcc compiler bug
7498 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007499 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007500 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007501 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007502 ret = ret * 10;
7503 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007504 ok = 1;
7505 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007506 temp = (double) tmp;
7507 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007508 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007509#else
7510 ret = 0;
7511 while ((CUR >= '0') && (CUR <= '9')) {
7512 ret = ret * 10 + (CUR - '0');
7513 ok = 1;
7514 NEXT;
7515 }
7516#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007517 if (CUR == '.') {
7518 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007519 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7520 XP_ERROR(XPATH_NUMBER_ERROR);
7521 }
7522 while ((CUR >= '0') && (CUR <= '9')) {
7523 mult /= 10;
7524 ret = ret + (CUR - '0') * mult;
7525 NEXT;
7526 }
Owen Taylor3473f882001-02-23 17:55:21 +00007527 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007528 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007529 NEXT;
7530 if (CUR == '-') {
7531 is_exponent_negative = 1;
7532 NEXT;
7533 }
7534 while ((CUR >= '0') && (CUR <= '9')) {
7535 exponent = exponent * 10 + (CUR - '0');
7536 NEXT;
7537 }
7538 if (is_exponent_negative)
7539 exponent = -exponent;
7540 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007541 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007542 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007543 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007544}
7545
7546/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007547 * xmlXPathParseLiteral:
7548 * @ctxt: the XPath Parser context
7549 *
7550 * Parse a Literal
7551 *
7552 * [29] Literal ::= '"' [^"]* '"'
7553 * | "'" [^']* "'"
7554 *
7555 * Returns the value found or NULL in case of error
7556 */
7557static xmlChar *
7558xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7559 const xmlChar *q;
7560 xmlChar *ret = NULL;
7561
7562 if (CUR == '"') {
7563 NEXT;
7564 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007565 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007566 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007567 if (!IS_CHAR((unsigned int) CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007568 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7569 } else {
7570 ret = xmlStrndup(q, CUR_PTR - q);
7571 NEXT;
7572 }
7573 } else if (CUR == '\'') {
7574 NEXT;
7575 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007576 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007577 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007578 if (!IS_CHAR((unsigned int) CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007579 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7580 } else {
7581 ret = xmlStrndup(q, CUR_PTR - q);
7582 NEXT;
7583 }
7584 } else {
7585 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7586 }
7587 return(ret);
7588}
7589
7590/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007591 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007592 * @ctxt: the XPath Parser context
7593 *
7594 * Parse a Literal and push it on the stack.
7595 *
7596 * [29] Literal ::= '"' [^"]* '"'
7597 * | "'" [^']* "'"
7598 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007599 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007600 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007601static void
7602xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007603 const xmlChar *q;
7604 xmlChar *ret = NULL;
7605
7606 if (CUR == '"') {
7607 NEXT;
7608 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007609 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007610 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007611 if (!IS_CHAR((unsigned int) CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007612 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7613 } else {
7614 ret = xmlStrndup(q, CUR_PTR - q);
7615 NEXT;
7616 }
7617 } else if (CUR == '\'') {
7618 NEXT;
7619 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007620 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007621 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007622 if (!IS_CHAR((unsigned int) CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007623 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7624 } else {
7625 ret = xmlStrndup(q, CUR_PTR - q);
7626 NEXT;
7627 }
7628 } else {
7629 XP_ERROR(XPATH_START_LITERAL_ERROR);
7630 }
7631 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007632 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7633 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007634 xmlFree(ret);
7635}
7636
7637/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007638 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007639 * @ctxt: the XPath Parser context
7640 *
7641 * Parse a VariableReference, evaluate it and push it on the stack.
7642 *
7643 * The variable bindings consist of a mapping from variable names
7644 * to variable values. The value of a variable is an object, which
7645 * of any of the types that are possible for the value of an expression,
7646 * and may also be of additional types not specified here.
7647 *
7648 * Early evaluation is possible since:
7649 * The variable bindings [...] used to evaluate a subexpression are
7650 * always the same as those used to evaluate the containing expression.
7651 *
7652 * [36] VariableReference ::= '$' QName
7653 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007654static void
7655xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007656 xmlChar *name;
7657 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007658
7659 SKIP_BLANKS;
7660 if (CUR != '$') {
7661 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7662 }
7663 NEXT;
7664 name = xmlXPathParseQName(ctxt, &prefix);
7665 if (name == NULL) {
7666 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7667 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007668 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007669 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7670 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007671 SKIP_BLANKS;
7672}
7673
7674/**
7675 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007676 * @name: a name string
7677 *
7678 * Is the name given a NodeType one.
7679 *
7680 * [38] NodeType ::= 'comment'
7681 * | 'text'
7682 * | 'processing-instruction'
7683 * | 'node'
7684 *
7685 * Returns 1 if true 0 otherwise
7686 */
7687int
7688xmlXPathIsNodeType(const xmlChar *name) {
7689 if (name == NULL)
7690 return(0);
7691
Daniel Veillard1971ee22002-01-31 20:29:19 +00007692 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007693 return(1);
7694 if (xmlStrEqual(name, BAD_CAST "text"))
7695 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007696 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007697 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007698 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007699 return(1);
7700 return(0);
7701}
7702
7703/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007704 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007705 * @ctxt: the XPath Parser context
7706 *
7707 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7708 * [17] Argument ::= Expr
7709 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007710 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007711 * pushed on the stack
7712 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007713static void
7714xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007715 xmlChar *name;
7716 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007717 int nbargs = 0;
7718
7719 name = xmlXPathParseQName(ctxt, &prefix);
7720 if (name == NULL) {
7721 XP_ERROR(XPATH_EXPR_ERROR);
7722 }
7723 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007724#ifdef DEBUG_EXPR
7725 if (prefix == NULL)
7726 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7727 name);
7728 else
7729 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7730 prefix, name);
7731#endif
7732
Owen Taylor3473f882001-02-23 17:55:21 +00007733 if (CUR != '(') {
7734 XP_ERROR(XPATH_EXPR_ERROR);
7735 }
7736 NEXT;
7737 SKIP_BLANKS;
7738
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007739 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007740 if (CUR != ')') {
7741 while (CUR != 0) {
7742 int op1 = ctxt->comp->last;
7743 ctxt->comp->last = -1;
7744 xmlXPathCompileExpr(ctxt);
7745 CHECK_ERROR;
7746 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7747 nbargs++;
7748 if (CUR == ')') break;
7749 if (CUR != ',') {
7750 XP_ERROR(XPATH_EXPR_ERROR);
7751 }
7752 NEXT;
7753 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007754 }
Owen Taylor3473f882001-02-23 17:55:21 +00007755 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007756 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7757 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007758 NEXT;
7759 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007760}
7761
7762/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007763 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007764 * @ctxt: the XPath Parser context
7765 *
7766 * [15] PrimaryExpr ::= VariableReference
7767 * | '(' Expr ')'
7768 * | Literal
7769 * | Number
7770 * | FunctionCall
7771 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007772 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007773 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007774static void
7775xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007776 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007777 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007778 else if (CUR == '(') {
7779 NEXT;
7780 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007781 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007782 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007783 if (CUR != ')') {
7784 XP_ERROR(XPATH_EXPR_ERROR);
7785 }
7786 NEXT;
7787 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007788 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007789 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007790 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007791 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007792 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007793 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007794 }
7795 SKIP_BLANKS;
7796}
7797
7798/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007799 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007800 * @ctxt: the XPath Parser context
7801 *
7802 * [20] FilterExpr ::= PrimaryExpr
7803 * | FilterExpr Predicate
7804 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007805 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007806 * Square brackets are used to filter expressions in the same way that
7807 * they are used in location paths. It is an error if the expression to
7808 * be filtered does not evaluate to a node-set. The context node list
7809 * used for evaluating the expression in square brackets is the node-set
7810 * to be filtered listed in document order.
7811 */
7812
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007813static void
7814xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7815 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007816 CHECK_ERROR;
7817 SKIP_BLANKS;
7818
7819 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007820 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007821 SKIP_BLANKS;
7822 }
7823
7824
7825}
7826
7827/**
7828 * xmlXPathScanName:
7829 * @ctxt: the XPath Parser context
7830 *
7831 * Trickery: parse an XML name but without consuming the input flow
7832 * Needed to avoid insanity in the parser state.
7833 *
7834 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7835 * CombiningChar | Extender
7836 *
7837 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7838 *
7839 * [6] Names ::= Name (S Name)*
7840 *
7841 * Returns the Name parsed or NULL
7842 */
7843
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007844static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007845xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7846 xmlChar buf[XML_MAX_NAMELEN];
7847 int len = 0;
7848
7849 SKIP_BLANKS;
7850 if (!IS_LETTER(CUR) && (CUR != '_') &&
7851 (CUR != ':')) {
7852 return(NULL);
7853 }
7854
7855 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7856 (NXT(len) == '.') || (NXT(len) == '-') ||
7857 (NXT(len) == '_') || (NXT(len) == ':') ||
7858 (IS_COMBINING(NXT(len))) ||
7859 (IS_EXTENDER(NXT(len)))) {
7860 buf[len] = NXT(len);
7861 len++;
7862 if (len >= XML_MAX_NAMELEN) {
7863 xmlGenericError(xmlGenericErrorContext,
7864 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7865 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7866 (NXT(len) == '.') || (NXT(len) == '-') ||
7867 (NXT(len) == '_') || (NXT(len) == ':') ||
7868 (IS_COMBINING(NXT(len))) ||
7869 (IS_EXTENDER(NXT(len))))
7870 len++;
7871 break;
7872 }
7873 }
7874 return(xmlStrndup(buf, len));
7875}
7876
7877/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007878 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007879 * @ctxt: the XPath Parser context
7880 *
7881 * [19] PathExpr ::= LocationPath
7882 * | FilterExpr
7883 * | FilterExpr '/' RelativeLocationPath
7884 * | FilterExpr '//' RelativeLocationPath
7885 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007886 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007887 * The / operator and // operators combine an arbitrary expression
7888 * and a relative location path. It is an error if the expression
7889 * does not evaluate to a node-set.
7890 * The / operator does composition in the same way as when / is
7891 * used in a location path. As in location paths, // is short for
7892 * /descendant-or-self::node()/.
7893 */
7894
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007895static void
7896xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007897 int lc = 1; /* Should we branch to LocationPath ? */
7898 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7899
7900 SKIP_BLANKS;
7901 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007902 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007903 lc = 0;
7904 } else if (CUR == '*') {
7905 /* relative or absolute location path */
7906 lc = 1;
7907 } else if (CUR == '/') {
7908 /* relative or absolute location path */
7909 lc = 1;
7910 } else if (CUR == '@') {
7911 /* relative abbreviated attribute location path */
7912 lc = 1;
7913 } else if (CUR == '.') {
7914 /* relative abbreviated attribute location path */
7915 lc = 1;
7916 } else {
7917 /*
7918 * Problem is finding if we have a name here whether it's:
7919 * - a nodetype
7920 * - a function call in which case it's followed by '('
7921 * - an axis in which case it's followed by ':'
7922 * - a element name
7923 * We do an a priori analysis here rather than having to
7924 * maintain parsed token content through the recursive function
7925 * calls. This looks uglier but makes the code quite easier to
7926 * read/write/debug.
7927 */
7928 SKIP_BLANKS;
7929 name = xmlXPathScanName(ctxt);
7930 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7931#ifdef DEBUG_STEP
7932 xmlGenericError(xmlGenericErrorContext,
7933 "PathExpr: Axis\n");
7934#endif
7935 lc = 1;
7936 xmlFree(name);
7937 } else if (name != NULL) {
7938 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00007939
7940
7941 while (NXT(len) != 0) {
7942 if (NXT(len) == '/') {
7943 /* element name */
7944#ifdef DEBUG_STEP
7945 xmlGenericError(xmlGenericErrorContext,
7946 "PathExpr: AbbrRelLocation\n");
7947#endif
7948 lc = 1;
7949 break;
7950 } else if (IS_BLANK(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00007951 /* ignore blanks */
7952 ;
Owen Taylor3473f882001-02-23 17:55:21 +00007953 } else if (NXT(len) == ':') {
7954#ifdef DEBUG_STEP
7955 xmlGenericError(xmlGenericErrorContext,
7956 "PathExpr: AbbrRelLocation\n");
7957#endif
7958 lc = 1;
7959 break;
7960 } else if ((NXT(len) == '(')) {
7961 /* Note Type or Function */
7962 if (xmlXPathIsNodeType(name)) {
7963#ifdef DEBUG_STEP
7964 xmlGenericError(xmlGenericErrorContext,
7965 "PathExpr: Type search\n");
7966#endif
7967 lc = 1;
7968 } else {
7969#ifdef DEBUG_STEP
7970 xmlGenericError(xmlGenericErrorContext,
7971 "PathExpr: function call\n");
7972#endif
7973 lc = 0;
7974 }
7975 break;
7976 } else if ((NXT(len) == '[')) {
7977 /* element name */
7978#ifdef DEBUG_STEP
7979 xmlGenericError(xmlGenericErrorContext,
7980 "PathExpr: AbbrRelLocation\n");
7981#endif
7982 lc = 1;
7983 break;
7984 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7985 (NXT(len) == '=')) {
7986 lc = 1;
7987 break;
7988 } else {
7989 lc = 1;
7990 break;
7991 }
7992 len++;
7993 }
7994 if (NXT(len) == 0) {
7995#ifdef DEBUG_STEP
7996 xmlGenericError(xmlGenericErrorContext,
7997 "PathExpr: AbbrRelLocation\n");
7998#endif
7999 /* element name */
8000 lc = 1;
8001 }
8002 xmlFree(name);
8003 } else {
8004 /* make sure all cases are covered explicitely */
8005 XP_ERROR(XPATH_EXPR_ERROR);
8006 }
8007 }
8008
8009 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008010 if (CUR == '/') {
8011 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8012 } else {
8013 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008014 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008015 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008016 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008017 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008018 CHECK_ERROR;
8019 if ((CUR == '/') && (NXT(1) == '/')) {
8020 SKIP(2);
8021 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008022
8023 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8024 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8025 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8026
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008027 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008028 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008029 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008030 }
8031 }
8032 SKIP_BLANKS;
8033}
8034
8035/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008036 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008037 * @ctxt: the XPath Parser context
8038 *
8039 * [18] UnionExpr ::= PathExpr
8040 * | UnionExpr '|' PathExpr
8041 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008042 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008043 */
8044
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008045static void
8046xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8047 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008048 CHECK_ERROR;
8049 SKIP_BLANKS;
8050 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008051 int op1 = ctxt->comp->last;
8052 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008053
8054 NEXT;
8055 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008056 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008057
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008058 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8059
Owen Taylor3473f882001-02-23 17:55:21 +00008060 SKIP_BLANKS;
8061 }
Owen Taylor3473f882001-02-23 17:55:21 +00008062}
8063
8064/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008065 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008066 * @ctxt: the XPath Parser context
8067 *
8068 * [27] UnaryExpr ::= UnionExpr
8069 * | '-' UnaryExpr
8070 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008071 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008072 */
8073
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008074static void
8075xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008076 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008077 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008078
8079 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008080 while (CUR == '-') {
8081 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008082 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008083 NEXT;
8084 SKIP_BLANKS;
8085 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008086
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008087 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008088 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008089 if (found) {
8090 if (minus)
8091 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8092 else
8093 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008094 }
8095}
8096
8097/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008098 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008099 * @ctxt: the XPath Parser context
8100 *
8101 * [26] MultiplicativeExpr ::= UnaryExpr
8102 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8103 * | MultiplicativeExpr 'div' UnaryExpr
8104 * | MultiplicativeExpr 'mod' UnaryExpr
8105 * [34] MultiplyOperator ::= '*'
8106 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008107 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008108 */
8109
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008110static void
8111xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8112 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008113 CHECK_ERROR;
8114 SKIP_BLANKS;
8115 while ((CUR == '*') ||
8116 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8117 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8118 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008119 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008120
8121 if (CUR == '*') {
8122 op = 0;
8123 NEXT;
8124 } else if (CUR == 'd') {
8125 op = 1;
8126 SKIP(3);
8127 } else if (CUR == 'm') {
8128 op = 2;
8129 SKIP(3);
8130 }
8131 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008132 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008133 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008134 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008135 SKIP_BLANKS;
8136 }
8137}
8138
8139/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008140 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008141 * @ctxt: the XPath Parser context
8142 *
8143 * [25] AdditiveExpr ::= MultiplicativeExpr
8144 * | AdditiveExpr '+' MultiplicativeExpr
8145 * | AdditiveExpr '-' MultiplicativeExpr
8146 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008147 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008148 */
8149
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008150static void
8151xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008152
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008153 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008154 CHECK_ERROR;
8155 SKIP_BLANKS;
8156 while ((CUR == '+') || (CUR == '-')) {
8157 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008158 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008159
8160 if (CUR == '+') plus = 1;
8161 else plus = 0;
8162 NEXT;
8163 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008164 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008165 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008166 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008167 SKIP_BLANKS;
8168 }
8169}
8170
8171/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008172 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008173 * @ctxt: the XPath Parser context
8174 *
8175 * [24] RelationalExpr ::= AdditiveExpr
8176 * | RelationalExpr '<' AdditiveExpr
8177 * | RelationalExpr '>' AdditiveExpr
8178 * | RelationalExpr '<=' AdditiveExpr
8179 * | RelationalExpr '>=' AdditiveExpr
8180 *
8181 * A <= B > C is allowed ? Answer from James, yes with
8182 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8183 * which is basically what got implemented.
8184 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008185 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008186 * on the stack
8187 */
8188
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008189static void
8190xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8191 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008192 CHECK_ERROR;
8193 SKIP_BLANKS;
8194 while ((CUR == '<') ||
8195 (CUR == '>') ||
8196 ((CUR == '<') && (NXT(1) == '=')) ||
8197 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008198 int inf, strict;
8199 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008200
8201 if (CUR == '<') inf = 1;
8202 else inf = 0;
8203 if (NXT(1) == '=') strict = 0;
8204 else strict = 1;
8205 NEXT;
8206 if (!strict) NEXT;
8207 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008208 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008209 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008210 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008211 SKIP_BLANKS;
8212 }
8213}
8214
8215/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008216 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008217 * @ctxt: the XPath Parser context
8218 *
8219 * [23] EqualityExpr ::= RelationalExpr
8220 * | EqualityExpr '=' RelationalExpr
8221 * | EqualityExpr '!=' RelationalExpr
8222 *
8223 * A != B != C is allowed ? Answer from James, yes with
8224 * (RelationalExpr = RelationalExpr) = RelationalExpr
8225 * (RelationalExpr != RelationalExpr) != RelationalExpr
8226 * which is basically what got implemented.
8227 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008228 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008229 *
8230 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008231static void
8232xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8233 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008234 CHECK_ERROR;
8235 SKIP_BLANKS;
8236 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008237 int eq;
8238 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008239
8240 if (CUR == '=') eq = 1;
8241 else eq = 0;
8242 NEXT;
8243 if (!eq) NEXT;
8244 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008245 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008246 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008247 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008248 SKIP_BLANKS;
8249 }
8250}
8251
8252/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008253 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008254 * @ctxt: the XPath Parser context
8255 *
8256 * [22] AndExpr ::= EqualityExpr
8257 * | AndExpr 'and' EqualityExpr
8258 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008259 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008260 *
8261 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008262static void
8263xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8264 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008265 CHECK_ERROR;
8266 SKIP_BLANKS;
8267 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008268 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008269 SKIP(3);
8270 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008271 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008272 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008273 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008274 SKIP_BLANKS;
8275 }
8276}
8277
8278/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008279 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008280 * @ctxt: the XPath Parser context
8281 *
8282 * [14] Expr ::= OrExpr
8283 * [21] OrExpr ::= AndExpr
8284 * | OrExpr 'or' AndExpr
8285 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008286 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008287 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008288static void
8289xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8290 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008291 CHECK_ERROR;
8292 SKIP_BLANKS;
8293 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008294 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008295 SKIP(2);
8296 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008297 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008298 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008299 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8300 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008301 SKIP_BLANKS;
8302 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008303 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8304 /* more ops could be optimized too */
8305 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8306 }
Owen Taylor3473f882001-02-23 17:55:21 +00008307}
8308
8309/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008310 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008311 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008312 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008313 *
8314 * [8] Predicate ::= '[' PredicateExpr ']'
8315 * [9] PredicateExpr ::= Expr
8316 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008317 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008318 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008319static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008320xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008321 int op1 = ctxt->comp->last;
8322
8323 SKIP_BLANKS;
8324 if (CUR != '[') {
8325 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8326 }
8327 NEXT;
8328 SKIP_BLANKS;
8329
8330 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008331 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008332 CHECK_ERROR;
8333
8334 if (CUR != ']') {
8335 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8336 }
8337
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008338 if (filter)
8339 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8340 else
8341 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008342
8343 NEXT;
8344 SKIP_BLANKS;
8345}
8346
8347/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008348 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008349 * @ctxt: the XPath Parser context
8350 * @test: pointer to a xmlXPathTestVal
8351 * @type: pointer to a xmlXPathTypeVal
8352 * @prefix: placeholder for a possible name prefix
8353 *
8354 * [7] NodeTest ::= NameTest
8355 * | NodeType '(' ')'
8356 * | 'processing-instruction' '(' Literal ')'
8357 *
8358 * [37] NameTest ::= '*'
8359 * | NCName ':' '*'
8360 * | QName
8361 * [38] NodeType ::= 'comment'
8362 * | 'text'
8363 * | 'processing-instruction'
8364 * | 'node'
8365 *
8366 * Returns the name found and update @test, @type and @prefix appropriately
8367 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008368static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008369xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8370 xmlXPathTypeVal *type, const xmlChar **prefix,
8371 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008372 int blanks;
8373
8374 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8375 STRANGE;
8376 return(NULL);
8377 }
William M. Brack78637da2003-07-31 14:47:38 +00008378 *type = (xmlXPathTypeVal) 0;
8379 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008380 *prefix = NULL;
8381 SKIP_BLANKS;
8382
8383 if ((name == NULL) && (CUR == '*')) {
8384 /*
8385 * All elements
8386 */
8387 NEXT;
8388 *test = NODE_TEST_ALL;
8389 return(NULL);
8390 }
8391
8392 if (name == NULL)
8393 name = xmlXPathParseNCName(ctxt);
8394 if (name == NULL) {
8395 XP_ERROR0(XPATH_EXPR_ERROR);
8396 }
8397
8398 blanks = IS_BLANK(CUR);
8399 SKIP_BLANKS;
8400 if (CUR == '(') {
8401 NEXT;
8402 /*
8403 * NodeType or PI search
8404 */
8405 if (xmlStrEqual(name, BAD_CAST "comment"))
8406 *type = NODE_TYPE_COMMENT;
8407 else if (xmlStrEqual(name, BAD_CAST "node"))
8408 *type = NODE_TYPE_NODE;
8409 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8410 *type = NODE_TYPE_PI;
8411 else if (xmlStrEqual(name, BAD_CAST "text"))
8412 *type = NODE_TYPE_TEXT;
8413 else {
8414 if (name != NULL)
8415 xmlFree(name);
8416 XP_ERROR0(XPATH_EXPR_ERROR);
8417 }
8418
8419 *test = NODE_TEST_TYPE;
8420
8421 SKIP_BLANKS;
8422 if (*type == NODE_TYPE_PI) {
8423 /*
8424 * Specific case: search a PI by name.
8425 */
Owen Taylor3473f882001-02-23 17:55:21 +00008426 if (name != NULL)
8427 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008428 name = NULL;
8429 if (CUR != ')') {
8430 name = xmlXPathParseLiteral(ctxt);
8431 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008432 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008433 SKIP_BLANKS;
8434 }
Owen Taylor3473f882001-02-23 17:55:21 +00008435 }
8436 if (CUR != ')') {
8437 if (name != NULL)
8438 xmlFree(name);
8439 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8440 }
8441 NEXT;
8442 return(name);
8443 }
8444 *test = NODE_TEST_NAME;
8445 if ((!blanks) && (CUR == ':')) {
8446 NEXT;
8447
8448 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008449 * Since currently the parser context don't have a
8450 * namespace list associated:
8451 * The namespace name for this prefix can be computed
8452 * only at evaluation time. The compilation is done
8453 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008454 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008455#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008456 *prefix = xmlXPathNsLookup(ctxt->context, name);
8457 if (name != NULL)
8458 xmlFree(name);
8459 if (*prefix == NULL) {
8460 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8461 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008462#else
8463 *prefix = name;
8464#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008465
8466 if (CUR == '*') {
8467 /*
8468 * All elements
8469 */
8470 NEXT;
8471 *test = NODE_TEST_ALL;
8472 return(NULL);
8473 }
8474
8475 name = xmlXPathParseNCName(ctxt);
8476 if (name == NULL) {
8477 XP_ERROR0(XPATH_EXPR_ERROR);
8478 }
8479 }
8480 return(name);
8481}
8482
8483/**
8484 * xmlXPathIsAxisName:
8485 * @name: a preparsed name token
8486 *
8487 * [6] AxisName ::= 'ancestor'
8488 * | 'ancestor-or-self'
8489 * | 'attribute'
8490 * | 'child'
8491 * | 'descendant'
8492 * | 'descendant-or-self'
8493 * | 'following'
8494 * | 'following-sibling'
8495 * | 'namespace'
8496 * | 'parent'
8497 * | 'preceding'
8498 * | 'preceding-sibling'
8499 * | 'self'
8500 *
8501 * Returns the axis or 0
8502 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008503static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008504xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008505 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008506 switch (name[0]) {
8507 case 'a':
8508 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8509 ret = AXIS_ANCESTOR;
8510 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8511 ret = AXIS_ANCESTOR_OR_SELF;
8512 if (xmlStrEqual(name, BAD_CAST "attribute"))
8513 ret = AXIS_ATTRIBUTE;
8514 break;
8515 case 'c':
8516 if (xmlStrEqual(name, BAD_CAST "child"))
8517 ret = AXIS_CHILD;
8518 break;
8519 case 'd':
8520 if (xmlStrEqual(name, BAD_CAST "descendant"))
8521 ret = AXIS_DESCENDANT;
8522 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8523 ret = AXIS_DESCENDANT_OR_SELF;
8524 break;
8525 case 'f':
8526 if (xmlStrEqual(name, BAD_CAST "following"))
8527 ret = AXIS_FOLLOWING;
8528 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8529 ret = AXIS_FOLLOWING_SIBLING;
8530 break;
8531 case 'n':
8532 if (xmlStrEqual(name, BAD_CAST "namespace"))
8533 ret = AXIS_NAMESPACE;
8534 break;
8535 case 'p':
8536 if (xmlStrEqual(name, BAD_CAST "parent"))
8537 ret = AXIS_PARENT;
8538 if (xmlStrEqual(name, BAD_CAST "preceding"))
8539 ret = AXIS_PRECEDING;
8540 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8541 ret = AXIS_PRECEDING_SIBLING;
8542 break;
8543 case 's':
8544 if (xmlStrEqual(name, BAD_CAST "self"))
8545 ret = AXIS_SELF;
8546 break;
8547 }
8548 return(ret);
8549}
8550
8551/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008552 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008553 * @ctxt: the XPath Parser context
8554 *
8555 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8556 * | AbbreviatedStep
8557 *
8558 * [12] AbbreviatedStep ::= '.' | '..'
8559 *
8560 * [5] AxisSpecifier ::= AxisName '::'
8561 * | AbbreviatedAxisSpecifier
8562 *
8563 * [13] AbbreviatedAxisSpecifier ::= '@'?
8564 *
8565 * Modified for XPtr range support as:
8566 *
8567 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8568 * | AbbreviatedStep
8569 * | 'range-to' '(' Expr ')' Predicate*
8570 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008571 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008572 * A location step of . is short for self::node(). This is
8573 * particularly useful in conjunction with //. For example, the
8574 * location path .//para is short for
8575 * self::node()/descendant-or-self::node()/child::para
8576 * and so will select all para descendant elements of the context
8577 * node.
8578 * Similarly, a location step of .. is short for parent::node().
8579 * For example, ../title is short for parent::node()/child::title
8580 * and so will select the title children of the parent of the context
8581 * node.
8582 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008583static void
8584xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008585#ifdef LIBXML_XPTR_ENABLED
8586 int rangeto = 0;
8587 int op2 = -1;
8588#endif
8589
Owen Taylor3473f882001-02-23 17:55:21 +00008590 SKIP_BLANKS;
8591 if ((CUR == '.') && (NXT(1) == '.')) {
8592 SKIP(2);
8593 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008594 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8595 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008596 } else if (CUR == '.') {
8597 NEXT;
8598 SKIP_BLANKS;
8599 } else {
8600 xmlChar *name = NULL;
8601 const xmlChar *prefix = NULL;
8602 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008603 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008604 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008605 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008606
8607 /*
8608 * The modification needed for XPointer change to the production
8609 */
8610#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008611 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008612 name = xmlXPathParseNCName(ctxt);
8613 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008614 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008615 xmlFree(name);
8616 SKIP_BLANKS;
8617 if (CUR != '(') {
8618 XP_ERROR(XPATH_EXPR_ERROR);
8619 }
8620 NEXT;
8621 SKIP_BLANKS;
8622
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008623 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008624 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008625 CHECK_ERROR;
8626
8627 SKIP_BLANKS;
8628 if (CUR != ')') {
8629 XP_ERROR(XPATH_EXPR_ERROR);
8630 }
8631 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008632 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008633 goto eval_predicates;
8634 }
8635 }
8636#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008637 if (CUR == '*') {
8638 axis = AXIS_CHILD;
8639 } else {
8640 if (name == NULL)
8641 name = xmlXPathParseNCName(ctxt);
8642 if (name != NULL) {
8643 axis = xmlXPathIsAxisName(name);
8644 if (axis != 0) {
8645 SKIP_BLANKS;
8646 if ((CUR == ':') && (NXT(1) == ':')) {
8647 SKIP(2);
8648 xmlFree(name);
8649 name = NULL;
8650 } else {
8651 /* an element name can conflict with an axis one :-\ */
8652 axis = AXIS_CHILD;
8653 }
Owen Taylor3473f882001-02-23 17:55:21 +00008654 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008655 axis = AXIS_CHILD;
8656 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008657 } else if (CUR == '@') {
8658 NEXT;
8659 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008660 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008661 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008662 }
Owen Taylor3473f882001-02-23 17:55:21 +00008663 }
8664
8665 CHECK_ERROR;
8666
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008667 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008668 if (test == 0)
8669 return;
8670
8671#ifdef DEBUG_STEP
8672 xmlGenericError(xmlGenericErrorContext,
8673 "Basis : computing new set\n");
8674#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008675
Owen Taylor3473f882001-02-23 17:55:21 +00008676#ifdef DEBUG_STEP
8677 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008678 if (ctxt->value == NULL)
8679 xmlGenericError(xmlGenericErrorContext, "no value\n");
8680 else if (ctxt->value->nodesetval == NULL)
8681 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8682 else
8683 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008684#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008685
8686eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008687 op1 = ctxt->comp->last;
8688 ctxt->comp->last = -1;
8689
Owen Taylor3473f882001-02-23 17:55:21 +00008690 SKIP_BLANKS;
8691 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008692 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008693 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008694
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008695#ifdef LIBXML_XPTR_ENABLED
8696 if (rangeto) {
8697 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8698 } else
8699#endif
8700 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8701 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008702
Owen Taylor3473f882001-02-23 17:55:21 +00008703 }
8704#ifdef DEBUG_STEP
8705 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008706 if (ctxt->value == NULL)
8707 xmlGenericError(xmlGenericErrorContext, "no value\n");
8708 else if (ctxt->value->nodesetval == NULL)
8709 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8710 else
8711 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8712 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008713#endif
8714}
8715
8716/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008717 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008718 * @ctxt: the XPath Parser context
8719 *
8720 * [3] RelativeLocationPath ::= Step
8721 * | RelativeLocationPath '/' Step
8722 * | AbbreviatedRelativeLocationPath
8723 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8724 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008725 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008726 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008727static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008728xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008729(xmlXPathParserContextPtr ctxt) {
8730 SKIP_BLANKS;
8731 if ((CUR == '/') && (NXT(1) == '/')) {
8732 SKIP(2);
8733 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008734 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8735 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008736 } else if (CUR == '/') {
8737 NEXT;
8738 SKIP_BLANKS;
8739 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008740 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008741 SKIP_BLANKS;
8742 while (CUR == '/') {
8743 if ((CUR == '/') && (NXT(1) == '/')) {
8744 SKIP(2);
8745 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008746 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008747 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008748 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008749 } else if (CUR == '/') {
8750 NEXT;
8751 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008752 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008753 }
8754 SKIP_BLANKS;
8755 }
8756}
8757
8758/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008759 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008760 * @ctxt: the XPath Parser context
8761 *
8762 * [1] LocationPath ::= RelativeLocationPath
8763 * | AbsoluteLocationPath
8764 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8765 * | AbbreviatedAbsoluteLocationPath
8766 * [10] AbbreviatedAbsoluteLocationPath ::=
8767 * '//' RelativeLocationPath
8768 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008769 * Compile a location path
8770 *
Owen Taylor3473f882001-02-23 17:55:21 +00008771 * // is short for /descendant-or-self::node()/. For example,
8772 * //para is short for /descendant-or-self::node()/child::para and
8773 * so will select any para element in the document (even a para element
8774 * that is a document element will be selected by //para since the
8775 * document element node is a child of the root node); div//para is
8776 * short for div/descendant-or-self::node()/child::para and so will
8777 * select all para descendants of div children.
8778 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008779static void
8780xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008781 SKIP_BLANKS;
8782 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008783 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008784 } else {
8785 while (CUR == '/') {
8786 if ((CUR == '/') && (NXT(1) == '/')) {
8787 SKIP(2);
8788 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008789 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8790 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008791 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008792 } else if (CUR == '/') {
8793 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008794 SKIP_BLANKS;
8795 if ((CUR != 0 ) &&
8796 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8797 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008798 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008799 }
8800 }
8801 }
8802}
8803
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008804/************************************************************************
8805 * *
8806 * XPath precompiled expression evaluation *
8807 * *
8808 ************************************************************************/
8809
Daniel Veillardf06307e2001-07-03 10:35:50 +00008810static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008811xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8812
8813/**
8814 * xmlXPathNodeCollectAndTest:
8815 * @ctxt: the XPath Parser context
8816 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008817 * @first: pointer to the first element in document order
8818 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008819 *
8820 * This is the function implementing a step: based on the current list
8821 * of nodes, it builds up a new list, looking at all nodes under that
8822 * axis and selecting them it also do the predicate filtering
8823 *
8824 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008825 *
8826 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008827 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008828static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008829xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008830 xmlXPathStepOpPtr op,
8831 xmlNodePtr * first, xmlNodePtr * last)
8832{
William M. Brack78637da2003-07-31 14:47:38 +00008833 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8834 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8835 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008836 const xmlChar *prefix = op->value4;
8837 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008838 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008839
8840#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008841 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008842#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008843 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008844 xmlNodeSetPtr ret, list;
8845 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008846 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008847 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008848 xmlNodePtr cur = NULL;
8849 xmlXPathObjectPtr obj;
8850 xmlNodeSetPtr nodelist;
8851 xmlNodePtr tmp;
8852
Daniel Veillardf06307e2001-07-03 10:35:50 +00008853 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008854 obj = valuePop(ctxt);
8855 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008856 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008857 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008858 URI = xmlXPathNsLookup(ctxt->context, prefix);
8859 if (URI == NULL)
8860 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008861 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008862#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008863 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008864#endif
8865 switch (axis) {
8866 case AXIS_ANCESTOR:
8867#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008868 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008869#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008870 first = NULL;
8871 next = xmlXPathNextAncestor;
8872 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008873 case AXIS_ANCESTOR_OR_SELF:
8874#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 xmlGenericError(xmlGenericErrorContext,
8876 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008877#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008878 first = NULL;
8879 next = xmlXPathNextAncestorOrSelf;
8880 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008881 case AXIS_ATTRIBUTE:
8882#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008883 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008884#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008885 first = NULL;
8886 last = NULL;
8887 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008888 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008889 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008890 case AXIS_CHILD:
8891#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008892 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008893#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008894 last = NULL;
8895 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008896 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008897 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008898 case AXIS_DESCENDANT:
8899#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008900 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008901#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 last = NULL;
8903 next = xmlXPathNextDescendant;
8904 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008905 case AXIS_DESCENDANT_OR_SELF:
8906#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008907 xmlGenericError(xmlGenericErrorContext,
8908 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008909#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008910 last = NULL;
8911 next = xmlXPathNextDescendantOrSelf;
8912 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008913 case AXIS_FOLLOWING:
8914#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008915 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008916#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 last = NULL;
8918 next = xmlXPathNextFollowing;
8919 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008920 case AXIS_FOLLOWING_SIBLING:
8921#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008922 xmlGenericError(xmlGenericErrorContext,
8923 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008924#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008925 last = NULL;
8926 next = xmlXPathNextFollowingSibling;
8927 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008928 case AXIS_NAMESPACE:
8929#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008930 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008931#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008932 first = NULL;
8933 last = NULL;
8934 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008935 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008936 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008937 case AXIS_PARENT:
8938#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008939 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008940#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008941 first = NULL;
8942 next = xmlXPathNextParent;
8943 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008944 case AXIS_PRECEDING:
8945#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008946 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008947#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008948 first = NULL;
8949 next = xmlXPathNextPrecedingInternal;
8950 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008951 case AXIS_PRECEDING_SIBLING:
8952#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008953 xmlGenericError(xmlGenericErrorContext,
8954 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008955#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008956 first = NULL;
8957 next = xmlXPathNextPrecedingSibling;
8958 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008959 case AXIS_SELF:
8960#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008961 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008962#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008963 first = NULL;
8964 last = NULL;
8965 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008966 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008967 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008968 }
8969 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008970 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008971
8972 nodelist = obj->nodesetval;
8973 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974 xmlXPathFreeObject(obj);
8975 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8976 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977 }
8978 addNode = xmlXPathNodeSetAddUnique;
8979 ret = NULL;
8980#ifdef DEBUG_STEP
8981 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008983 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008984 case NODE_TEST_NONE:
8985 xmlGenericError(xmlGenericErrorContext,
8986 " searching for none !!!\n");
8987 break;
8988 case NODE_TEST_TYPE:
8989 xmlGenericError(xmlGenericErrorContext,
8990 " searching for type %d\n", type);
8991 break;
8992 case NODE_TEST_PI:
8993 xmlGenericError(xmlGenericErrorContext,
8994 " searching for PI !!!\n");
8995 break;
8996 case NODE_TEST_ALL:
8997 xmlGenericError(xmlGenericErrorContext,
8998 " searching for *\n");
8999 break;
9000 case NODE_TEST_NS:
9001 xmlGenericError(xmlGenericErrorContext,
9002 " searching for namespace %s\n",
9003 prefix);
9004 break;
9005 case NODE_TEST_NAME:
9006 xmlGenericError(xmlGenericErrorContext,
9007 " searching for name %s\n", name);
9008 if (prefix != NULL)
9009 xmlGenericError(xmlGenericErrorContext,
9010 " with namespace %s\n", prefix);
9011 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009012 }
9013 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9014#endif
9015 /*
9016 * 2.3 Node Tests
9017 * - For the attribute axis, the principal node type is attribute.
9018 * - For the namespace axis, the principal node type is namespace.
9019 * - For other axes, the principal node type is element.
9020 *
9021 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009022 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009023 * select all element children of the context node
9024 */
9025 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009026 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009027 ctxt->context->node = nodelist->nodeTab[i];
9028
Daniel Veillardf06307e2001-07-03 10:35:50 +00009029 cur = NULL;
9030 list = xmlXPathNodeSetCreate(NULL);
9031 do {
9032 cur = next(ctxt, cur);
9033 if (cur == NULL)
9034 break;
9035 if ((first != NULL) && (*first == cur))
9036 break;
9037 if (((t % 256) == 0) &&
9038 (first != NULL) && (*first != NULL) &&
9039 (xmlXPathCmpNodes(*first, cur) >= 0))
9040 break;
9041 if ((last != NULL) && (*last == cur))
9042 break;
9043 if (((t % 256) == 0) &&
9044 (last != NULL) && (*last != NULL) &&
9045 (xmlXPathCmpNodes(cur, *last) >= 0))
9046 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009047 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009048#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009049 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9050#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009052 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 ctxt->context->node = tmp;
9054 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009055 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009056 if ((cur->type == type) ||
9057 ((type == NODE_TYPE_NODE) &&
9058 ((cur->type == XML_DOCUMENT_NODE) ||
9059 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9060 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009061 (cur->type == XML_NAMESPACE_DECL) ||
9062 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009063 (cur->type == XML_PI_NODE) ||
9064 (cur->type == XML_COMMENT_NODE) ||
9065 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009066 (cur->type == XML_TEXT_NODE))) ||
9067 ((type == NODE_TYPE_TEXT) &&
9068 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009069#ifdef DEBUG_STEP
9070 n++;
9071#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009072 addNode(list, cur);
9073 }
9074 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009075 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009076 if (cur->type == XML_PI_NODE) {
9077 if ((name != NULL) &&
9078 (!xmlStrEqual(name, cur->name)))
9079 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009080#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009081 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009082#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009083 addNode(list, cur);
9084 }
9085 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009086 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009087 if (axis == AXIS_ATTRIBUTE) {
9088 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009089#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009090 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 addNode(list, cur);
9093 }
9094 } else if (axis == AXIS_NAMESPACE) {
9095 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009096#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009097 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009098#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009099 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9100 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 }
9102 } else {
9103 if (cur->type == XML_ELEMENT_NODE) {
9104 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009105#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009106 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009107#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 addNode(list, cur);
9109 } else if ((cur->ns != NULL) &&
9110 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009111#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009112 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009113#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 addNode(list, cur);
9115 }
9116 }
9117 }
9118 break;
9119 case NODE_TEST_NS:{
9120 TODO;
9121 break;
9122 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009123 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009124 switch (cur->type) {
9125 case XML_ELEMENT_NODE:
9126 if (xmlStrEqual(name, cur->name)) {
9127 if (prefix == NULL) {
9128 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009129#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009130 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009131#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 addNode(list, cur);
9133 }
9134 } else {
9135 if ((cur->ns != NULL) &&
9136 (xmlStrEqual(URI,
9137 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009138#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009140#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 addNode(list, cur);
9142 }
9143 }
9144 }
9145 break;
9146 case XML_ATTRIBUTE_NODE:{
9147 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009148
Daniel Veillardf06307e2001-07-03 10:35:50 +00009149 if (xmlStrEqual(name, attr->name)) {
9150 if (prefix == NULL) {
9151 if ((attr->ns == NULL) ||
9152 (attr->ns->prefix == NULL)) {
9153#ifdef DEBUG_STEP
9154 n++;
9155#endif
9156 addNode(list,
9157 (xmlNodePtr) attr);
9158 }
9159 } else {
9160 if ((attr->ns != NULL) &&
9161 (xmlStrEqual(URI,
9162 attr->ns->
9163 href))) {
9164#ifdef DEBUG_STEP
9165 n++;
9166#endif
9167 addNode(list,
9168 (xmlNodePtr) attr);
9169 }
9170 }
9171 }
9172 break;
9173 }
9174 case XML_NAMESPACE_DECL:
9175 if (cur->type == XML_NAMESPACE_DECL) {
9176 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009177
Daniel Veillardf06307e2001-07-03 10:35:50 +00009178 if ((ns->prefix != NULL) && (name != NULL)
9179 && (xmlStrEqual(ns->prefix, name))) {
9180#ifdef DEBUG_STEP
9181 n++;
9182#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009183 xmlXPathNodeSetAddNs(list,
9184 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009185 }
9186 }
9187 break;
9188 default:
9189 break;
9190 }
9191 break;
9192 break;
9193 }
9194 } while (cur != NULL);
9195
9196 /*
9197 * If there is some predicate filtering do it now
9198 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009199 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009200 xmlXPathObjectPtr obj2;
9201
9202 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9203 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9204 CHECK_TYPE0(XPATH_NODESET);
9205 obj2 = valuePop(ctxt);
9206 list = obj2->nodesetval;
9207 obj2->nodesetval = NULL;
9208 xmlXPathFreeObject(obj2);
9209 }
9210 if (ret == NULL) {
9211 ret = list;
9212 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009213 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009214 xmlXPathFreeNodeSet(list);
9215 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009216 }
9217 ctxt->context->node = tmp;
9218#ifdef DEBUG_STEP
9219 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009220 "\nExamined %d nodes, found %d nodes at that step\n",
9221 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009222#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009223 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009224 if ((obj->boolval) && (obj->user != NULL)) {
9225 ctxt->value->boolval = 1;
9226 ctxt->value->user = obj->user;
9227 obj->user = NULL;
9228 obj->boolval = 0;
9229 }
9230 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009231 return(t);
9232}
9233
9234/**
9235 * xmlXPathNodeCollectAndTestNth:
9236 * @ctxt: the XPath Parser context
9237 * @op: the XPath precompiled step operation
9238 * @indx: the index to collect
9239 * @first: pointer to the first element in document order
9240 * @last: pointer to the last element in document order
9241 *
9242 * This is the function implementing a step: based on the current list
9243 * of nodes, it builds up a new list, looking at all nodes under that
9244 * axis and selecting them it also do the predicate filtering
9245 *
9246 * Pushes the new NodeSet resulting from the search.
9247 * Returns the number of node traversed
9248 */
9249static int
9250xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9251 xmlXPathStepOpPtr op, int indx,
9252 xmlNodePtr * first, xmlNodePtr * last)
9253{
William M. Brack78637da2003-07-31 14:47:38 +00009254 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9255 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9256 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009257 const xmlChar *prefix = op->value4;
9258 const xmlChar *name = op->value5;
9259 const xmlChar *URI = NULL;
9260 int n = 0, t = 0;
9261
9262 int i;
9263 xmlNodeSetPtr list;
9264 xmlXPathTraversalFunction next = NULL;
9265 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9266 xmlNodePtr cur = NULL;
9267 xmlXPathObjectPtr obj;
9268 xmlNodeSetPtr nodelist;
9269 xmlNodePtr tmp;
9270
9271 CHECK_TYPE0(XPATH_NODESET);
9272 obj = valuePop(ctxt);
9273 addNode = xmlXPathNodeSetAdd;
9274 if (prefix != NULL) {
9275 URI = xmlXPathNsLookup(ctxt->context, prefix);
9276 if (URI == NULL)
9277 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9278 }
9279#ifdef DEBUG_STEP_NTH
9280 xmlGenericError(xmlGenericErrorContext, "new step : ");
9281 if (first != NULL) {
9282 if (*first != NULL)
9283 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9284 (*first)->name);
9285 else
9286 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9287 }
9288 if (last != NULL) {
9289 if (*last != NULL)
9290 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9291 (*last)->name);
9292 else
9293 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9294 }
9295#endif
9296 switch (axis) {
9297 case AXIS_ANCESTOR:
9298#ifdef DEBUG_STEP_NTH
9299 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9300#endif
9301 first = NULL;
9302 next = xmlXPathNextAncestor;
9303 break;
9304 case AXIS_ANCESTOR_OR_SELF:
9305#ifdef DEBUG_STEP_NTH
9306 xmlGenericError(xmlGenericErrorContext,
9307 "axis 'ancestors-or-self' ");
9308#endif
9309 first = NULL;
9310 next = xmlXPathNextAncestorOrSelf;
9311 break;
9312 case AXIS_ATTRIBUTE:
9313#ifdef DEBUG_STEP_NTH
9314 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9315#endif
9316 first = NULL;
9317 last = NULL;
9318 next = xmlXPathNextAttribute;
9319 break;
9320 case AXIS_CHILD:
9321#ifdef DEBUG_STEP_NTH
9322 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9323#endif
9324 last = NULL;
9325 next = xmlXPathNextChild;
9326 break;
9327 case AXIS_DESCENDANT:
9328#ifdef DEBUG_STEP_NTH
9329 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9330#endif
9331 last = NULL;
9332 next = xmlXPathNextDescendant;
9333 break;
9334 case AXIS_DESCENDANT_OR_SELF:
9335#ifdef DEBUG_STEP_NTH
9336 xmlGenericError(xmlGenericErrorContext,
9337 "axis 'descendant-or-self' ");
9338#endif
9339 last = NULL;
9340 next = xmlXPathNextDescendantOrSelf;
9341 break;
9342 case AXIS_FOLLOWING:
9343#ifdef DEBUG_STEP_NTH
9344 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9345#endif
9346 last = NULL;
9347 next = xmlXPathNextFollowing;
9348 break;
9349 case AXIS_FOLLOWING_SIBLING:
9350#ifdef DEBUG_STEP_NTH
9351 xmlGenericError(xmlGenericErrorContext,
9352 "axis 'following-siblings' ");
9353#endif
9354 last = NULL;
9355 next = xmlXPathNextFollowingSibling;
9356 break;
9357 case AXIS_NAMESPACE:
9358#ifdef DEBUG_STEP_NTH
9359 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9360#endif
9361 last = NULL;
9362 first = NULL;
9363 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9364 break;
9365 case AXIS_PARENT:
9366#ifdef DEBUG_STEP_NTH
9367 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9368#endif
9369 first = NULL;
9370 next = xmlXPathNextParent;
9371 break;
9372 case AXIS_PRECEDING:
9373#ifdef DEBUG_STEP_NTH
9374 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9375#endif
9376 first = NULL;
9377 next = xmlXPathNextPrecedingInternal;
9378 break;
9379 case AXIS_PRECEDING_SIBLING:
9380#ifdef DEBUG_STEP_NTH
9381 xmlGenericError(xmlGenericErrorContext,
9382 "axis 'preceding-sibling' ");
9383#endif
9384 first = NULL;
9385 next = xmlXPathNextPrecedingSibling;
9386 break;
9387 case AXIS_SELF:
9388#ifdef DEBUG_STEP_NTH
9389 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9390#endif
9391 first = NULL;
9392 last = NULL;
9393 next = xmlXPathNextSelf;
9394 break;
9395 }
9396 if (next == NULL)
9397 return(0);
9398
9399 nodelist = obj->nodesetval;
9400 if (nodelist == NULL) {
9401 xmlXPathFreeObject(obj);
9402 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9403 return(0);
9404 }
9405 addNode = xmlXPathNodeSetAddUnique;
9406#ifdef DEBUG_STEP_NTH
9407 xmlGenericError(xmlGenericErrorContext,
9408 " context contains %d nodes\n", nodelist->nodeNr);
9409 switch (test) {
9410 case NODE_TEST_NONE:
9411 xmlGenericError(xmlGenericErrorContext,
9412 " searching for none !!!\n");
9413 break;
9414 case NODE_TEST_TYPE:
9415 xmlGenericError(xmlGenericErrorContext,
9416 " searching for type %d\n", type);
9417 break;
9418 case NODE_TEST_PI:
9419 xmlGenericError(xmlGenericErrorContext,
9420 " searching for PI !!!\n");
9421 break;
9422 case NODE_TEST_ALL:
9423 xmlGenericError(xmlGenericErrorContext,
9424 " searching for *\n");
9425 break;
9426 case NODE_TEST_NS:
9427 xmlGenericError(xmlGenericErrorContext,
9428 " searching for namespace %s\n",
9429 prefix);
9430 break;
9431 case NODE_TEST_NAME:
9432 xmlGenericError(xmlGenericErrorContext,
9433 " searching for name %s\n", name);
9434 if (prefix != NULL)
9435 xmlGenericError(xmlGenericErrorContext,
9436 " with namespace %s\n", prefix);
9437 break;
9438 }
9439 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9440#endif
9441 /*
9442 * 2.3 Node Tests
9443 * - For the attribute axis, the principal node type is attribute.
9444 * - For the namespace axis, the principal node type is namespace.
9445 * - For other axes, the principal node type is element.
9446 *
9447 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009448 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009449 * select all element children of the context node
9450 */
9451 tmp = ctxt->context->node;
9452 list = xmlXPathNodeSetCreate(NULL);
9453 for (i = 0; i < nodelist->nodeNr; i++) {
9454 ctxt->context->node = nodelist->nodeTab[i];
9455
9456 cur = NULL;
9457 n = 0;
9458 do {
9459 cur = next(ctxt, cur);
9460 if (cur == NULL)
9461 break;
9462 if ((first != NULL) && (*first == cur))
9463 break;
9464 if (((t % 256) == 0) &&
9465 (first != NULL) && (*first != NULL) &&
9466 (xmlXPathCmpNodes(*first, cur) >= 0))
9467 break;
9468 if ((last != NULL) && (*last == cur))
9469 break;
9470 if (((t % 256) == 0) &&
9471 (last != NULL) && (*last != NULL) &&
9472 (xmlXPathCmpNodes(cur, *last) >= 0))
9473 break;
9474 t++;
9475 switch (test) {
9476 case NODE_TEST_NONE:
9477 ctxt->context->node = tmp;
9478 STRANGE return(0);
9479 case NODE_TEST_TYPE:
9480 if ((cur->type == type) ||
9481 ((type == NODE_TYPE_NODE) &&
9482 ((cur->type == XML_DOCUMENT_NODE) ||
9483 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9484 (cur->type == XML_ELEMENT_NODE) ||
9485 (cur->type == XML_PI_NODE) ||
9486 (cur->type == XML_COMMENT_NODE) ||
9487 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009488 (cur->type == XML_TEXT_NODE))) ||
9489 ((type == NODE_TYPE_TEXT) &&
9490 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009491 n++;
9492 if (n == indx)
9493 addNode(list, cur);
9494 }
9495 break;
9496 case NODE_TEST_PI:
9497 if (cur->type == XML_PI_NODE) {
9498 if ((name != NULL) &&
9499 (!xmlStrEqual(name, cur->name)))
9500 break;
9501 n++;
9502 if (n == indx)
9503 addNode(list, cur);
9504 }
9505 break;
9506 case NODE_TEST_ALL:
9507 if (axis == AXIS_ATTRIBUTE) {
9508 if (cur->type == XML_ATTRIBUTE_NODE) {
9509 n++;
9510 if (n == indx)
9511 addNode(list, cur);
9512 }
9513 } else if (axis == AXIS_NAMESPACE) {
9514 if (cur->type == XML_NAMESPACE_DECL) {
9515 n++;
9516 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009517 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9518 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009519 }
9520 } else {
9521 if (cur->type == XML_ELEMENT_NODE) {
9522 if (prefix == NULL) {
9523 n++;
9524 if (n == indx)
9525 addNode(list, cur);
9526 } else if ((cur->ns != NULL) &&
9527 (xmlStrEqual(URI, cur->ns->href))) {
9528 n++;
9529 if (n == indx)
9530 addNode(list, cur);
9531 }
9532 }
9533 }
9534 break;
9535 case NODE_TEST_NS:{
9536 TODO;
9537 break;
9538 }
9539 case NODE_TEST_NAME:
9540 switch (cur->type) {
9541 case XML_ELEMENT_NODE:
9542 if (xmlStrEqual(name, cur->name)) {
9543 if (prefix == NULL) {
9544 if (cur->ns == NULL) {
9545 n++;
9546 if (n == indx)
9547 addNode(list, cur);
9548 }
9549 } else {
9550 if ((cur->ns != NULL) &&
9551 (xmlStrEqual(URI,
9552 cur->ns->href))) {
9553 n++;
9554 if (n == indx)
9555 addNode(list, cur);
9556 }
9557 }
9558 }
9559 break;
9560 case XML_ATTRIBUTE_NODE:{
9561 xmlAttrPtr attr = (xmlAttrPtr) cur;
9562
9563 if (xmlStrEqual(name, attr->name)) {
9564 if (prefix == NULL) {
9565 if ((attr->ns == NULL) ||
9566 (attr->ns->prefix == NULL)) {
9567 n++;
9568 if (n == indx)
9569 addNode(list, cur);
9570 }
9571 } else {
9572 if ((attr->ns != NULL) &&
9573 (xmlStrEqual(URI,
9574 attr->ns->
9575 href))) {
9576 n++;
9577 if (n == indx)
9578 addNode(list, cur);
9579 }
9580 }
9581 }
9582 break;
9583 }
9584 case XML_NAMESPACE_DECL:
9585 if (cur->type == XML_NAMESPACE_DECL) {
9586 xmlNsPtr ns = (xmlNsPtr) cur;
9587
9588 if ((ns->prefix != NULL) && (name != NULL)
9589 && (xmlStrEqual(ns->prefix, name))) {
9590 n++;
9591 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009592 xmlXPathNodeSetAddNs(list,
9593 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009594 }
9595 }
9596 break;
9597 default:
9598 break;
9599 }
9600 break;
9601 break;
9602 }
9603 } while (n < indx);
9604 }
9605 ctxt->context->node = tmp;
9606#ifdef DEBUG_STEP_NTH
9607 xmlGenericError(xmlGenericErrorContext,
9608 "\nExamined %d nodes, found %d nodes at that step\n",
9609 t, list->nodeNr);
9610#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009611 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009612 if ((obj->boolval) && (obj->user != NULL)) {
9613 ctxt->value->boolval = 1;
9614 ctxt->value->user = obj->user;
9615 obj->user = NULL;
9616 obj->boolval = 0;
9617 }
9618 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009619 return(t);
9620}
9621
9622/**
9623 * xmlXPathCompOpEvalFirst:
9624 * @ctxt: the XPath parser context with the compiled expression
9625 * @op: an XPath compiled operation
9626 * @first: the first elem found so far
9627 *
9628 * Evaluate the Precompiled XPath operation searching only the first
9629 * element in document order
9630 *
9631 * Returns the number of examined objects.
9632 */
9633static int
9634xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9635 xmlXPathStepOpPtr op, xmlNodePtr * first)
9636{
9637 int total = 0, cur;
9638 xmlXPathCompExprPtr comp;
9639 xmlXPathObjectPtr arg1, arg2;
9640
Daniel Veillard556c6682001-10-06 09:59:51 +00009641 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009642 comp = ctxt->comp;
9643 switch (op->op) {
9644 case XPATH_OP_END:
9645 return (0);
9646 case XPATH_OP_UNION:
9647 total =
9648 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9649 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009650 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009651 if ((ctxt->value != NULL)
9652 && (ctxt->value->type == XPATH_NODESET)
9653 && (ctxt->value->nodesetval != NULL)
9654 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9655 /*
9656 * limit tree traversing to first node in the result
9657 */
9658 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9659 *first = ctxt->value->nodesetval->nodeTab[0];
9660 }
9661 cur =
9662 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9663 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009664 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009665 CHECK_TYPE0(XPATH_NODESET);
9666 arg2 = valuePop(ctxt);
9667
9668 CHECK_TYPE0(XPATH_NODESET);
9669 arg1 = valuePop(ctxt);
9670
9671 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9672 arg2->nodesetval);
9673 valuePush(ctxt, arg1);
9674 xmlXPathFreeObject(arg2);
9675 /* optimizer */
9676 if (total > cur)
9677 xmlXPathCompSwap(op);
9678 return (total + cur);
9679 case XPATH_OP_ROOT:
9680 xmlXPathRoot(ctxt);
9681 return (0);
9682 case XPATH_OP_NODE:
9683 if (op->ch1 != -1)
9684 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009685 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009686 if (op->ch2 != -1)
9687 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009688 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009689 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9690 return (total);
9691 case XPATH_OP_RESET:
9692 if (op->ch1 != -1)
9693 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009694 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009695 if (op->ch2 != -1)
9696 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009697 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009698 ctxt->context->node = NULL;
9699 return (total);
9700 case XPATH_OP_COLLECT:{
9701 if (op->ch1 == -1)
9702 return (total);
9703
9704 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009705 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009706
9707 /*
9708 * Optimization for [n] selection where n is a number
9709 */
9710 if ((op->ch2 != -1) &&
9711 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9712 (comp->steps[op->ch2].ch1 == -1) &&
9713 (comp->steps[op->ch2].ch2 != -1) &&
9714 (comp->steps[comp->steps[op->ch2].ch2].op ==
9715 XPATH_OP_VALUE)) {
9716 xmlXPathObjectPtr val;
9717
9718 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9719 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9720 int indx = (int) val->floatval;
9721
9722 if (val->floatval == (float) indx) {
9723 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9724 first, NULL);
9725 return (total);
9726 }
9727 }
9728 }
9729 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9730 return (total);
9731 }
9732 case XPATH_OP_VALUE:
9733 valuePush(ctxt,
9734 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9735 return (0);
9736 case XPATH_OP_SORT:
9737 if (op->ch1 != -1)
9738 total +=
9739 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9740 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009741 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009742 if ((ctxt->value != NULL)
9743 && (ctxt->value->type == XPATH_NODESET)
9744 && (ctxt->value->nodesetval != NULL))
9745 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9746 return (total);
9747 default:
9748 return (xmlXPathCompOpEval(ctxt, op));
9749 }
9750}
9751
9752/**
9753 * xmlXPathCompOpEvalLast:
9754 * @ctxt: the XPath parser context with the compiled expression
9755 * @op: an XPath compiled operation
9756 * @last: the last elem found so far
9757 *
9758 * Evaluate the Precompiled XPath operation searching only the last
9759 * element in document order
9760 *
9761 * Returns the number of node traversed
9762 */
9763static int
9764xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9765 xmlNodePtr * last)
9766{
9767 int total = 0, cur;
9768 xmlXPathCompExprPtr comp;
9769 xmlXPathObjectPtr arg1, arg2;
9770
Daniel Veillard556c6682001-10-06 09:59:51 +00009771 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009772 comp = ctxt->comp;
9773 switch (op->op) {
9774 case XPATH_OP_END:
9775 return (0);
9776 case XPATH_OP_UNION:
9777 total =
9778 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009779 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009780 if ((ctxt->value != NULL)
9781 && (ctxt->value->type == XPATH_NODESET)
9782 && (ctxt->value->nodesetval != NULL)
9783 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9784 /*
9785 * limit tree traversing to first node in the result
9786 */
9787 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9788 *last =
9789 ctxt->value->nodesetval->nodeTab[ctxt->value->
9790 nodesetval->nodeNr -
9791 1];
9792 }
9793 cur =
9794 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009795 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009796 if ((ctxt->value != NULL)
9797 && (ctxt->value->type == XPATH_NODESET)
9798 && (ctxt->value->nodesetval != NULL)
9799 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9800 }
9801 CHECK_TYPE0(XPATH_NODESET);
9802 arg2 = valuePop(ctxt);
9803
9804 CHECK_TYPE0(XPATH_NODESET);
9805 arg1 = valuePop(ctxt);
9806
9807 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9808 arg2->nodesetval);
9809 valuePush(ctxt, arg1);
9810 xmlXPathFreeObject(arg2);
9811 /* optimizer */
9812 if (total > cur)
9813 xmlXPathCompSwap(op);
9814 return (total + cur);
9815 case XPATH_OP_ROOT:
9816 xmlXPathRoot(ctxt);
9817 return (0);
9818 case XPATH_OP_NODE:
9819 if (op->ch1 != -1)
9820 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009821 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009822 if (op->ch2 != -1)
9823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009824 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009825 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9826 return (total);
9827 case XPATH_OP_RESET:
9828 if (op->ch1 != -1)
9829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009830 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009831 if (op->ch2 != -1)
9832 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009833 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009834 ctxt->context->node = NULL;
9835 return (total);
9836 case XPATH_OP_COLLECT:{
9837 if (op->ch1 == -1)
9838 return (0);
9839
9840 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009841 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009842
9843 /*
9844 * Optimization for [n] selection where n is a number
9845 */
9846 if ((op->ch2 != -1) &&
9847 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9848 (comp->steps[op->ch2].ch1 == -1) &&
9849 (comp->steps[op->ch2].ch2 != -1) &&
9850 (comp->steps[comp->steps[op->ch2].ch2].op ==
9851 XPATH_OP_VALUE)) {
9852 xmlXPathObjectPtr val;
9853
9854 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9855 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9856 int indx = (int) val->floatval;
9857
9858 if (val->floatval == (float) indx) {
9859 total +=
9860 xmlXPathNodeCollectAndTestNth(ctxt, op,
9861 indx, NULL,
9862 last);
9863 return (total);
9864 }
9865 }
9866 }
9867 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9868 return (total);
9869 }
9870 case XPATH_OP_VALUE:
9871 valuePush(ctxt,
9872 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9873 return (0);
9874 case XPATH_OP_SORT:
9875 if (op->ch1 != -1)
9876 total +=
9877 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9878 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009879 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009880 if ((ctxt->value != NULL)
9881 && (ctxt->value->type == XPATH_NODESET)
9882 && (ctxt->value->nodesetval != NULL))
9883 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9884 return (total);
9885 default:
9886 return (xmlXPathCompOpEval(ctxt, op));
9887 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009888}
9889
Owen Taylor3473f882001-02-23 17:55:21 +00009890/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009891 * xmlXPathCompOpEval:
9892 * @ctxt: the XPath parser context with the compiled expression
9893 * @op: an XPath compiled operation
9894 *
9895 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009896 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009897 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009898static int
9899xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9900{
9901 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009902 int equal, ret;
9903 xmlXPathCompExprPtr comp;
9904 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009905 xmlNodePtr bak;
9906 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009907 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009908 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009909
Daniel Veillard556c6682001-10-06 09:59:51 +00009910 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009911 comp = ctxt->comp;
9912 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009913 case XPATH_OP_END:
9914 return (0);
9915 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009916 bakd = ctxt->context->doc;
9917 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009918 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009919 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009920 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009921 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 xmlXPathBooleanFunction(ctxt, 1);
9923 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9924 return (total);
9925 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009926 ctxt->context->doc = bakd;
9927 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009928 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009929 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009930 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009931 if (ctxt->error) {
9932 xmlXPathFreeObject(arg2);
9933 return(0);
9934 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009935 xmlXPathBooleanFunction(ctxt, 1);
9936 arg1 = valuePop(ctxt);
9937 arg1->boolval &= arg2->boolval;
9938 valuePush(ctxt, arg1);
9939 xmlXPathFreeObject(arg2);
9940 return (total);
9941 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009942 bakd = ctxt->context->doc;
9943 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009944 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009945 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009946 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009947 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 xmlXPathBooleanFunction(ctxt, 1);
9949 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9950 return (total);
9951 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009952 ctxt->context->doc = bakd;
9953 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009954 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009955 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009956 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009957 if (ctxt->error) {
9958 xmlXPathFreeObject(arg2);
9959 return(0);
9960 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009961 xmlXPathBooleanFunction(ctxt, 1);
9962 arg1 = valuePop(ctxt);
9963 arg1->boolval |= arg2->boolval;
9964 valuePush(ctxt, arg1);
9965 xmlXPathFreeObject(arg2);
9966 return (total);
9967 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009968 bakd = ctxt->context->doc;
9969 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009970 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009971 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009972 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009973 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009974 ctxt->context->doc = bakd;
9975 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009976 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009977 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009978 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009979 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009980 if (op->value)
9981 equal = xmlXPathEqualValues(ctxt);
9982 else
9983 equal = xmlXPathNotEqualValues(ctxt);
9984 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009985 return (total);
9986 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009987 bakd = ctxt->context->doc;
9988 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009989 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009990 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009991 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009992 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009993 ctxt->context->doc = bakd;
9994 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009995 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009996 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009997 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009998 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009999 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10000 valuePush(ctxt, xmlXPathNewBoolean(ret));
10001 return (total);
10002 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010003 bakd = ctxt->context->doc;
10004 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010005 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010006 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010007 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010008 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010009 if (op->ch2 != -1) {
10010 ctxt->context->doc = bakd;
10011 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010012 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010013 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010014 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010015 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010016 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010017 if (op->value == 0)
10018 xmlXPathSubValues(ctxt);
10019 else if (op->value == 1)
10020 xmlXPathAddValues(ctxt);
10021 else if (op->value == 2)
10022 xmlXPathValueFlipSign(ctxt);
10023 else if (op->value == 3) {
10024 CAST_TO_NUMBER;
10025 CHECK_TYPE0(XPATH_NUMBER);
10026 }
10027 return (total);
10028 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010029 bakd = ctxt->context->doc;
10030 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010031 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010032 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010033 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010034 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010035 ctxt->context->doc = bakd;
10036 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010037 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010038 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010039 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010040 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010041 if (op->value == 0)
10042 xmlXPathMultValues(ctxt);
10043 else if (op->value == 1)
10044 xmlXPathDivValues(ctxt);
10045 else if (op->value == 2)
10046 xmlXPathModValues(ctxt);
10047 return (total);
10048 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010049 bakd = ctxt->context->doc;
10050 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010051 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010052 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010053 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010054 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010055 ctxt->context->doc = bakd;
10056 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010057 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010058 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010060 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061 CHECK_TYPE0(XPATH_NODESET);
10062 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010063
Daniel Veillardf06307e2001-07-03 10:35:50 +000010064 CHECK_TYPE0(XPATH_NODESET);
10065 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010066
Daniel Veillardf06307e2001-07-03 10:35:50 +000010067 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10068 arg2->nodesetval);
10069 valuePush(ctxt, arg1);
10070 xmlXPathFreeObject(arg2);
10071 return (total);
10072 case XPATH_OP_ROOT:
10073 xmlXPathRoot(ctxt);
10074 return (total);
10075 case XPATH_OP_NODE:
10076 if (op->ch1 != -1)
10077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010078 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079 if (op->ch2 != -1)
10080 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010081 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010082 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10083 return (total);
10084 case XPATH_OP_RESET:
10085 if (op->ch1 != -1)
10086 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010087 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010088 if (op->ch2 != -1)
10089 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010090 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010091 ctxt->context->node = NULL;
10092 return (total);
10093 case XPATH_OP_COLLECT:{
10094 if (op->ch1 == -1)
10095 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010096
Daniel Veillardf06307e2001-07-03 10:35:50 +000010097 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010098 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010099
Daniel Veillardf06307e2001-07-03 10:35:50 +000010100 /*
10101 * Optimization for [n] selection where n is a number
10102 */
10103 if ((op->ch2 != -1) &&
10104 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10105 (comp->steps[op->ch2].ch1 == -1) &&
10106 (comp->steps[op->ch2].ch2 != -1) &&
10107 (comp->steps[comp->steps[op->ch2].ch2].op ==
10108 XPATH_OP_VALUE)) {
10109 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010110
Daniel Veillardf06307e2001-07-03 10:35:50 +000010111 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10112 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10113 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010114
Daniel Veillardf06307e2001-07-03 10:35:50 +000010115 if (val->floatval == (float) indx) {
10116 total +=
10117 xmlXPathNodeCollectAndTestNth(ctxt, op,
10118 indx, NULL,
10119 NULL);
10120 return (total);
10121 }
10122 }
10123 }
10124 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10125 return (total);
10126 }
10127 case XPATH_OP_VALUE:
10128 valuePush(ctxt,
10129 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10130 return (total);
10131 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010132 xmlXPathObjectPtr val;
10133
Daniel Veillardf06307e2001-07-03 10:35:50 +000010134 if (op->ch1 != -1)
10135 total +=
10136 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010137 if (op->value5 == NULL) {
10138 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10139 if (val == NULL) {
10140 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10141 return(0);
10142 }
10143 valuePush(ctxt, val);
10144 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010145 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010146
Daniel Veillardf06307e2001-07-03 10:35:50 +000010147 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10148 if (URI == NULL) {
10149 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010150 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010151 op->value4, op->value5);
10152 return (total);
10153 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010154 val = xmlXPathVariableLookupNS(ctxt->context,
10155 op->value4, URI);
10156 if (val == NULL) {
10157 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10158 return(0);
10159 }
10160 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010161 }
10162 return (total);
10163 }
10164 case XPATH_OP_FUNCTION:{
10165 xmlXPathFunction func;
10166 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010167 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010168
10169 if (op->ch1 != -1)
10170 total +=
10171 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010172 if (ctxt->valueNr < op->value) {
10173 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010174 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010175 ctxt->error = XPATH_INVALID_OPERAND;
10176 return (total);
10177 }
10178 for (i = 0; i < op->value; i++)
10179 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10180 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010181 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010182 ctxt->error = XPATH_INVALID_OPERAND;
10183 return (total);
10184 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010185 if (op->cache != NULL)
10186 func = (xmlXPathFunction) op->cache;
10187 else {
10188 const xmlChar *URI = NULL;
10189
10190 if (op->value5 == NULL)
10191 func =
10192 xmlXPathFunctionLookup(ctxt->context,
10193 op->value4);
10194 else {
10195 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10196 if (URI == NULL) {
10197 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010198 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010199 op->value4, op->value5);
10200 return (total);
10201 }
10202 func = xmlXPathFunctionLookupNS(ctxt->context,
10203 op->value4, URI);
10204 }
10205 if (func == NULL) {
10206 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010207 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010208 op->value4);
10209 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010210 }
10211 op->cache = (void *) func;
10212 op->cacheURI = (void *) URI;
10213 }
10214 oldFunc = ctxt->context->function;
10215 oldFuncURI = ctxt->context->functionURI;
10216 ctxt->context->function = op->value4;
10217 ctxt->context->functionURI = op->cacheURI;
10218 func(ctxt, op->value);
10219 ctxt->context->function = oldFunc;
10220 ctxt->context->functionURI = oldFuncURI;
10221 return (total);
10222 }
10223 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010224 bakd = ctxt->context->doc;
10225 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010226 if (op->ch1 != -1)
10227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010228 ctxt->context->doc = bakd;
10229 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010230 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010231 if (op->ch2 != -1)
10232 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010233 ctxt->context->doc = bakd;
10234 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010235 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010236 return (total);
10237 case XPATH_OP_PREDICATE:
10238 case XPATH_OP_FILTER:{
10239 xmlXPathObjectPtr res;
10240 xmlXPathObjectPtr obj, tmp;
10241 xmlNodeSetPtr newset = NULL;
10242 xmlNodeSetPtr oldset;
10243 xmlNodePtr oldnode;
10244 int i;
10245
10246 /*
10247 * Optimization for ()[1] selection i.e. the first elem
10248 */
10249 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10250 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10251 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10252 xmlXPathObjectPtr val;
10253
10254 val = comp->steps[op->ch2].value4;
10255 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10256 (val->floatval == 1.0)) {
10257 xmlNodePtr first = NULL;
10258
10259 total +=
10260 xmlXPathCompOpEvalFirst(ctxt,
10261 &comp->steps[op->ch1],
10262 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010263 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010264 /*
10265 * The nodeset should be in document order,
10266 * Keep only the first value
10267 */
10268 if ((ctxt->value != NULL) &&
10269 (ctxt->value->type == XPATH_NODESET) &&
10270 (ctxt->value->nodesetval != NULL) &&
10271 (ctxt->value->nodesetval->nodeNr > 1))
10272 ctxt->value->nodesetval->nodeNr = 1;
10273 return (total);
10274 }
10275 }
10276 /*
10277 * Optimization for ()[last()] selection i.e. the last elem
10278 */
10279 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10280 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10281 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10282 int f = comp->steps[op->ch2].ch1;
10283
10284 if ((f != -1) &&
10285 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10286 (comp->steps[f].value5 == NULL) &&
10287 (comp->steps[f].value == 0) &&
10288 (comp->steps[f].value4 != NULL) &&
10289 (xmlStrEqual
10290 (comp->steps[f].value4, BAD_CAST "last"))) {
10291 xmlNodePtr last = NULL;
10292
10293 total +=
10294 xmlXPathCompOpEvalLast(ctxt,
10295 &comp->steps[op->ch1],
10296 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010297 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010298 /*
10299 * The nodeset should be in document order,
10300 * Keep only the last value
10301 */
10302 if ((ctxt->value != NULL) &&
10303 (ctxt->value->type == XPATH_NODESET) &&
10304 (ctxt->value->nodesetval != NULL) &&
10305 (ctxt->value->nodesetval->nodeTab != NULL) &&
10306 (ctxt->value->nodesetval->nodeNr > 1)) {
10307 ctxt->value->nodesetval->nodeTab[0] =
10308 ctxt->value->nodesetval->nodeTab[ctxt->
10309 value->
10310 nodesetval->
10311 nodeNr -
10312 1];
10313 ctxt->value->nodesetval->nodeNr = 1;
10314 }
10315 return (total);
10316 }
10317 }
10318
10319 if (op->ch1 != -1)
10320 total +=
10321 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010322 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010323 if (op->ch2 == -1)
10324 return (total);
10325 if (ctxt->value == NULL)
10326 return (total);
10327
10328 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010329
10330#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010331 /*
10332 * Hum are we filtering the result of an XPointer expression
10333 */
10334 if (ctxt->value->type == XPATH_LOCATIONSET) {
10335 xmlLocationSetPtr newlocset = NULL;
10336 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010337
Daniel Veillardf06307e2001-07-03 10:35:50 +000010338 /*
10339 * Extract the old locset, and then evaluate the result of the
10340 * expression for all the element in the locset. use it to grow
10341 * up a new locset.
10342 */
10343 CHECK_TYPE0(XPATH_LOCATIONSET);
10344 obj = valuePop(ctxt);
10345 oldlocset = obj->user;
10346 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010347
Daniel Veillardf06307e2001-07-03 10:35:50 +000010348 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10349 ctxt->context->contextSize = 0;
10350 ctxt->context->proximityPosition = 0;
10351 if (op->ch2 != -1)
10352 total +=
10353 xmlXPathCompOpEval(ctxt,
10354 &comp->steps[op->ch2]);
10355 res = valuePop(ctxt);
10356 if (res != NULL)
10357 xmlXPathFreeObject(res);
10358 valuePush(ctxt, obj);
10359 CHECK_ERROR0;
10360 return (total);
10361 }
10362 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010363
Daniel Veillardf06307e2001-07-03 10:35:50 +000010364 for (i = 0; i < oldlocset->locNr; i++) {
10365 /*
10366 * Run the evaluation with a node list made of a
10367 * single item in the nodelocset.
10368 */
10369 ctxt->context->node = oldlocset->locTab[i]->user;
10370 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10371 valuePush(ctxt, tmp);
10372 ctxt->context->contextSize = oldlocset->locNr;
10373 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010374
Daniel Veillardf06307e2001-07-03 10:35:50 +000010375 if (op->ch2 != -1)
10376 total +=
10377 xmlXPathCompOpEval(ctxt,
10378 &comp->steps[op->ch2]);
10379 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010380
Daniel Veillardf06307e2001-07-03 10:35:50 +000010381 /*
10382 * The result of the evaluation need to be tested to
10383 * decided whether the filter succeeded or not
10384 */
10385 res = valuePop(ctxt);
10386 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10387 xmlXPtrLocationSetAdd(newlocset,
10388 xmlXPathObjectCopy
10389 (oldlocset->locTab[i]));
10390 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010391
Daniel Veillardf06307e2001-07-03 10:35:50 +000010392 /*
10393 * Cleanup
10394 */
10395 if (res != NULL)
10396 xmlXPathFreeObject(res);
10397 if (ctxt->value == tmp) {
10398 res = valuePop(ctxt);
10399 xmlXPathFreeObject(res);
10400 }
10401
10402 ctxt->context->node = NULL;
10403 }
10404
10405 /*
10406 * The result is used as the new evaluation locset.
10407 */
10408 xmlXPathFreeObject(obj);
10409 ctxt->context->node = NULL;
10410 ctxt->context->contextSize = -1;
10411 ctxt->context->proximityPosition = -1;
10412 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10413 ctxt->context->node = oldnode;
10414 return (total);
10415 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010416#endif /* LIBXML_XPTR_ENABLED */
10417
Daniel Veillardf06307e2001-07-03 10:35:50 +000010418 /*
10419 * Extract the old set, and then evaluate the result of the
10420 * expression for all the element in the set. use it to grow
10421 * up a new set.
10422 */
10423 CHECK_TYPE0(XPATH_NODESET);
10424 obj = valuePop(ctxt);
10425 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010426
Daniel Veillardf06307e2001-07-03 10:35:50 +000010427 oldnode = ctxt->context->node;
10428 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010429
Daniel Veillardf06307e2001-07-03 10:35:50 +000010430 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10431 ctxt->context->contextSize = 0;
10432 ctxt->context->proximityPosition = 0;
10433 if (op->ch2 != -1)
10434 total +=
10435 xmlXPathCompOpEval(ctxt,
10436 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010437 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010438 res = valuePop(ctxt);
10439 if (res != NULL)
10440 xmlXPathFreeObject(res);
10441 valuePush(ctxt, obj);
10442 ctxt->context->node = oldnode;
10443 CHECK_ERROR0;
10444 } else {
10445 /*
10446 * Initialize the new set.
10447 */
10448 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010449
Daniel Veillardf06307e2001-07-03 10:35:50 +000010450 for (i = 0; i < oldset->nodeNr; i++) {
10451 /*
10452 * Run the evaluation with a node list made of
10453 * a single item in the nodeset.
10454 */
10455 ctxt->context->node = oldset->nodeTab[i];
10456 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10457 valuePush(ctxt, tmp);
10458 ctxt->context->contextSize = oldset->nodeNr;
10459 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010460
Daniel Veillardf06307e2001-07-03 10:35:50 +000010461 if (op->ch2 != -1)
10462 total +=
10463 xmlXPathCompOpEval(ctxt,
10464 &comp->steps[op->ch2]);
10465 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010466
Daniel Veillardf06307e2001-07-03 10:35:50 +000010467 /*
10468 * The result of the evaluation need to be tested to
10469 * decided whether the filter succeeded or not
10470 */
10471 res = valuePop(ctxt);
10472 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10473 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10474 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010475
Daniel Veillardf06307e2001-07-03 10:35:50 +000010476 /*
10477 * Cleanup
10478 */
10479 if (res != NULL)
10480 xmlXPathFreeObject(res);
10481 if (ctxt->value == tmp) {
10482 res = valuePop(ctxt);
10483 xmlXPathFreeObject(res);
10484 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010485
Daniel Veillardf06307e2001-07-03 10:35:50 +000010486 ctxt->context->node = NULL;
10487 }
10488
10489 /*
10490 * The result is used as the new evaluation set.
10491 */
10492 xmlXPathFreeObject(obj);
10493 ctxt->context->node = NULL;
10494 ctxt->context->contextSize = -1;
10495 ctxt->context->proximityPosition = -1;
10496 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10497 }
10498 ctxt->context->node = oldnode;
10499 return (total);
10500 }
10501 case XPATH_OP_SORT:
10502 if (op->ch1 != -1)
10503 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010504 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010505 if ((ctxt->value != NULL) &&
10506 (ctxt->value->type == XPATH_NODESET) &&
10507 (ctxt->value->nodesetval != NULL))
10508 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10509 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010510#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010511 case XPATH_OP_RANGETO:{
10512 xmlXPathObjectPtr range;
10513 xmlXPathObjectPtr res, obj;
10514 xmlXPathObjectPtr tmp;
10515 xmlLocationSetPtr newset = NULL;
10516 xmlNodeSetPtr oldset;
10517 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010518
Daniel Veillardf06307e2001-07-03 10:35:50 +000010519 if (op->ch1 != -1)
10520 total +=
10521 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10522 if (op->ch2 == -1)
10523 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010524
Daniel Veillardf06307e2001-07-03 10:35:50 +000010525 CHECK_TYPE0(XPATH_NODESET);
10526 obj = valuePop(ctxt);
10527 oldset = obj->nodesetval;
10528 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010529
Daniel Veillardf06307e2001-07-03 10:35:50 +000010530 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010531
Daniel Veillardf06307e2001-07-03 10:35:50 +000010532 if (oldset != NULL) {
10533 for (i = 0; i < oldset->nodeNr; i++) {
10534 /*
10535 * Run the evaluation with a node list made of a single item
10536 * in the nodeset.
10537 */
10538 ctxt->context->node = oldset->nodeTab[i];
10539 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10540 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010541
Daniel Veillardf06307e2001-07-03 10:35:50 +000010542 if (op->ch2 != -1)
10543 total +=
10544 xmlXPathCompOpEval(ctxt,
10545 &comp->steps[op->ch2]);
10546 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010547
Daniel Veillardf06307e2001-07-03 10:35:50 +000010548 /*
10549 * The result of the evaluation need to be tested to
10550 * decided whether the filter succeeded or not
10551 */
10552 res = valuePop(ctxt);
10553 range =
10554 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10555 res);
10556 if (range != NULL) {
10557 xmlXPtrLocationSetAdd(newset, range);
10558 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010559
Daniel Veillardf06307e2001-07-03 10:35:50 +000010560 /*
10561 * Cleanup
10562 */
10563 if (res != NULL)
10564 xmlXPathFreeObject(res);
10565 if (ctxt->value == tmp) {
10566 res = valuePop(ctxt);
10567 xmlXPathFreeObject(res);
10568 }
10569
10570 ctxt->context->node = NULL;
10571 }
10572 }
10573
10574 /*
10575 * The result is used as the new evaluation set.
10576 */
10577 xmlXPathFreeObject(obj);
10578 ctxt->context->node = NULL;
10579 ctxt->context->contextSize = -1;
10580 ctxt->context->proximityPosition = -1;
10581 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10582 return (total);
10583 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010584#endif /* LIBXML_XPTR_ENABLED */
10585 }
10586 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010587 "XPath: unknown precompiled operation %d\n", op->op);
10588 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010589}
10590
10591/**
10592 * xmlXPathRunEval:
10593 * @ctxt: the XPath parser context with the compiled expression
10594 *
10595 * Evaluate the Precompiled XPath expression in the given context.
10596 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010597static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010598xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10599 xmlXPathCompExprPtr comp;
10600
10601 if ((ctxt == NULL) || (ctxt->comp == NULL))
10602 return;
10603
10604 if (ctxt->valueTab == NULL) {
10605 /* Allocate the value stack */
10606 ctxt->valueTab = (xmlXPathObjectPtr *)
10607 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10608 if (ctxt->valueTab == NULL) {
10609 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010610 }
10611 ctxt->valueNr = 0;
10612 ctxt->valueMax = 10;
10613 ctxt->value = NULL;
10614 }
10615 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010616 if(comp->last < 0) {
10617 xmlGenericError(xmlGenericErrorContext,
10618 "xmlXPathRunEval: last is less than zero\n");
10619 return;
10620 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010621 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10622}
10623
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010624/************************************************************************
10625 * *
10626 * Public interfaces *
10627 * *
10628 ************************************************************************/
10629
10630/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010631 * xmlXPathEvalPredicate:
10632 * @ctxt: the XPath context
10633 * @res: the Predicate Expression evaluation result
10634 *
10635 * Evaluate a predicate result for the current node.
10636 * A PredicateExpr is evaluated by evaluating the Expr and converting
10637 * the result to a boolean. If the result is a number, the result will
10638 * be converted to true if the number is equal to the position of the
10639 * context node in the context node list (as returned by the position
10640 * function) and will be converted to false otherwise; if the result
10641 * is not a number, then the result will be converted as if by a call
10642 * to the boolean function.
10643 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010644 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010645 */
10646int
10647xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10648 if (res == NULL) return(0);
10649 switch (res->type) {
10650 case XPATH_BOOLEAN:
10651 return(res->boolval);
10652 case XPATH_NUMBER:
10653 return(res->floatval == ctxt->proximityPosition);
10654 case XPATH_NODESET:
10655 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010656 if (res->nodesetval == NULL)
10657 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010658 return(res->nodesetval->nodeNr != 0);
10659 case XPATH_STRING:
10660 return((res->stringval != NULL) &&
10661 (xmlStrlen(res->stringval) != 0));
10662 default:
10663 STRANGE
10664 }
10665 return(0);
10666}
10667
10668/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010669 * xmlXPathEvaluatePredicateResult:
10670 * @ctxt: the XPath Parser context
10671 * @res: the Predicate Expression evaluation result
10672 *
10673 * Evaluate a predicate result for the current node.
10674 * A PredicateExpr is evaluated by evaluating the Expr and converting
10675 * the result to a boolean. If the result is a number, the result will
10676 * be converted to true if the number is equal to the position of the
10677 * context node in the context node list (as returned by the position
10678 * function) and will be converted to false otherwise; if the result
10679 * is not a number, then the result will be converted as if by a call
10680 * to the boolean function.
10681 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010682 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010683 */
10684int
10685xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10686 xmlXPathObjectPtr res) {
10687 if (res == NULL) return(0);
10688 switch (res->type) {
10689 case XPATH_BOOLEAN:
10690 return(res->boolval);
10691 case XPATH_NUMBER:
10692 return(res->floatval == ctxt->context->proximityPosition);
10693 case XPATH_NODESET:
10694 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010695 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010696 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010697 return(res->nodesetval->nodeNr != 0);
10698 case XPATH_STRING:
10699 return((res->stringval != NULL) &&
10700 (xmlStrlen(res->stringval) != 0));
10701 default:
10702 STRANGE
10703 }
10704 return(0);
10705}
10706
10707/**
10708 * xmlXPathCompile:
10709 * @str: the XPath expression
10710 *
10711 * Compile an XPath expression
10712 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010713 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010714 * the caller has to free the object.
10715 */
10716xmlXPathCompExprPtr
10717xmlXPathCompile(const xmlChar *str) {
10718 xmlXPathParserContextPtr ctxt;
10719 xmlXPathCompExprPtr comp;
10720
10721 xmlXPathInit();
10722
10723 ctxt = xmlXPathNewParserContext(str, NULL);
10724 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010725
Daniel Veillard40af6492001-04-22 08:50:55 +000010726 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010727 /*
10728 * aleksey: in some cases this line prints *second* error message
10729 * (see bug #78858) and probably this should be fixed.
10730 * However, we are not sure that all error messages are printed
10731 * out in other places. It's not critical so we leave it as-is for now
10732 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010733 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10734 comp = NULL;
10735 } else {
10736 comp = ctxt->comp;
10737 ctxt->comp = NULL;
10738 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010739 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010740 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010741 comp->expr = xmlStrdup(str);
10742#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010743 comp->string = xmlStrdup(str);
10744 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010745#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010746 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010747 return(comp);
10748}
10749
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010750/**
10751 * xmlXPathCompiledEval:
10752 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010753 * @ctx: the XPath context
10754 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010755 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010756 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010757 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010758 * the caller has to free the object.
10759 */
10760xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010761xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010762 xmlXPathParserContextPtr ctxt;
10763 xmlXPathObjectPtr res, tmp, init = NULL;
10764 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010765#ifndef LIBXML_THREAD_ENABLED
10766 static int reentance = 0;
10767#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010768
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010769 if ((comp == NULL) || (ctx == NULL))
10770 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010771 xmlXPathInit();
10772
10773 CHECK_CONTEXT(ctx)
10774
Daniel Veillard81463942001-10-16 12:34:39 +000010775#ifndef LIBXML_THREAD_ENABLED
10776 reentance++;
10777 if (reentance > 1)
10778 xmlXPathDisableOptimizer = 1;
10779#endif
10780
Daniel Veillardf06307e2001-07-03 10:35:50 +000010781#ifdef DEBUG_EVAL_COUNTS
10782 comp->nb++;
10783 if ((comp->string != NULL) && (comp->nb > 100)) {
10784 fprintf(stderr, "100 x %s\n", comp->string);
10785 comp->nb = 0;
10786 }
10787#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010788 ctxt = xmlXPathCompParserContext(comp, ctx);
10789 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010790
10791 if (ctxt->value == NULL) {
10792 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010793 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010794 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010795 } else {
10796 res = valuePop(ctxt);
10797 }
10798
Daniel Veillardf06307e2001-07-03 10:35:50 +000010799
Owen Taylor3473f882001-02-23 17:55:21 +000010800 do {
10801 tmp = valuePop(ctxt);
10802 if (tmp != NULL) {
10803 if (tmp != init)
10804 stack++;
10805 xmlXPathFreeObject(tmp);
10806 }
10807 } while (tmp != NULL);
10808 if ((stack != 0) && (res != NULL)) {
10809 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010810 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010811 stack);
10812 }
10813 if (ctxt->error != XPATH_EXPRESSION_OK) {
10814 xmlXPathFreeObject(res);
10815 res = NULL;
10816 }
10817
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010818
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010819 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010820 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010821#ifndef LIBXML_THREAD_ENABLED
10822 reentance--;
10823#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010824 return(res);
10825}
10826
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010827/**
10828 * xmlXPathEvalExpr:
10829 * @ctxt: the XPath Parser context
10830 *
10831 * Parse and evaluate an XPath expression in the given context,
10832 * then push the result on the context stack
10833 */
10834void
10835xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10836 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010837 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010838 xmlXPathRunEval(ctxt);
10839}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010840
10841/**
10842 * xmlXPathEval:
10843 * @str: the XPath expression
10844 * @ctx: the XPath context
10845 *
10846 * Evaluate the XPath Location Path in the given context.
10847 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010848 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010849 * the caller has to free the object.
10850 */
10851xmlXPathObjectPtr
10852xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10853 xmlXPathParserContextPtr ctxt;
10854 xmlXPathObjectPtr res, tmp, init = NULL;
10855 int stack = 0;
10856
10857 xmlXPathInit();
10858
10859 CHECK_CONTEXT(ctx)
10860
10861 ctxt = xmlXPathNewParserContext(str, ctx);
10862 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010863
10864 if (ctxt->value == NULL) {
10865 xmlGenericError(xmlGenericErrorContext,
10866 "xmlXPathEval: evaluation failed\n");
10867 res = NULL;
10868 } else if (*ctxt->cur != 0) {
10869 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10870 res = NULL;
10871 } else {
10872 res = valuePop(ctxt);
10873 }
10874
10875 do {
10876 tmp = valuePop(ctxt);
10877 if (tmp != NULL) {
10878 if (tmp != init)
10879 stack++;
10880 xmlXPathFreeObject(tmp);
10881 }
10882 } while (tmp != NULL);
10883 if ((stack != 0) && (res != NULL)) {
10884 xmlGenericError(xmlGenericErrorContext,
10885 "xmlXPathEval: %d object left on the stack\n",
10886 stack);
10887 }
10888 if (ctxt->error != XPATH_EXPRESSION_OK) {
10889 xmlXPathFreeObject(res);
10890 res = NULL;
10891 }
10892
Owen Taylor3473f882001-02-23 17:55:21 +000010893 xmlXPathFreeParserContext(ctxt);
10894 return(res);
10895}
10896
10897/**
10898 * xmlXPathEvalExpression:
10899 * @str: the XPath expression
10900 * @ctxt: the XPath context
10901 *
10902 * Evaluate the XPath expression in the given context.
10903 *
10904 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10905 * the caller has to free the object.
10906 */
10907xmlXPathObjectPtr
10908xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10909 xmlXPathParserContextPtr pctxt;
10910 xmlXPathObjectPtr res, tmp;
10911 int stack = 0;
10912
10913 xmlXPathInit();
10914
10915 CHECK_CONTEXT(ctxt)
10916
10917 pctxt = xmlXPathNewParserContext(str, ctxt);
10918 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010919
10920 if (*pctxt->cur != 0) {
10921 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10922 res = NULL;
10923 } else {
10924 res = valuePop(pctxt);
10925 }
10926 do {
10927 tmp = valuePop(pctxt);
10928 if (tmp != NULL) {
10929 xmlXPathFreeObject(tmp);
10930 stack++;
10931 }
10932 } while (tmp != NULL);
10933 if ((stack != 0) && (res != NULL)) {
10934 xmlGenericError(xmlGenericErrorContext,
10935 "xmlXPathEvalExpression: %d object left on the stack\n",
10936 stack);
10937 }
10938 xmlXPathFreeParserContext(pctxt);
10939 return(res);
10940}
10941
Daniel Veillard42766c02002-08-22 20:52:17 +000010942/************************************************************************
10943 * *
10944 * Extra functions not pertaining to the XPath spec *
10945 * *
10946 ************************************************************************/
10947/**
10948 * xmlXPathEscapeUriFunction:
10949 * @ctxt: the XPath Parser context
10950 * @nargs: the number of arguments
10951 *
10952 * Implement the escape-uri() XPath function
10953 * string escape-uri(string $str, bool $escape-reserved)
10954 *
10955 * This function applies the URI escaping rules defined in section 2 of [RFC
10956 * 2396] to the string supplied as $uri-part, which typically represents all
10957 * or part of a URI. The effect of the function is to replace any special
10958 * character in the string by an escape sequence of the form %xx%yy...,
10959 * where xxyy... is the hexadecimal representation of the octets used to
10960 * represent the character in UTF-8.
10961 *
10962 * The set of characters that are escaped depends on the setting of the
10963 * boolean argument $escape-reserved.
10964 *
10965 * If $escape-reserved is true, all characters are escaped other than lower
10966 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10967 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10968 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10969 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10970 * A-F).
10971 *
10972 * If $escape-reserved is false, the behavior differs in that characters
10973 * referred to in [RFC 2396] as reserved characters are not escaped. These
10974 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10975 *
10976 * [RFC 2396] does not define whether escaped URIs should use lower case or
10977 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10978 * compared using string comparison functions, this function must always use
10979 * the upper-case letters A-F.
10980 *
10981 * Generally, $escape-reserved should be set to true when escaping a string
10982 * that is to form a single part of a URI, and to false when escaping an
10983 * entire URI or URI reference.
10984 *
10985 * In the case of non-ascii characters, the string is encoded according to
10986 * utf-8 and then converted according to RFC 2396.
10987 *
10988 * Examples
10989 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10990 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10991 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10992 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10993 *
10994 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010995static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010996xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10997 xmlXPathObjectPtr str;
10998 int escape_reserved;
10999 xmlBufferPtr target;
11000 xmlChar *cptr;
11001 xmlChar escape[4];
11002
11003 CHECK_ARITY(2);
11004
11005 escape_reserved = xmlXPathPopBoolean(ctxt);
11006
11007 CAST_TO_STRING;
11008 str = valuePop(ctxt);
11009
11010 target = xmlBufferCreate();
11011
11012 escape[0] = '%';
11013 escape[3] = 0;
11014
11015 if (target) {
11016 for (cptr = str->stringval; *cptr; cptr++) {
11017 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11018 (*cptr >= 'a' && *cptr <= 'z') ||
11019 (*cptr >= '0' && *cptr <= '9') ||
11020 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11021 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11022 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11023 (*cptr == '%' &&
11024 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11025 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11026 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11027 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11028 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11029 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11030 (!escape_reserved &&
11031 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11032 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11033 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11034 *cptr == ','))) {
11035 xmlBufferAdd(target, cptr, 1);
11036 } else {
11037 if ((*cptr >> 4) < 10)
11038 escape[1] = '0' + (*cptr >> 4);
11039 else
11040 escape[1] = 'A' - 10 + (*cptr >> 4);
11041 if ((*cptr & 0xF) < 10)
11042 escape[2] = '0' + (*cptr & 0xF);
11043 else
11044 escape[2] = 'A' - 10 + (*cptr & 0xF);
11045
11046 xmlBufferAdd(target, &escape[0], 3);
11047 }
11048 }
11049 }
11050 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11051 xmlBufferFree(target);
11052 xmlXPathFreeObject(str);
11053}
11054
Owen Taylor3473f882001-02-23 17:55:21 +000011055/**
11056 * xmlXPathRegisterAllFunctions:
11057 * @ctxt: the XPath context
11058 *
11059 * Registers all default XPath functions in this context
11060 */
11061void
11062xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11063{
11064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11065 xmlXPathBooleanFunction);
11066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11067 xmlXPathCeilingFunction);
11068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11069 xmlXPathCountFunction);
11070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11071 xmlXPathConcatFunction);
11072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11073 xmlXPathContainsFunction);
11074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11075 xmlXPathIdFunction);
11076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11077 xmlXPathFalseFunction);
11078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11079 xmlXPathFloorFunction);
11080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11081 xmlXPathLastFunction);
11082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11083 xmlXPathLangFunction);
11084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11085 xmlXPathLocalNameFunction);
11086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11087 xmlXPathNotFunction);
11088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11089 xmlXPathNameFunction);
11090 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11091 xmlXPathNamespaceURIFunction);
11092 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11093 xmlXPathNormalizeFunction);
11094 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11095 xmlXPathNumberFunction);
11096 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11097 xmlXPathPositionFunction);
11098 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11099 xmlXPathRoundFunction);
11100 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11101 xmlXPathStringFunction);
11102 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11103 xmlXPathStringLengthFunction);
11104 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11105 xmlXPathStartsWithFunction);
11106 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11107 xmlXPathSubstringFunction);
11108 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11109 xmlXPathSubstringBeforeFunction);
11110 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11111 xmlXPathSubstringAfterFunction);
11112 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11113 xmlXPathSumFunction);
11114 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11115 xmlXPathTrueFunction);
11116 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11117 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011118
11119 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11120 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11121 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011122}
11123
11124#endif /* LIBXML_XPATH_ENABLED */