blob: b63f8b7f349e850e7beee1a00f43663fbbd746a1 [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 *
11 * See COPYRIGHT for the status of this software
12 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Bjorn Reese70a9da52001-04-21 16:57:29 +000019#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000020#ifdef LIBXML_XPATH_ENABLED
21
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <string.h>
23
24#ifdef HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27#ifdef HAVE_MATH_H
28#include <math.h>
29#endif
30#ifdef HAVE_FLOAT_H
31#include <float.h>
32#endif
Owen Taylor3473f882001-02-23 17:55:21 +000033#ifdef HAVE_CTYPE_H
34#include <ctype.h>
35#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000036#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000037#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#endif
Owen Taylor3473f882001-02-23 17:55:21 +000039
40#include <libxml/xmlmemory.h>
41#include <libxml/tree.h>
42#include <libxml/valid.h>
43#include <libxml/xpath.h>
44#include <libxml/xpathInternals.h>
45#include <libxml/parserInternals.h>
46#include <libxml/hash.h>
47#ifdef LIBXML_XPTR_ENABLED
48#include <libxml/xpointer.h>
49#endif
50#ifdef LIBXML_DEBUG_ENABLED
51#include <libxml/debugXML.h>
52#endif
53#include <libxml/xmlerror.h>
54
55/* #define DEBUG */
56/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000057/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000058/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000059/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000060
61void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
62double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillard5792e162001-04-30 17:44:45 +000063double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000064
Daniel Veillard20ee8c02001-10-05 09:18:14 +000065static xmlNs xmlXPathXMLNamespaceStruct = {
66 NULL,
67 XML_NAMESPACE_DECL,
68 XML_XML_NAMESPACE,
69 BAD_CAST "xml"
70};
71static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
72
Daniel Veillard9e7160d2001-03-18 23:17:47 +000073/************************************************************************
74 * *
75 * Floating point stuff *
76 * *
77 ************************************************************************/
78
Daniel Veillardc0631a62001-09-20 13:56:06 +000079#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000080#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000081#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000082#include "trionan.c"
83
Owen Taylor3473f882001-02-23 17:55:21 +000084/*
Owen Taylor3473f882001-02-23 17:55:21 +000085 * The lack of portability of this section of the libc is annoying !
86 */
87double xmlXPathNAN = 0;
88double xmlXPathPINF = 1;
89double xmlXPathNINF = -1;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000090static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000091
Owen Taylor3473f882001-02-23 17:55:21 +000092/**
93 * xmlXPathInit:
94 *
95 * Initialize the XPath environment
96 */
97void
98xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000099 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000100
Bjorn Reese45029602001-08-21 09:23:53 +0000101 xmlXPathPINF = trio_pinf();
102 xmlXPathNINF = trio_ninf();
103 xmlXPathNAN = trio_nan();
Owen Taylor3473f882001-02-23 17:55:21 +0000104
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000105 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000106}
107
Daniel Veillardcda96922001-08-21 10:56:31 +0000108/**
109 * xmlXPathIsNaN:
110 * @val: a double value
111 *
112 * Provides a portable isnan() function to detect whether a double
113 * is a NotaNumber. Based on trio code
114 * http://sourceforge.net/projects/ctrio/
115 *
116 * Returns 1 if the value is a NaN, 0 otherwise
117 */
118int
119xmlXPathIsNaN(double val) {
120 return(trio_isnan(val));
121}
122
123/**
124 * xmlXPathIsInf:
125 * @val: a double value
126 *
127 * Provides a portable isinf() function to detect whether a double
128 * is a +Infinite or -Infinite. Based on trio code
129 * http://sourceforge.net/projects/ctrio/
130 *
131 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
132 */
133int
134xmlXPathIsInf(double val) {
135 return(trio_isinf(val));
136}
137
Owen Taylor3473f882001-02-23 17:55:21 +0000138/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000139 * *
140 * Parser Types *
141 * *
142 ************************************************************************/
143
144/*
145 * Types are private:
146 */
147
148typedef enum {
149 XPATH_OP_END=0,
150 XPATH_OP_AND,
151 XPATH_OP_OR,
152 XPATH_OP_EQUAL,
153 XPATH_OP_CMP,
154 XPATH_OP_PLUS,
155 XPATH_OP_MULT,
156 XPATH_OP_UNION,
157 XPATH_OP_ROOT,
158 XPATH_OP_NODE,
159 XPATH_OP_RESET,
160 XPATH_OP_COLLECT,
161 XPATH_OP_VALUE,
162 XPATH_OP_VARIABLE,
163 XPATH_OP_FUNCTION,
164 XPATH_OP_ARG,
165 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000166 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000167 XPATH_OP_SORT
168#ifdef LIBXML_XPTR_ENABLED
169 ,XPATH_OP_RANGETO
170#endif
171} xmlXPathOp;
172
173typedef enum {
174 AXIS_ANCESTOR = 1,
175 AXIS_ANCESTOR_OR_SELF,
176 AXIS_ATTRIBUTE,
177 AXIS_CHILD,
178 AXIS_DESCENDANT,
179 AXIS_DESCENDANT_OR_SELF,
180 AXIS_FOLLOWING,
181 AXIS_FOLLOWING_SIBLING,
182 AXIS_NAMESPACE,
183 AXIS_PARENT,
184 AXIS_PRECEDING,
185 AXIS_PRECEDING_SIBLING,
186 AXIS_SELF
187} xmlXPathAxisVal;
188
189typedef enum {
190 NODE_TEST_NONE = 0,
191 NODE_TEST_TYPE = 1,
192 NODE_TEST_PI = 2,
193 NODE_TEST_ALL = 3,
194 NODE_TEST_NS = 4,
195 NODE_TEST_NAME = 5
196} xmlXPathTestVal;
197
198typedef enum {
199 NODE_TYPE_NODE = 0,
200 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
201 NODE_TYPE_TEXT = XML_TEXT_NODE,
202 NODE_TYPE_PI = XML_PI_NODE
203} xmlXPathTypeVal;
204
205
206typedef struct _xmlXPathStepOp xmlXPathStepOp;
207typedef xmlXPathStepOp *xmlXPathStepOpPtr;
208struct _xmlXPathStepOp {
209 xmlXPathOp op;
210 int ch1;
211 int ch2;
212 int value;
213 int value2;
214 int value3;
215 void *value4;
216 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000217 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000218 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000219};
220
221struct _xmlXPathCompExpr {
222 int nbStep;
223 int maxStep;
224 xmlXPathStepOp *steps; /* ops for computation */
225 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000226#ifdef DEBUG_EVAL_COUNTS
227 int nb;
228 xmlChar *string;
229#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000230};
231
232/************************************************************************
233 * *
234 * Parser Type functions *
235 * *
236 ************************************************************************/
237
238/**
239 * xmlXPathNewCompExpr:
240 *
241 * Create a new Xpath component
242 *
243 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
244 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000245static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000246xmlXPathNewCompExpr(void) {
247 xmlXPathCompExprPtr cur;
248
249 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
250 if (cur == NULL) {
251 xmlGenericError(xmlGenericErrorContext,
252 "xmlXPathNewCompExpr : malloc failed\n");
253 return(NULL);
254 }
255 memset(cur, 0, sizeof(xmlXPathCompExpr));
256 cur->maxStep = 10;
257 cur->nbStep = 0;
258 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
259 sizeof(xmlXPathStepOp));
260 if (cur->steps == NULL) {
261 xmlGenericError(xmlGenericErrorContext,
262 "xmlXPathNewCompExpr : malloc failed\n");
263 xmlFree(cur);
264 return(NULL);
265 }
266 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
267 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000268#ifdef DEBUG_EVAL_COUNTS
269 cur->nb = 0;
270#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000271 return(cur);
272}
273
274/**
275 * xmlXPathFreeCompExpr:
276 * @comp: an XPATH comp
277 *
278 * Free up the memory allocated by @comp
279 */
280void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000281xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
282{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000283 xmlXPathStepOpPtr op;
284 int i;
285
286 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000287 return;
288 for (i = 0; i < comp->nbStep; i++) {
289 op = &comp->steps[i];
290 if (op->value4 != NULL) {
291 if (op->op == XPATH_OP_VALUE)
292 xmlXPathFreeObject(op->value4);
293 else
294 xmlFree(op->value4);
295 }
296 if (op->value5 != NULL)
297 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000298 }
299 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000300 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000301 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000302#ifdef DEBUG_EVAL_COUNTS
303 if (comp->string != NULL) {
304 xmlFree(comp->string);
305 }
306#endif
307
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000308 xmlFree(comp);
309}
310
311/**
312 * xmlXPathCompExprAdd:
313 * @comp: the compiled expression
314 * @ch1: first child index
315 * @ch2: second child index
316 * @op: an op
317 * @value: the first int value
318 * @value2: the second int value
319 * @value3: the third int value
320 * @value4: the first string value
321 * @value5: the second string value
322 *
323 * Add an step to an XPath Compiled Expression
324 *
325 * Returns -1 in case of failure, the index otherwise
326 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000327static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000328xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
329 xmlXPathOp op, int value,
330 int value2, int value3, void *value4, void *value5) {
331 if (comp->nbStep >= comp->maxStep) {
332 xmlXPathStepOp *real;
333
334 comp->maxStep *= 2;
335 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
336 comp->maxStep * sizeof(xmlXPathStepOp));
337 if (real == NULL) {
338 comp->maxStep /= 2;
339 xmlGenericError(xmlGenericErrorContext,
340 "xmlXPathCompExprAdd : realloc failed\n");
341 return(-1);
342 }
343 comp->steps = real;
344 }
345 comp->last = comp->nbStep;
346 comp->steps[comp->nbStep].ch1 = ch1;
347 comp->steps[comp->nbStep].ch2 = ch2;
348 comp->steps[comp->nbStep].op = op;
349 comp->steps[comp->nbStep].value = value;
350 comp->steps[comp->nbStep].value2 = value2;
351 comp->steps[comp->nbStep].value3 = value3;
352 comp->steps[comp->nbStep].value4 = value4;
353 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000354 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000355 return(comp->nbStep++);
356}
357
Daniel Veillardf06307e2001-07-03 10:35:50 +0000358/**
359 * xmlXPathCompSwap:
360 * @comp: the compiled expression
361 * @op: operation index
362 *
363 * Swaps 2 operations in the compiled expression
364 * TODO: not thread safe, disable for multi-thread operations
365 *
366 * Returns -1 in case of failure, the index otherwise
367 */
368static void
369xmlXPathCompSwap(xmlXPathStepOpPtr op) {
370 int tmp;
371
372 tmp = op->ch1;
373 op->ch1 = op->ch2;
374 op->ch2 = tmp;
375}
376
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000377#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
378 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
379 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000380#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
381 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
382 (op), (val), (val2), (val3), (val4), (val5))
383
384#define PUSH_LEAVE_EXPR(op, val, val2) \
385xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
386
387#define PUSH_UNARY_EXPR(op, ch, val, val2) \
388xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
389
390#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
391xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
392
393/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000394 * *
395 * Debugging related functions *
396 * *
397 ************************************************************************/
398
399#define TODO \
400 xmlGenericError(xmlGenericErrorContext, \
401 "Unimplemented block at %s:%d\n", \
402 __FILE__, __LINE__);
403
404#define STRANGE \
405 xmlGenericError(xmlGenericErrorContext, \
406 "Internal error at %s:%d\n", \
407 __FILE__, __LINE__);
408
409#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000410static void
411xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000412 int i;
413 char shift[100];
414
415 for (i = 0;((i < depth) && (i < 25));i++)
416 shift[2 * i] = shift[2 * i + 1] = ' ';
417 shift[2 * i] = shift[2 * i + 1] = 0;
418 if (cur == NULL) {
419 fprintf(output, shift);
420 fprintf(output, "Node is NULL !\n");
421 return;
422
423 }
424
425 if ((cur->type == XML_DOCUMENT_NODE) ||
426 (cur->type == XML_HTML_DOCUMENT_NODE)) {
427 fprintf(output, shift);
428 fprintf(output, " /\n");
429 } else if (cur->type == XML_ATTRIBUTE_NODE)
430 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
431 else
432 xmlDebugDumpOneNode(output, cur, depth);
433}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000434static void
435xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000436 xmlNodePtr tmp;
437 int i;
438 char shift[100];
439
440 for (i = 0;((i < depth) && (i < 25));i++)
441 shift[2 * i] = shift[2 * i + 1] = ' ';
442 shift[2 * i] = shift[2 * i + 1] = 0;
443 if (cur == NULL) {
444 fprintf(output, shift);
445 fprintf(output, "Node is NULL !\n");
446 return;
447
448 }
449
450 while (cur != NULL) {
451 tmp = cur;
452 cur = cur->next;
453 xmlDebugDumpOneNode(output, tmp, depth);
454 }
455}
Owen Taylor3473f882001-02-23 17:55:21 +0000456
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000457static void
458xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000459 int i;
460 char shift[100];
461
462 for (i = 0;((i < depth) && (i < 25));i++)
463 shift[2 * i] = shift[2 * i + 1] = ' ';
464 shift[2 * i] = shift[2 * i + 1] = 0;
465
466 if (cur == NULL) {
467 fprintf(output, shift);
468 fprintf(output, "NodeSet is NULL !\n");
469 return;
470
471 }
472
Daniel Veillard911f49a2001-04-07 15:39:35 +0000473 if (cur != NULL) {
474 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
475 for (i = 0;i < cur->nodeNr;i++) {
476 fprintf(output, shift);
477 fprintf(output, "%d", i + 1);
478 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
479 }
Owen Taylor3473f882001-02-23 17:55:21 +0000480 }
481}
482
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000483static void
484xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000485 int i;
486 char shift[100];
487
488 for (i = 0;((i < depth) && (i < 25));i++)
489 shift[2 * i] = shift[2 * i + 1] = ' ';
490 shift[2 * i] = shift[2 * i + 1] = 0;
491
492 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
493 fprintf(output, shift);
494 fprintf(output, "Value Tree is NULL !\n");
495 return;
496
497 }
498
499 fprintf(output, shift);
500 fprintf(output, "%d", i + 1);
501 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
502}
Owen Taylor3473f882001-02-23 17:55:21 +0000503#if defined(LIBXML_XPTR_ENABLED)
504void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000505static void
506xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000507 int i;
508 char shift[100];
509
510 for (i = 0;((i < depth) && (i < 25));i++)
511 shift[2 * i] = shift[2 * i + 1] = ' ';
512 shift[2 * i] = shift[2 * i + 1] = 0;
513
514 if (cur == NULL) {
515 fprintf(output, shift);
516 fprintf(output, "LocationSet is NULL !\n");
517 return;
518
519 }
520
521 for (i = 0;i < cur->locNr;i++) {
522 fprintf(output, shift);
523 fprintf(output, "%d : ", i + 1);
524 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
525 }
526}
Daniel Veillard017b1082001-06-21 11:20:21 +0000527#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000528
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000529/**
530 * xmlXPathDebugDumpObject:
531 * @output: the FILE * to dump the output
532 * @cur: the object to inspect
533 * @depth: indentation level
534 *
535 * Dump the content of the object for debugging purposes
536 */
537void
538xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000539 int i;
540 char shift[100];
541
542 for (i = 0;((i < depth) && (i < 25));i++)
543 shift[2 * i] = shift[2 * i + 1] = ' ';
544 shift[2 * i] = shift[2 * i + 1] = 0;
545
546 fprintf(output, shift);
547
548 if (cur == NULL) {
549 fprintf(output, "Object is empty (NULL)\n");
550 return;
551 }
552 switch(cur->type) {
553 case XPATH_UNDEFINED:
554 fprintf(output, "Object is uninitialized\n");
555 break;
556 case XPATH_NODESET:
557 fprintf(output, "Object is a Node Set :\n");
558 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
559 break;
560 case XPATH_XSLT_TREE:
561 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000562 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000563 break;
564 case XPATH_BOOLEAN:
565 fprintf(output, "Object is a Boolean : ");
566 if (cur->boolval) fprintf(output, "true\n");
567 else fprintf(output, "false\n");
568 break;
569 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000570 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000571 case 1:
572 fprintf(output, "Object is a number : +Infinity\n");
573 break;
574 case -1:
575 fprintf(output, "Object is a number : -Infinity\n");
576 break;
577 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000578 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000579 fprintf(output, "Object is a number : NaN\n");
580 } else {
581 fprintf(output, "Object is a number : %0g\n", cur->floatval);
582 }
583 }
Owen Taylor3473f882001-02-23 17:55:21 +0000584 break;
585 case XPATH_STRING:
586 fprintf(output, "Object is a string : ");
587 xmlDebugDumpString(output, cur->stringval);
588 fprintf(output, "\n");
589 break;
590 case XPATH_POINT:
591 fprintf(output, "Object is a point : index %d in node", cur->index);
592 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
593 fprintf(output, "\n");
594 break;
595 case XPATH_RANGE:
596 if ((cur->user2 == NULL) ||
597 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
598 fprintf(output, "Object is a collapsed range :\n");
599 fprintf(output, shift);
600 if (cur->index >= 0)
601 fprintf(output, "index %d in ", cur->index);
602 fprintf(output, "node\n");
603 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
604 depth + 1);
605 } else {
606 fprintf(output, "Object is a range :\n");
607 fprintf(output, shift);
608 fprintf(output, "From ");
609 if (cur->index >= 0)
610 fprintf(output, "index %d in ", cur->index);
611 fprintf(output, "node\n");
612 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
613 depth + 1);
614 fprintf(output, shift);
615 fprintf(output, "To ");
616 if (cur->index2 >= 0)
617 fprintf(output, "index %d in ", cur->index2);
618 fprintf(output, "node\n");
619 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
620 depth + 1);
621 fprintf(output, "\n");
622 }
623 break;
624 case XPATH_LOCATIONSET:
625#if defined(LIBXML_XPTR_ENABLED)
626 fprintf(output, "Object is a Location Set:\n");
627 xmlXPathDebugDumpLocationSet(output,
628 (xmlLocationSetPtr) cur->user, depth);
629#endif
630 break;
631 case XPATH_USERS:
632 fprintf(output, "Object is user defined\n");
633 break;
634 }
635}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000636
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000637static void
638xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000639 xmlXPathStepOpPtr op, int depth) {
640 int i;
641 char shift[100];
642
643 for (i = 0;((i < depth) && (i < 25));i++)
644 shift[2 * i] = shift[2 * i + 1] = ' ';
645 shift[2 * i] = shift[2 * i + 1] = 0;
646
647 fprintf(output, shift);
648 if (op == NULL) {
649 fprintf(output, "Step is NULL\n");
650 return;
651 }
652 switch (op->op) {
653 case XPATH_OP_END:
654 fprintf(output, "END"); break;
655 case XPATH_OP_AND:
656 fprintf(output, "AND"); break;
657 case XPATH_OP_OR:
658 fprintf(output, "OR"); break;
659 case XPATH_OP_EQUAL:
660 if (op->value)
661 fprintf(output, "EQUAL =");
662 else
663 fprintf(output, "EQUAL !=");
664 break;
665 case XPATH_OP_CMP:
666 if (op->value)
667 fprintf(output, "CMP <");
668 else
669 fprintf(output, "CMP >");
670 if (!op->value2)
671 fprintf(output, "=");
672 break;
673 case XPATH_OP_PLUS:
674 if (op->value == 0)
675 fprintf(output, "PLUS -");
676 else if (op->value == 1)
677 fprintf(output, "PLUS +");
678 else if (op->value == 2)
679 fprintf(output, "PLUS unary -");
680 else if (op->value == 3)
681 fprintf(output, "PLUS unary - -");
682 break;
683 case XPATH_OP_MULT:
684 if (op->value == 0)
685 fprintf(output, "MULT *");
686 else if (op->value == 1)
687 fprintf(output, "MULT div");
688 else
689 fprintf(output, "MULT mod");
690 break;
691 case XPATH_OP_UNION:
692 fprintf(output, "UNION"); break;
693 case XPATH_OP_ROOT:
694 fprintf(output, "ROOT"); break;
695 case XPATH_OP_NODE:
696 fprintf(output, "NODE"); break;
697 case XPATH_OP_RESET:
698 fprintf(output, "RESET"); break;
699 case XPATH_OP_SORT:
700 fprintf(output, "SORT"); break;
701 case XPATH_OP_COLLECT: {
702 xmlXPathAxisVal axis = op->value;
703 xmlXPathTestVal test = op->value2;
704 xmlXPathTypeVal type = op->value3;
705 const xmlChar *prefix = op->value4;
706 const xmlChar *name = op->value5;
707
708 fprintf(output, "COLLECT ");
709 switch (axis) {
710 case AXIS_ANCESTOR:
711 fprintf(output, " 'ancestors' "); break;
712 case AXIS_ANCESTOR_OR_SELF:
713 fprintf(output, " 'ancestors-or-self' "); break;
714 case AXIS_ATTRIBUTE:
715 fprintf(output, " 'attributes' "); break;
716 case AXIS_CHILD:
717 fprintf(output, " 'child' "); break;
718 case AXIS_DESCENDANT:
719 fprintf(output, " 'descendant' "); break;
720 case AXIS_DESCENDANT_OR_SELF:
721 fprintf(output, " 'descendant-or-self' "); break;
722 case AXIS_FOLLOWING:
723 fprintf(output, " 'following' "); break;
724 case AXIS_FOLLOWING_SIBLING:
725 fprintf(output, " 'following-siblings' "); break;
726 case AXIS_NAMESPACE:
727 fprintf(output, " 'namespace' "); break;
728 case AXIS_PARENT:
729 fprintf(output, " 'parent' "); break;
730 case AXIS_PRECEDING:
731 fprintf(output, " 'preceding' "); break;
732 case AXIS_PRECEDING_SIBLING:
733 fprintf(output, " 'preceding-sibling' "); break;
734 case AXIS_SELF:
735 fprintf(output, " 'self' "); break;
736 }
737 switch (test) {
738 case NODE_TEST_NONE:
739 fprintf(output, "'none' "); break;
740 case NODE_TEST_TYPE:
741 fprintf(output, "'type' "); break;
742 case NODE_TEST_PI:
743 fprintf(output, "'PI' "); break;
744 case NODE_TEST_ALL:
745 fprintf(output, "'all' "); break;
746 case NODE_TEST_NS:
747 fprintf(output, "'namespace' "); break;
748 case NODE_TEST_NAME:
749 fprintf(output, "'name' "); break;
750 }
751 switch (type) {
752 case NODE_TYPE_NODE:
753 fprintf(output, "'node' "); break;
754 case NODE_TYPE_COMMENT:
755 fprintf(output, "'comment' "); break;
756 case NODE_TYPE_TEXT:
757 fprintf(output, "'text' "); break;
758 case NODE_TYPE_PI:
759 fprintf(output, "'PI' "); break;
760 }
761 if (prefix != NULL)
762 fprintf(output, "%s:", prefix);
763 if (name != NULL)
764 fprintf(output, "%s", name);
765 break;
766
767 }
768 case XPATH_OP_VALUE: {
769 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
770
771 fprintf(output, "ELEM ");
772 xmlXPathDebugDumpObject(output, object, 0);
773 goto finish;
774 }
775 case XPATH_OP_VARIABLE: {
776 const xmlChar *prefix = op->value5;
777 const xmlChar *name = op->value4;
778
779 if (prefix != NULL)
780 fprintf(output, "VARIABLE %s:%s", prefix, name);
781 else
782 fprintf(output, "VARIABLE %s", name);
783 break;
784 }
785 case XPATH_OP_FUNCTION: {
786 int nbargs = op->value;
787 const xmlChar *prefix = op->value5;
788 const xmlChar *name = op->value4;
789
790 if (prefix != NULL)
791 fprintf(output, "FUNCTION %s:%s(%d args)",
792 prefix, name, nbargs);
793 else
794 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
795 break;
796 }
797 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
798 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000799 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000800#ifdef LIBXML_XPTR_ENABLED
801 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
802#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000803 default:
804 fprintf(output, "UNKNOWN %d\n", op->op); return;
805 }
806 fprintf(output, "\n");
807finish:
808 if (op->ch1 >= 0)
809 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
810 if (op->ch2 >= 0)
811 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
812}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000813
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000814/**
815 * xmlXPathDebugDumpCompExpr:
816 * @output: the FILE * for the output
817 * @comp: the precompiled XPath expression
818 * @depth: the indentation level.
819 *
820 * Dumps the tree of the compiled XPath expression.
821 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000822void
823xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
824 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000825 int i;
826 char shift[100];
827
828 for (i = 0;((i < depth) && (i < 25));i++)
829 shift[2 * i] = shift[2 * i + 1] = ' ';
830 shift[2 * i] = shift[2 * i + 1] = 0;
831
832 fprintf(output, shift);
833
834 if (comp == NULL) {
835 fprintf(output, "Compiled Expression is NULL\n");
836 return;
837 }
838 fprintf(output, "Compiled Expression : %d elements\n",
839 comp->nbStep);
840 i = comp->last;
841 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
842}
Daniel Veillard017b1082001-06-21 11:20:21 +0000843#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000844
845/************************************************************************
846 * *
847 * Parser stacks related functions and macros *
848 * *
849 ************************************************************************/
850
851/*
852 * Generic function for accessing stacks in the Parser Context
853 */
854
855#define PUSH_AND_POP(type, name) \
856extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
857 if (ctxt->name##Nr >= ctxt->name##Max) { \
858 ctxt->name##Max *= 2; \
859 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
860 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
861 if (ctxt->name##Tab == NULL) { \
862 xmlGenericError(xmlGenericErrorContext, \
863 "realloc failed !\n"); \
864 return(0); \
865 } \
866 } \
867 ctxt->name##Tab[ctxt->name##Nr] = value; \
868 ctxt->name = value; \
869 return(ctxt->name##Nr++); \
870} \
871extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
872 type ret; \
873 if (ctxt->name##Nr <= 0) return(0); \
874 ctxt->name##Nr--; \
875 if (ctxt->name##Nr > 0) \
876 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
877 else \
878 ctxt->name = NULL; \
879 ret = ctxt->name##Tab[ctxt->name##Nr]; \
880 ctxt->name##Tab[ctxt->name##Nr] = 0; \
881 return(ret); \
882} \
883
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000884/**
885 * valuePop:
886 * @ctxt: an XPath evaluation context
887 *
888 * Pops the top XPath object from the value stack
889 *
890 * Returns the XPath object just removed
891 */
892/**
893 * valuePush:
894 * @ctxt: an XPath evaluation context
895 * @value: the XPath object
896 *
897 * Pushes a new XPath object on top of the value stack
898 */
Owen Taylor3473f882001-02-23 17:55:21 +0000899PUSH_AND_POP(xmlXPathObjectPtr, value)
900
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000901/**
902 * xmlXPathPopBoolean:
903 * @ctxt: an XPath parser context
904 *
905 * Pops a boolean from the stack, handling conversion if needed.
906 * Check error with #xmlXPathCheckError.
907 *
908 * Returns the boolean
909 */
910int
911xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
912 xmlXPathObjectPtr obj;
913 int ret;
914
915 obj = valuePop(ctxt);
916 if (obj == NULL) {
917 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
918 return(0);
919 }
920 ret = xmlXPathCastToBoolean(obj);
921 xmlXPathFreeObject(obj);
922 return(ret);
923}
924
925/**
926 * xmlXPathPopNumber:
927 * @ctxt: an XPath parser context
928 *
929 * Pops a number from the stack, handling conversion if needed.
930 * Check error with #xmlXPathCheckError.
931 *
932 * Returns the number
933 */
934double
935xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
936 xmlXPathObjectPtr obj;
937 double ret;
938
939 obj = valuePop(ctxt);
940 if (obj == NULL) {
941 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
942 return(0);
943 }
944 ret = xmlXPathCastToNumber(obj);
945 xmlXPathFreeObject(obj);
946 return(ret);
947}
948
949/**
950 * xmlXPathPopString:
951 * @ctxt: an XPath parser context
952 *
953 * Pops a string from the stack, handling conversion if needed.
954 * Check error with #xmlXPathCheckError.
955 *
956 * Returns the string
957 */
958xmlChar *
959xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
960 xmlXPathObjectPtr obj;
961 xmlChar * ret;
962
963 obj = valuePop(ctxt);
964 if (obj == NULL) {
965 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
966 return(NULL);
967 }
968 ret = xmlXPathCastToString(obj);
969 /* TODO: needs refactoring somewhere else */
970 if (obj->stringval == ret)
971 obj->stringval = NULL;
972 xmlXPathFreeObject(obj);
973 return(ret);
974}
975
976/**
977 * xmlXPathPopNodeSet:
978 * @ctxt: an XPath parser context
979 *
980 * Pops a node-set from the stack, handling conversion if needed.
981 * Check error with #xmlXPathCheckError.
982 *
983 * Returns the node-set
984 */
985xmlNodeSetPtr
986xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
987 xmlXPathObjectPtr obj;
988 xmlNodeSetPtr ret;
989
990 if (ctxt->value == NULL) {
991 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
992 return(NULL);
993 }
994 if (!xmlXPathStackIsNodeSet(ctxt)) {
995 xmlXPathSetTypeError(ctxt);
996 return(NULL);
997 }
998 obj = valuePop(ctxt);
999 ret = obj->nodesetval;
1000 xmlXPathFreeNodeSetList(obj);
1001 return(ret);
1002}
1003
1004/**
1005 * xmlXPathPopExternal:
1006 * @ctxt: an XPath parser context
1007 *
1008 * Pops an external oject from the stack, handling conversion if needed.
1009 * Check error with #xmlXPathCheckError.
1010 *
1011 * Returns the object
1012 */
1013void *
1014xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1015 xmlXPathObjectPtr obj;
1016 void * ret;
1017
1018 if (ctxt->value == NULL) {
1019 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1020 return(NULL);
1021 }
1022 if (ctxt->value->type != XPATH_USERS) {
1023 xmlXPathSetTypeError(ctxt);
1024 return(NULL);
1025 }
1026 obj = valuePop(ctxt);
1027 ret = obj->user;
1028 xmlXPathFreeObject(obj);
1029 return(ret);
1030}
1031
Owen Taylor3473f882001-02-23 17:55:21 +00001032/*
1033 * Macros for accessing the content. Those should be used only by the parser,
1034 * and not exported.
1035 *
1036 * Dirty macros, i.e. one need to make assumption on the context to use them
1037 *
1038 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1039 * CUR returns the current xmlChar value, i.e. a 8 bit value
1040 * in ISO-Latin or UTF-8.
1041 * This should be used internally by the parser
1042 * only to compare to ASCII values otherwise it would break when
1043 * running with UTF-8 encoding.
1044 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1045 * to compare on ASCII based substring.
1046 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1047 * strings within the parser.
1048 * CURRENT Returns the current char value, with the full decoding of
1049 * UTF-8 if we are using this mode. It returns an int.
1050 * NEXT Skip to the next character, this does the proper decoding
1051 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1052 * It returns the pointer to the current xmlChar.
1053 */
1054
1055#define CUR (*ctxt->cur)
1056#define SKIP(val) ctxt->cur += (val)
1057#define NXT(val) ctxt->cur[(val)]
1058#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001059#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1060
1061#define COPY_BUF(l,b,i,v) \
1062 if (l == 1) b[i++] = (xmlChar) v; \
1063 else i += xmlCopyChar(l,&b[i],v)
1064
1065#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001066
1067#define SKIP_BLANKS \
1068 while (IS_BLANK(*(ctxt->cur))) NEXT
1069
1070#define CURRENT (*ctxt->cur)
1071#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1072
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001073
1074#ifndef DBL_DIG
1075#define DBL_DIG 16
1076#endif
1077#ifndef DBL_EPSILON
1078#define DBL_EPSILON 1E-9
1079#endif
1080
1081#define UPPER_DOUBLE 1E9
1082#define LOWER_DOUBLE 1E-5
1083
1084#define INTEGER_DIGITS DBL_DIG
1085#define FRACTION_DIGITS (DBL_DIG + 1)
1086#define EXPONENT_DIGITS (3 + 2)
1087
1088/**
1089 * xmlXPathFormatNumber:
1090 * @number: number to format
1091 * @buffer: output buffer
1092 * @buffersize: size of output buffer
1093 *
1094 * Convert the number into a string representation.
1095 */
1096static void
1097xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1098{
Daniel Veillardcda96922001-08-21 10:56:31 +00001099 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001100 case 1:
1101 if (buffersize > (int)sizeof("+Infinity"))
1102 sprintf(buffer, "+Infinity");
1103 break;
1104 case -1:
1105 if (buffersize > (int)sizeof("-Infinity"))
1106 sprintf(buffer, "-Infinity");
1107 break;
1108 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001109 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001110 if (buffersize > (int)sizeof("NaN"))
1111 sprintf(buffer, "NaN");
1112 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001113 /* 3 is sign, decimal point, and terminating zero */
1114 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1115 int integer_place, fraction_place;
1116 char *ptr;
1117 char *after_fraction;
1118 double absolute_value;
1119 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001120
Bjorn Reese70a9da52001-04-21 16:57:29 +00001121 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001122
Bjorn Reese70a9da52001-04-21 16:57:29 +00001123 /*
1124 * First choose format - scientific or regular floating point.
1125 * In either case, result is in work, and after_fraction points
1126 * just past the fractional part.
1127 */
1128 if ( ((absolute_value > UPPER_DOUBLE) ||
1129 (absolute_value < LOWER_DOUBLE)) &&
1130 (absolute_value != 0.0) ) {
1131 /* Use scientific notation */
1132 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1133 fraction_place = DBL_DIG - 1;
1134 snprintf(work, sizeof(work),"%*.*e",
1135 integer_place, fraction_place, number);
1136 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001137 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001138 else {
1139 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001140 if (absolute_value > 0.0)
1141 integer_place = 1 + (int)log10(absolute_value);
1142 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001143 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001144 fraction_place = (integer_place > 0)
1145 ? DBL_DIG - integer_place
1146 : DBL_DIG;
1147 size = snprintf(work, sizeof(work), "%0.*f",
1148 fraction_place, number);
1149 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001150 }
1151
Bjorn Reese70a9da52001-04-21 16:57:29 +00001152 /* Remove fractional trailing zeroes */
1153 ptr = after_fraction;
1154 while (*(--ptr) == '0')
1155 ;
1156 if (*ptr != '.')
1157 ptr++;
1158 strcpy(ptr, after_fraction);
1159
1160 /* Finally copy result back to caller */
1161 size = strlen(work) + 1;
1162 if (size > buffersize) {
1163 work[buffersize - 1] = 0;
1164 size = buffersize;
1165 }
1166 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001167 }
1168 break;
1169 }
1170}
1171
Owen Taylor3473f882001-02-23 17:55:21 +00001172/************************************************************************
1173 * *
1174 * Error handling routines *
1175 * *
1176 ************************************************************************/
1177
1178
Daniel Veillardb44025c2001-10-11 22:55:55 +00001179static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001180 "Ok",
1181 "Number encoding",
1182 "Unfinished litteral",
1183 "Start of litteral",
1184 "Expected $ for variable reference",
1185 "Undefined variable",
1186 "Invalid predicate",
1187 "Invalid expression",
1188 "Missing closing curly brace",
1189 "Unregistered function",
1190 "Invalid operand",
1191 "Invalid type",
1192 "Invalid number of arguments",
1193 "Invalid context size",
1194 "Invalid context position",
1195 "Memory allocation error",
1196 "Syntax error",
1197 "Resource error",
1198 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001199 "Undefined namespace prefix",
1200 "Encoding error",
1201 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001202};
1203
1204/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001205 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001206 * @ctxt: the XPath Parser context
1207 * @file: the file name
1208 * @line: the line number
1209 * @no: the error number
1210 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001211 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001212 */
1213void
1214xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1215 int line, int no) {
1216 int n;
1217 const xmlChar *cur;
1218 const xmlChar *base;
1219
1220 xmlGenericError(xmlGenericErrorContext,
1221 "Error %s:%d: %s\n", file, line,
1222 xmlXPathErrorMessages[no]);
1223
1224 cur = ctxt->cur;
1225 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001226 if ((cur == NULL) || (base == NULL))
1227 return;
1228
Owen Taylor3473f882001-02-23 17:55:21 +00001229 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1230 cur--;
1231 }
1232 n = 0;
1233 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1234 cur--;
1235 if ((*cur == '\n') || (*cur == '\r')) cur++;
1236 base = cur;
1237 n = 0;
1238 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1239 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1240 n++;
1241 }
1242 xmlGenericError(xmlGenericErrorContext, "\n");
1243 cur = ctxt->cur;
1244 while ((*cur == '\n') || (*cur == '\r'))
1245 cur--;
1246 n = 0;
1247 while ((cur != base) && (n++ < 80)) {
1248 xmlGenericError(xmlGenericErrorContext, " ");
1249 base++;
1250 }
1251 xmlGenericError(xmlGenericErrorContext,"^\n");
1252}
1253
1254
1255/************************************************************************
1256 * *
1257 * Routines to handle NodeSets *
1258 * *
1259 ************************************************************************/
1260
1261/**
1262 * xmlXPathCmpNodes:
1263 * @node1: the first node
1264 * @node2: the second node
1265 *
1266 * Compare two nodes w.r.t document order
1267 *
1268 * Returns -2 in case of error 1 if first point < second point, 0 if
1269 * that's the same node, -1 otherwise
1270 */
1271int
1272xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1273 int depth1, depth2;
1274 xmlNodePtr cur, root;
1275
1276 if ((node1 == NULL) || (node2 == NULL))
1277 return(-2);
1278 /*
1279 * a couple of optimizations which will avoid computations in most cases
1280 */
1281 if (node1 == node2)
1282 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001283 if ((node1->type == XML_NAMESPACE_DECL) ||
1284 (node2->type == XML_NAMESPACE_DECL))
1285 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001286 if (node1 == node2->prev)
1287 return(1);
1288 if (node1 == node2->next)
1289 return(-1);
1290
1291 /*
1292 * compute depth to root
1293 */
1294 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1295 if (cur == node1)
1296 return(1);
1297 depth2++;
1298 }
1299 root = cur;
1300 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1301 if (cur == node2)
1302 return(-1);
1303 depth1++;
1304 }
1305 /*
1306 * Distinct document (or distinct entities :-( ) case.
1307 */
1308 if (root != cur) {
1309 return(-2);
1310 }
1311 /*
1312 * get the nearest common ancestor.
1313 */
1314 while (depth1 > depth2) {
1315 depth1--;
1316 node1 = node1->parent;
1317 }
1318 while (depth2 > depth1) {
1319 depth2--;
1320 node2 = node2->parent;
1321 }
1322 while (node1->parent != node2->parent) {
1323 node1 = node1->parent;
1324 node2 = node2->parent;
1325 /* should not happen but just in case ... */
1326 if ((node1 == NULL) || (node2 == NULL))
1327 return(-2);
1328 }
1329 /*
1330 * Find who's first.
1331 */
1332 if (node1 == node2->next)
1333 return(-1);
1334 for (cur = node1->next;cur != NULL;cur = cur->next)
1335 if (cur == node2)
1336 return(1);
1337 return(-1); /* assume there is no sibling list corruption */
1338}
1339
1340/**
1341 * xmlXPathNodeSetSort:
1342 * @set: the node set
1343 *
1344 * Sort the node set in document order
1345 */
1346void
1347xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001348 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001349 xmlNodePtr tmp;
1350
1351 if (set == NULL)
1352 return;
1353
1354 /* Use Shell's sort to sort the node-set */
1355 len = set->nodeNr;
1356 for (incr = len / 2; incr > 0; incr /= 2) {
1357 for (i = incr; i < len; i++) {
1358 j = i - incr;
1359 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001360 if (xmlXPathCmpNodes(set->nodeTab[j],
1361 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001362 tmp = set->nodeTab[j];
1363 set->nodeTab[j] = set->nodeTab[j + incr];
1364 set->nodeTab[j + incr] = tmp;
1365 j -= incr;
1366 } else
1367 break;
1368 }
1369 }
1370 }
1371}
1372
1373#define XML_NODESET_DEFAULT 10
1374/**
1375 * xmlXPathNodeSetCreate:
1376 * @val: an initial xmlNodePtr, or NULL
1377 *
1378 * Create a new xmlNodeSetPtr of type double and of value @val
1379 *
1380 * Returns the newly created object.
1381 */
1382xmlNodeSetPtr
1383xmlXPathNodeSetCreate(xmlNodePtr val) {
1384 xmlNodeSetPtr ret;
1385
1386 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1387 if (ret == NULL) {
1388 xmlGenericError(xmlGenericErrorContext,
1389 "xmlXPathNewNodeSet: out of memory\n");
1390 return(NULL);
1391 }
1392 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1393 if (val != NULL) {
1394 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1395 sizeof(xmlNodePtr));
1396 if (ret->nodeTab == NULL) {
1397 xmlGenericError(xmlGenericErrorContext,
1398 "xmlXPathNewNodeSet: out of memory\n");
1399 return(NULL);
1400 }
1401 memset(ret->nodeTab, 0 ,
1402 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1403 ret->nodeMax = XML_NODESET_DEFAULT;
1404 ret->nodeTab[ret->nodeNr++] = val;
1405 }
1406 return(ret);
1407}
1408
1409/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001410 * xmlXPathNodeSetContains:
1411 * @cur: the node-set
1412 * @val: the node
1413 *
1414 * checks whether @cur contains @val
1415 *
1416 * Returns true (1) if @cur contains @val, false (0) otherwise
1417 */
1418int
1419xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1420 int i;
1421
1422 for (i = 0; i < cur->nodeNr; i++) {
1423 if (cur->nodeTab[i] == val)
1424 return(1);
1425 }
1426 return(0);
1427}
1428
1429/**
Owen Taylor3473f882001-02-23 17:55:21 +00001430 * xmlXPathNodeSetAdd:
1431 * @cur: the initial node set
1432 * @val: a new xmlNodePtr
1433 *
1434 * add a new xmlNodePtr ot an existing NodeSet
1435 */
1436void
1437xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1438 int i;
1439
1440 if (val == NULL) return;
1441
1442 /*
1443 * check against doublons
1444 */
1445 for (i = 0;i < cur->nodeNr;i++)
1446 if (cur->nodeTab[i] == val) return;
1447
1448 /*
1449 * grow the nodeTab if needed
1450 */
1451 if (cur->nodeMax == 0) {
1452 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1453 sizeof(xmlNodePtr));
1454 if (cur->nodeTab == NULL) {
1455 xmlGenericError(xmlGenericErrorContext,
1456 "xmlXPathNodeSetAdd: out of memory\n");
1457 return;
1458 }
1459 memset(cur->nodeTab, 0 ,
1460 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1461 cur->nodeMax = XML_NODESET_DEFAULT;
1462 } else if (cur->nodeNr == cur->nodeMax) {
1463 xmlNodePtr *temp;
1464
1465 cur->nodeMax *= 2;
1466 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1467 sizeof(xmlNodePtr));
1468 if (temp == NULL) {
1469 xmlGenericError(xmlGenericErrorContext,
1470 "xmlXPathNodeSetAdd: out of memory\n");
1471 return;
1472 }
1473 cur->nodeTab = temp;
1474 }
1475 cur->nodeTab[cur->nodeNr++] = val;
1476}
1477
1478/**
1479 * xmlXPathNodeSetAddUnique:
1480 * @cur: the initial node set
1481 * @val: a new xmlNodePtr
1482 *
1483 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1484 * when we are sure the node is not already in the set.
1485 */
1486void
1487xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1488 if (val == NULL) return;
1489
1490 /*
1491 * grow the nodeTab if needed
1492 */
1493 if (cur->nodeMax == 0) {
1494 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1495 sizeof(xmlNodePtr));
1496 if (cur->nodeTab == NULL) {
1497 xmlGenericError(xmlGenericErrorContext,
1498 "xmlXPathNodeSetAddUnique: out of memory\n");
1499 return;
1500 }
1501 memset(cur->nodeTab, 0 ,
1502 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1503 cur->nodeMax = XML_NODESET_DEFAULT;
1504 } else if (cur->nodeNr == cur->nodeMax) {
1505 xmlNodePtr *temp;
1506
1507 cur->nodeMax *= 2;
1508 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1509 sizeof(xmlNodePtr));
1510 if (temp == NULL) {
1511 xmlGenericError(xmlGenericErrorContext,
1512 "xmlXPathNodeSetAddUnique: out of memory\n");
1513 return;
1514 }
1515 cur->nodeTab = temp;
1516 }
1517 cur->nodeTab[cur->nodeNr++] = val;
1518}
1519
1520/**
1521 * xmlXPathNodeSetMerge:
1522 * @val1: the first NodeSet or NULL
1523 * @val2: the second NodeSet
1524 *
1525 * Merges two nodesets, all nodes from @val2 are added to @val1
1526 * if @val1 is NULL, a new set is created and copied from @val2
1527 *
1528 * Returns val1 once extended or NULL in case of error.
1529 */
1530xmlNodeSetPtr
1531xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001532 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001533
1534 if (val2 == NULL) return(val1);
1535 if (val1 == NULL) {
1536 val1 = xmlXPathNodeSetCreate(NULL);
1537 }
1538
1539 initNr = val1->nodeNr;
1540
1541 for (i = 0;i < val2->nodeNr;i++) {
1542 /*
1543 * check against doublons
1544 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001545 skip = 0;
1546 for (j = 0; j < initNr; j++) {
1547 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1548 skip = 1;
1549 break;
1550 }
1551 }
1552 if (skip)
1553 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001554
1555 /*
1556 * grow the nodeTab if needed
1557 */
1558 if (val1->nodeMax == 0) {
1559 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1560 sizeof(xmlNodePtr));
1561 if (val1->nodeTab == NULL) {
1562 xmlGenericError(xmlGenericErrorContext,
1563 "xmlXPathNodeSetMerge: out of memory\n");
1564 return(NULL);
1565 }
1566 memset(val1->nodeTab, 0 ,
1567 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1568 val1->nodeMax = XML_NODESET_DEFAULT;
1569 } else if (val1->nodeNr == val1->nodeMax) {
1570 xmlNodePtr *temp;
1571
1572 val1->nodeMax *= 2;
1573 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1574 sizeof(xmlNodePtr));
1575 if (temp == NULL) {
1576 xmlGenericError(xmlGenericErrorContext,
1577 "xmlXPathNodeSetMerge: out of memory\n");
1578 return(NULL);
1579 }
1580 val1->nodeTab = temp;
1581 }
1582 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1583 }
1584
1585 return(val1);
1586}
1587
1588/**
1589 * xmlXPathNodeSetDel:
1590 * @cur: the initial node set
1591 * @val: an xmlNodePtr
1592 *
1593 * Removes an xmlNodePtr from an existing NodeSet
1594 */
1595void
1596xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1597 int i;
1598
1599 if (cur == NULL) return;
1600 if (val == NULL) return;
1601
1602 /*
1603 * check against doublons
1604 */
1605 for (i = 0;i < cur->nodeNr;i++)
1606 if (cur->nodeTab[i] == val) break;
1607
1608 if (i >= cur->nodeNr) {
1609#ifdef DEBUG
1610 xmlGenericError(xmlGenericErrorContext,
1611 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1612 val->name);
1613#endif
1614 return;
1615 }
1616 cur->nodeNr--;
1617 for (;i < cur->nodeNr;i++)
1618 cur->nodeTab[i] = cur->nodeTab[i + 1];
1619 cur->nodeTab[cur->nodeNr] = NULL;
1620}
1621
1622/**
1623 * xmlXPathNodeSetRemove:
1624 * @cur: the initial node set
1625 * @val: the index to remove
1626 *
1627 * Removes an entry from an existing NodeSet list.
1628 */
1629void
1630xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1631 if (cur == NULL) return;
1632 if (val >= cur->nodeNr) return;
1633 cur->nodeNr--;
1634 for (;val < cur->nodeNr;val++)
1635 cur->nodeTab[val] = cur->nodeTab[val + 1];
1636 cur->nodeTab[cur->nodeNr] = NULL;
1637}
1638
1639/**
1640 * xmlXPathFreeNodeSet:
1641 * @obj: the xmlNodeSetPtr to free
1642 *
1643 * Free the NodeSet compound (not the actual nodes !).
1644 */
1645void
1646xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1647 if (obj == NULL) return;
1648 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001649 xmlFree(obj->nodeTab);
1650 }
Owen Taylor3473f882001-02-23 17:55:21 +00001651 xmlFree(obj);
1652}
1653
1654/**
1655 * xmlXPathFreeValueTree:
1656 * @obj: the xmlNodeSetPtr to free
1657 *
1658 * Free the NodeSet compound and the actual tree, this is different
1659 * from xmlXPathFreeNodeSet()
1660 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001661static void
Owen Taylor3473f882001-02-23 17:55:21 +00001662xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1663 int i;
1664
1665 if (obj == NULL) return;
1666 for (i = 0;i < obj->nodeNr;i++)
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001667 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001668 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001669
1670 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001671 xmlFree(obj->nodeTab);
1672 }
Owen Taylor3473f882001-02-23 17:55:21 +00001673 xmlFree(obj);
1674}
1675
1676#if defined(DEBUG) || defined(DEBUG_STEP)
1677/**
1678 * xmlGenericErrorContextNodeSet:
1679 * @output: a FILE * for the output
1680 * @obj: the xmlNodeSetPtr to free
1681 *
1682 * Quick display of a NodeSet
1683 */
1684void
1685xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1686 int i;
1687
1688 if (output == NULL) output = xmlGenericErrorContext;
1689 if (obj == NULL) {
1690 fprintf(output, "NodeSet == NULL !\n");
1691 return;
1692 }
1693 if (obj->nodeNr == 0) {
1694 fprintf(output, "NodeSet is empty\n");
1695 return;
1696 }
1697 if (obj->nodeTab == NULL) {
1698 fprintf(output, " nodeTab == NULL !\n");
1699 return;
1700 }
1701 for (i = 0; i < obj->nodeNr; i++) {
1702 if (obj->nodeTab[i] == NULL) {
1703 fprintf(output, " NULL !\n");
1704 return;
1705 }
1706 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1707 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1708 fprintf(output, " /");
1709 else if (obj->nodeTab[i]->name == NULL)
1710 fprintf(output, " noname!");
1711 else fprintf(output, " %s", obj->nodeTab[i]->name);
1712 }
1713 fprintf(output, "\n");
1714}
1715#endif
1716
1717/**
1718 * xmlXPathNewNodeSet:
1719 * @val: the NodePtr value
1720 *
1721 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1722 * it with the single Node @val
1723 *
1724 * Returns the newly created object.
1725 */
1726xmlXPathObjectPtr
1727xmlXPathNewNodeSet(xmlNodePtr val) {
1728 xmlXPathObjectPtr ret;
1729
1730 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1731 if (ret == NULL) {
1732 xmlGenericError(xmlGenericErrorContext,
1733 "xmlXPathNewNodeSet: out of memory\n");
1734 return(NULL);
1735 }
1736 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1737 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001738 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001739 ret->nodesetval = xmlXPathNodeSetCreate(val);
1740 return(ret);
1741}
1742
1743/**
1744 * xmlXPathNewValueTree:
1745 * @val: the NodePtr value
1746 *
1747 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1748 * it with the tree root @val
1749 *
1750 * Returns the newly created object.
1751 */
1752xmlXPathObjectPtr
1753xmlXPathNewValueTree(xmlNodePtr val) {
1754 xmlXPathObjectPtr ret;
1755
1756 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1757 if (ret == NULL) {
1758 xmlGenericError(xmlGenericErrorContext,
1759 "xmlXPathNewNodeSet: out of memory\n");
1760 return(NULL);
1761 }
1762 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1763 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001764 ret->boolval = 1;
1765 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00001766 ret->nodesetval = xmlXPathNodeSetCreate(val);
1767 return(ret);
1768}
1769
1770/**
1771 * xmlXPathNewNodeSetList:
1772 * @val: an existing NodeSet
1773 *
1774 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1775 * it with the Nodeset @val
1776 *
1777 * Returns the newly created object.
1778 */
1779xmlXPathObjectPtr
1780xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1781 xmlXPathObjectPtr ret;
1782 int i;
1783
1784 if (val == NULL)
1785 ret = NULL;
1786 else if (val->nodeTab == NULL)
1787 ret = xmlXPathNewNodeSet(NULL);
1788 else
1789 {
1790 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1791 for (i = 1; i < val->nodeNr; ++i)
1792 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1793 }
1794
1795 return(ret);
1796}
1797
1798/**
1799 * xmlXPathWrapNodeSet:
1800 * @val: the NodePtr value
1801 *
1802 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1803 *
1804 * Returns the newly created object.
1805 */
1806xmlXPathObjectPtr
1807xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1808 xmlXPathObjectPtr ret;
1809
1810 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1811 if (ret == NULL) {
1812 xmlGenericError(xmlGenericErrorContext,
1813 "xmlXPathWrapNodeSet: out of memory\n");
1814 return(NULL);
1815 }
1816 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1817 ret->type = XPATH_NODESET;
1818 ret->nodesetval = val;
1819 return(ret);
1820}
1821
1822/**
1823 * xmlXPathFreeNodeSetList:
1824 * @obj: an existing NodeSetList object
1825 *
1826 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1827 * the list contrary to xmlXPathFreeObject().
1828 */
1829void
1830xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1831 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001832 xmlFree(obj);
1833}
1834
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001835/**
1836 * xmlXPathDifference:
1837 * @nodes1: a node-set
1838 * @nodes2: a node-set
1839 *
1840 * Implements the EXSLT - Sets difference() function:
1841 * node-set set:difference (node-set, node-set)
1842 *
1843 * Returns the difference between the two node sets, or nodes1 if
1844 * nodes2 is empty
1845 */
1846xmlNodeSetPtr
1847xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1848 xmlNodeSetPtr ret;
1849 int i, l1;
1850 xmlNodePtr cur;
1851
1852 if (xmlXPathNodeSetIsEmpty(nodes2))
1853 return(nodes1);
1854
1855 ret = xmlXPathNodeSetCreate(NULL);
1856 if (xmlXPathNodeSetIsEmpty(nodes1))
1857 return(ret);
1858
1859 l1 = xmlXPathNodeSetGetLength(nodes1);
1860
1861 for (i = 0; i < l1; i++) {
1862 cur = xmlXPathNodeSetItem(nodes1, i);
1863 if (!xmlXPathNodeSetContains(nodes2, cur))
1864 xmlXPathNodeSetAddUnique(ret, cur);
1865 }
1866 return(ret);
1867}
1868
1869/**
1870 * xmlXPathIntersection:
1871 * @nodes1: a node-set
1872 * @nodes2: a node-set
1873 *
1874 * Implements the EXSLT - Sets intersection() function:
1875 * node-set set:intersection (node-set, node-set)
1876 *
1877 * Returns a node set comprising the nodes that are within both the
1878 * node sets passed as arguments
1879 */
1880xmlNodeSetPtr
1881xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1882 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
1883 int i, l1;
1884 xmlNodePtr cur;
1885
1886 if (xmlXPathNodeSetIsEmpty(nodes1))
1887 return(ret);
1888 if (xmlXPathNodeSetIsEmpty(nodes2))
1889 return(ret);
1890
1891 l1 = xmlXPathNodeSetGetLength(nodes1);
1892
1893 for (i = 0; i < l1; i++) {
1894 cur = xmlXPathNodeSetItem(nodes1, i);
1895 if (xmlXPathNodeSetContains(nodes2, cur))
1896 xmlXPathNodeSetAddUnique(ret, cur);
1897 }
1898 return(ret);
1899}
1900
1901/**
1902 * xmlXPathDistinctSorted:
1903 * @nodes: a node-set, sorted by document order
1904 *
1905 * Implements the EXSLT - Sets distinct() function:
1906 * node-set set:distinct (node-set)
1907 *
1908 * Returns a subset of the nodes contained in @nodes, or @nodes if
1909 * it is empty
1910 */
1911xmlNodeSetPtr
1912xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
1913 xmlNodeSetPtr ret;
1914 xmlHashTablePtr hash;
1915 int i, l;
1916 xmlChar * strval;
1917 xmlNodePtr cur;
1918
1919 if (xmlXPathNodeSetIsEmpty(nodes))
1920 return(nodes);
1921
1922 ret = xmlXPathNodeSetCreate(NULL);
1923 l = xmlXPathNodeSetGetLength(nodes);
1924 hash = xmlHashCreate (l);
1925 for (i = 0; i < l; i++) {
1926 cur = xmlXPathNodeSetItem(nodes, i);
1927 strval = xmlXPathCastNodeToString(cur);
1928 if (xmlHashLookup(hash, strval) == NULL) {
1929 xmlHashAddEntry(hash, strval, strval);
1930 xmlXPathNodeSetAddUnique(ret, cur);
1931 } else {
1932 xmlFree(strval);
1933 }
1934 }
1935 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
1936 return(ret);
1937}
1938
1939/**
1940 * xmlXPathDistinct:
1941 * @nodes: a node-set
1942 *
1943 * Implements the EXSLT - Sets distinct() function:
1944 * node-set set:distinct (node-set)
1945 * @nodes is sorted by document order, then #exslSetsDistinctSorted
1946 * is called with the sorted node-set
1947 *
1948 * Returns a subset of the nodes contained in @nodes, or @nodes if
1949 * it is empty
1950 */
1951xmlNodeSetPtr
1952xmlXPathDistinct (xmlNodeSetPtr nodes) {
1953 if (xmlXPathNodeSetIsEmpty(nodes))
1954 return(nodes);
1955
1956 xmlXPathNodeSetSort(nodes);
1957 return(xmlXPathDistinctSorted(nodes));
1958}
1959
1960/**
1961 * xmlXPathHasSameNodes:
1962 * @nodes1: a node-set
1963 * @nodes2: a node-set
1964 *
1965 * Implements the EXSLT - Sets has-same-nodes function:
1966 * boolean set:has-same-node(node-set, node-set)
1967 *
1968 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
1969 * otherwise
1970 */
1971int
1972xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1973 int i, l;
1974 xmlNodePtr cur;
1975
1976 if (xmlXPathNodeSetIsEmpty(nodes1) ||
1977 xmlXPathNodeSetIsEmpty(nodes2))
1978 return(0);
1979
1980 l = xmlXPathNodeSetGetLength(nodes1);
1981 for (i = 0; i < l; i++) {
1982 cur = xmlXPathNodeSetItem(nodes1, i);
1983 if (xmlXPathNodeSetContains(nodes2, cur))
1984 return(1);
1985 }
1986 return(0);
1987}
1988
1989/**
1990 * xmlXPathNodeLeadingSorted:
1991 * @nodes: a node-set, sorted by document order
1992 * @node: a node
1993 *
1994 * Implements the EXSLT - Sets leading() function:
1995 * node-set set:leading (node-set, node-set)
1996 *
1997 * Returns the nodes in @nodes that precede @node in document order,
1998 * @nodes if @node is NULL or an empty node-set if @nodes
1999 * doesn't contain @node
2000 */
2001xmlNodeSetPtr
2002xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2003 int i, l;
2004 xmlNodePtr cur;
2005 xmlNodeSetPtr ret;
2006
2007 if (node == NULL)
2008 return(nodes);
2009
2010 ret = xmlXPathNodeSetCreate(NULL);
2011 if (xmlXPathNodeSetIsEmpty(nodes) ||
2012 (!xmlXPathNodeSetContains(nodes, node)))
2013 return(ret);
2014
2015 l = xmlXPathNodeSetGetLength(nodes);
2016 for (i = 0; i < l; i++) {
2017 cur = xmlXPathNodeSetItem(nodes, i);
2018 if (cur == node)
2019 break;
2020 xmlXPathNodeSetAddUnique(ret, cur);
2021 }
2022 return(ret);
2023}
2024
2025/**
2026 * xmlXPathNodeLeading:
2027 * @nodes: a node-set
2028 * @node: a node
2029 *
2030 * Implements the EXSLT - Sets leading() function:
2031 * node-set set:leading (node-set, node-set)
2032 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2033 * is called.
2034 *
2035 * Returns the nodes in @nodes that precede @node in document order,
2036 * @nodes if @node is NULL or an empty node-set if @nodes
2037 * doesn't contain @node
2038 */
2039xmlNodeSetPtr
2040xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2041 xmlXPathNodeSetSort(nodes);
2042 return(xmlXPathNodeLeadingSorted(nodes, node));
2043}
2044
2045/**
2046 * xmlXPathLeadingSorted:
2047 * @nodes1: a node-set, sorted by document order
2048 * @nodes2: a node-set, sorted by document order
2049 *
2050 * Implements the EXSLT - Sets leading() function:
2051 * node-set set:leading (node-set, node-set)
2052 *
2053 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2054 * in document order, @nodes1 if @nodes2 is NULL or empty or
2055 * an empty node-set if @nodes1 doesn't contain @nodes2
2056 */
2057xmlNodeSetPtr
2058xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2059 if (xmlXPathNodeSetIsEmpty(nodes2))
2060 return(nodes1);
2061 return(xmlXPathNodeLeadingSorted(nodes1,
2062 xmlXPathNodeSetItem(nodes2, 1)));
2063}
2064
2065/**
2066 * xmlXPathLeading:
2067 * @nodes1: a node-set
2068 * @nodes2: a node-set
2069 *
2070 * Implements the EXSLT - Sets leading() function:
2071 * node-set set:leading (node-set, node-set)
2072 * @nodes1 and @nodes2 are sorted by document order, then
2073 * #exslSetsLeadingSorted is called.
2074 *
2075 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2076 * in document order, @nodes1 if @nodes2 is NULL or empty or
2077 * an empty node-set if @nodes1 doesn't contain @nodes2
2078 */
2079xmlNodeSetPtr
2080xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2081 if (xmlXPathNodeSetIsEmpty(nodes2))
2082 return(nodes1);
2083 if (xmlXPathNodeSetIsEmpty(nodes1))
2084 return(xmlXPathNodeSetCreate(NULL));
2085 xmlXPathNodeSetSort(nodes1);
2086 xmlXPathNodeSetSort(nodes2);
2087 return(xmlXPathNodeLeadingSorted(nodes1,
2088 xmlXPathNodeSetItem(nodes2, 1)));
2089}
2090
2091/**
2092 * xmlXPathNodeTrailingSorted:
2093 * @nodes: a node-set, sorted by document order
2094 * @node: a node
2095 *
2096 * Implements the EXSLT - Sets trailing() function:
2097 * node-set set:trailing (node-set, node-set)
2098 *
2099 * Returns the nodes in @nodes that follow @node in document order,
2100 * @nodes if @node is NULL or an empty node-set if @nodes
2101 * doesn't contain @node
2102 */
2103xmlNodeSetPtr
2104xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2105 int i, l;
2106 xmlNodePtr cur;
2107 xmlNodeSetPtr ret;
2108
2109 if (node == NULL)
2110 return(nodes);
2111
2112 ret = xmlXPathNodeSetCreate(NULL);
2113 if (xmlXPathNodeSetIsEmpty(nodes) ||
2114 (!xmlXPathNodeSetContains(nodes, node)))
2115 return(ret);
2116
2117 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002118 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002119 cur = xmlXPathNodeSetItem(nodes, i);
2120 if (cur == node)
2121 break;
2122 xmlXPathNodeSetAddUnique(ret, cur);
2123 }
2124 return(ret);
2125}
2126
2127/**
2128 * xmlXPathNodeTrailing:
2129 * @nodes: a node-set
2130 * @node: a node
2131 *
2132 * Implements the EXSLT - Sets trailing() function:
2133 * node-set set:trailing (node-set, node-set)
2134 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2135 * is called.
2136 *
2137 * Returns the nodes in @nodes that follow @node in document order,
2138 * @nodes if @node is NULL or an empty node-set if @nodes
2139 * doesn't contain @node
2140 */
2141xmlNodeSetPtr
2142xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2143 xmlXPathNodeSetSort(nodes);
2144 return(xmlXPathNodeTrailingSorted(nodes, node));
2145}
2146
2147/**
2148 * xmlXPathTrailingSorted:
2149 * @nodes1: a node-set, sorted by document order
2150 * @nodes2: a node-set, sorted by document order
2151 *
2152 * Implements the EXSLT - Sets trailing() function:
2153 * node-set set:trailing (node-set, node-set)
2154 *
2155 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2156 * in document order, @nodes1 if @nodes2 is NULL or empty or
2157 * an empty node-set if @nodes1 doesn't contain @nodes2
2158 */
2159xmlNodeSetPtr
2160xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2161 if (xmlXPathNodeSetIsEmpty(nodes2))
2162 return(nodes1);
2163 return(xmlXPathNodeTrailingSorted(nodes1,
2164 xmlXPathNodeSetItem(nodes2, 0)));
2165}
2166
2167/**
2168 * xmlXPathTrailing:
2169 * @nodes1: a node-set
2170 * @nodes2: a node-set
2171 *
2172 * Implements the EXSLT - Sets trailing() function:
2173 * node-set set:trailing (node-set, node-set)
2174 * @nodes1 and @nodes2 are sorted by document order, then
2175 * #xmlXPathTrailingSorted is called.
2176 *
2177 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2178 * in document order, @nodes1 if @nodes2 is NULL or empty or
2179 * an empty node-set if @nodes1 doesn't contain @nodes2
2180 */
2181xmlNodeSetPtr
2182xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2183 if (xmlXPathNodeSetIsEmpty(nodes2))
2184 return(nodes1);
2185 if (xmlXPathNodeSetIsEmpty(nodes1))
2186 return(xmlXPathNodeSetCreate(NULL));
2187 xmlXPathNodeSetSort(nodes1);
2188 xmlXPathNodeSetSort(nodes2);
2189 return(xmlXPathNodeTrailingSorted(nodes1,
2190 xmlXPathNodeSetItem(nodes2, 0)));
2191}
2192
Owen Taylor3473f882001-02-23 17:55:21 +00002193/************************************************************************
2194 * *
2195 * Routines to handle extra functions *
2196 * *
2197 ************************************************************************/
2198
2199/**
2200 * xmlXPathRegisterFunc:
2201 * @ctxt: the XPath context
2202 * @name: the function name
2203 * @f: the function implementation or NULL
2204 *
2205 * Register a new function. If @f is NULL it unregisters the function
2206 *
2207 * Returns 0 in case of success, -1 in case of error
2208 */
2209int
2210xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2211 xmlXPathFunction f) {
2212 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2213}
2214
2215/**
2216 * xmlXPathRegisterFuncNS:
2217 * @ctxt: the XPath context
2218 * @name: the function name
2219 * @ns_uri: the function namespace URI
2220 * @f: the function implementation or NULL
2221 *
2222 * Register a new function. If @f is NULL it unregisters the function
2223 *
2224 * Returns 0 in case of success, -1 in case of error
2225 */
2226int
2227xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2228 const xmlChar *ns_uri, xmlXPathFunction f) {
2229 if (ctxt == NULL)
2230 return(-1);
2231 if (name == NULL)
2232 return(-1);
2233
2234 if (ctxt->funcHash == NULL)
2235 ctxt->funcHash = xmlHashCreate(0);
2236 if (ctxt->funcHash == NULL)
2237 return(-1);
2238 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2239}
2240
2241/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002242 * xmlXPathRegisterFuncLookup:
2243 * @ctxt: the XPath context
2244 * @f: the lookup function
2245 * @data: the lookup data
2246 *
2247 * Registers an external mecanism to do function lookup.
2248 */
2249void
2250xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2251 xmlXPathFuncLookupFunc f,
2252 void *funcCtxt) {
2253 if (ctxt == NULL)
2254 return;
2255 ctxt->funcLookupFunc = (void *) f;
2256 ctxt->funcLookupData = funcCtxt;
2257}
2258
2259/**
Owen Taylor3473f882001-02-23 17:55:21 +00002260 * xmlXPathFunctionLookup:
2261 * @ctxt: the XPath context
2262 * @name: the function name
2263 *
2264 * Search in the Function array of the context for the given
2265 * function.
2266 *
2267 * Returns the xmlXPathFunction or NULL if not found
2268 */
2269xmlXPathFunction
2270xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002271 if (ctxt == NULL)
2272 return (NULL);
2273
2274 if (ctxt->funcLookupFunc != NULL) {
2275 xmlXPathFunction ret;
2276
2277 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2278 (ctxt->funcLookupData, name, NULL);
2279 if (ret != NULL)
2280 return(ret);
2281 }
Owen Taylor3473f882001-02-23 17:55:21 +00002282 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2283}
2284
2285/**
2286 * xmlXPathFunctionLookupNS:
2287 * @ctxt: the XPath context
2288 * @name: the function name
2289 * @ns_uri: the function namespace URI
2290 *
2291 * Search in the Function array of the context for the given
2292 * function.
2293 *
2294 * Returns the xmlXPathFunction or NULL if not found
2295 */
2296xmlXPathFunction
2297xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2298 const xmlChar *ns_uri) {
2299 if (ctxt == NULL)
2300 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002301 if (name == NULL)
2302 return(NULL);
2303
Thomas Broyerba4ad322001-07-26 16:55:21 +00002304 if (ctxt->funcLookupFunc != NULL) {
2305 xmlXPathFunction ret;
2306
2307 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2308 (ctxt->funcLookupData, name, ns_uri);
2309 if (ret != NULL)
2310 return(ret);
2311 }
2312
2313 if (ctxt->funcHash == NULL)
2314 return(NULL);
2315
Owen Taylor3473f882001-02-23 17:55:21 +00002316 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2317}
2318
2319/**
2320 * xmlXPathRegisteredFuncsCleanup:
2321 * @ctxt: the XPath context
2322 *
2323 * Cleanup the XPath context data associated to registered functions
2324 */
2325void
2326xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2327 if (ctxt == NULL)
2328 return;
2329
2330 xmlHashFree(ctxt->funcHash, NULL);
2331 ctxt->funcHash = NULL;
2332}
2333
2334/************************************************************************
2335 * *
2336 * Routines to handle Variable *
2337 * *
2338 ************************************************************************/
2339
2340/**
2341 * xmlXPathRegisterVariable:
2342 * @ctxt: the XPath context
2343 * @name: the variable name
2344 * @value: the variable value or NULL
2345 *
2346 * Register a new variable value. If @value is NULL it unregisters
2347 * the variable
2348 *
2349 * Returns 0 in case of success, -1 in case of error
2350 */
2351int
2352xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2353 xmlXPathObjectPtr value) {
2354 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2355}
2356
2357/**
2358 * xmlXPathRegisterVariableNS:
2359 * @ctxt: the XPath context
2360 * @name: the variable name
2361 * @ns_uri: the variable namespace URI
2362 * @value: the variable value or NULL
2363 *
2364 * Register a new variable value. If @value is NULL it unregisters
2365 * the variable
2366 *
2367 * Returns 0 in case of success, -1 in case of error
2368 */
2369int
2370xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2371 const xmlChar *ns_uri,
2372 xmlXPathObjectPtr value) {
2373 if (ctxt == NULL)
2374 return(-1);
2375 if (name == NULL)
2376 return(-1);
2377
2378 if (ctxt->varHash == NULL)
2379 ctxt->varHash = xmlHashCreate(0);
2380 if (ctxt->varHash == NULL)
2381 return(-1);
2382 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2383 (void *) value,
2384 (xmlHashDeallocator)xmlXPathFreeObject));
2385}
2386
2387/**
2388 * xmlXPathRegisterVariableLookup:
2389 * @ctxt: the XPath context
2390 * @f: the lookup function
2391 * @data: the lookup data
2392 *
2393 * register an external mechanism to do variable lookup
2394 */
2395void
2396xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2397 xmlXPathVariableLookupFunc f, void *data) {
2398 if (ctxt == NULL)
2399 return;
2400 ctxt->varLookupFunc = (void *) f;
2401 ctxt->varLookupData = data;
2402}
2403
2404/**
2405 * xmlXPathVariableLookup:
2406 * @ctxt: the XPath context
2407 * @name: the variable name
2408 *
2409 * Search in the Variable array of the context for the given
2410 * variable value.
2411 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002412 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002413 */
2414xmlXPathObjectPtr
2415xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2416 if (ctxt == NULL)
2417 return(NULL);
2418
2419 if (ctxt->varLookupFunc != NULL) {
2420 xmlXPathObjectPtr ret;
2421
2422 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2423 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002424 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002425 }
2426 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2427}
2428
2429/**
2430 * xmlXPathVariableLookupNS:
2431 * @ctxt: the XPath context
2432 * @name: the variable name
2433 * @ns_uri: the variable namespace URI
2434 *
2435 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002436 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002437 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002438 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002439 */
2440xmlXPathObjectPtr
2441xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2442 const xmlChar *ns_uri) {
2443 if (ctxt == NULL)
2444 return(NULL);
2445
2446 if (ctxt->varLookupFunc != NULL) {
2447 xmlXPathObjectPtr ret;
2448
2449 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2450 (ctxt->varLookupData, name, ns_uri);
2451 if (ret != NULL) return(ret);
2452 }
2453
2454 if (ctxt->varHash == NULL)
2455 return(NULL);
2456 if (name == NULL)
2457 return(NULL);
2458
Daniel Veillard8c357d52001-07-03 23:43:33 +00002459 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2460 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002461}
2462
2463/**
2464 * xmlXPathRegisteredVariablesCleanup:
2465 * @ctxt: the XPath context
2466 *
2467 * Cleanup the XPath context data associated to registered variables
2468 */
2469void
2470xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2471 if (ctxt == NULL)
2472 return;
2473
Daniel Veillard76d66f42001-05-16 21:05:17 +00002474 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002475 ctxt->varHash = NULL;
2476}
2477
2478/**
2479 * xmlXPathRegisterNs:
2480 * @ctxt: the XPath context
2481 * @prefix: the namespace prefix
2482 * @ns_uri: the namespace name
2483 *
2484 * Register a new namespace. If @ns_uri is NULL it unregisters
2485 * the namespace
2486 *
2487 * Returns 0 in case of success, -1 in case of error
2488 */
2489int
2490xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2491 const xmlChar *ns_uri) {
2492 if (ctxt == NULL)
2493 return(-1);
2494 if (prefix == NULL)
2495 return(-1);
2496
2497 if (ctxt->nsHash == NULL)
2498 ctxt->nsHash = xmlHashCreate(10);
2499 if (ctxt->nsHash == NULL)
2500 return(-1);
2501 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2502 (xmlHashDeallocator)xmlFree));
2503}
2504
2505/**
2506 * xmlXPathNsLookup:
2507 * @ctxt: the XPath context
2508 * @prefix: the namespace prefix value
2509 *
2510 * Search in the namespace declaration array of the context for the given
2511 * namespace name associated to the given prefix
2512 *
2513 * Returns the value or NULL if not found
2514 */
2515const xmlChar *
2516xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2517 if (ctxt == NULL)
2518 return(NULL);
2519 if (prefix == NULL)
2520 return(NULL);
2521
2522#ifdef XML_XML_NAMESPACE
2523 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2524 return(XML_XML_NAMESPACE);
2525#endif
2526
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002527 if (ctxt->namespaces != NULL) {
2528 int i;
2529
2530 for (i = 0;i < ctxt->nsNr;i++) {
2531 if ((ctxt->namespaces[i] != NULL) &&
2532 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2533 return(ctxt->namespaces[i]->href);
2534 }
2535 }
Owen Taylor3473f882001-02-23 17:55:21 +00002536
2537 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2538}
2539
2540/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002541 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002542 * @ctxt: the XPath context
2543 *
2544 * Cleanup the XPath context data associated to registered variables
2545 */
2546void
2547xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2548 if (ctxt == NULL)
2549 return;
2550
2551 xmlHashFree(ctxt->nsHash, NULL);
2552 ctxt->nsHash = NULL;
2553}
2554
2555/************************************************************************
2556 * *
2557 * Routines to handle Values *
2558 * *
2559 ************************************************************************/
2560
2561/* Allocations are terrible, one need to optimize all this !!! */
2562
2563/**
2564 * xmlXPathNewFloat:
2565 * @val: the double value
2566 *
2567 * Create a new xmlXPathObjectPtr of type double and of value @val
2568 *
2569 * Returns the newly created object.
2570 */
2571xmlXPathObjectPtr
2572xmlXPathNewFloat(double val) {
2573 xmlXPathObjectPtr ret;
2574
2575 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2576 if (ret == NULL) {
2577 xmlGenericError(xmlGenericErrorContext,
2578 "xmlXPathNewFloat: out of memory\n");
2579 return(NULL);
2580 }
2581 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2582 ret->type = XPATH_NUMBER;
2583 ret->floatval = val;
2584 return(ret);
2585}
2586
2587/**
2588 * xmlXPathNewBoolean:
2589 * @val: the boolean value
2590 *
2591 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2592 *
2593 * Returns the newly created object.
2594 */
2595xmlXPathObjectPtr
2596xmlXPathNewBoolean(int val) {
2597 xmlXPathObjectPtr ret;
2598
2599 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2600 if (ret == NULL) {
2601 xmlGenericError(xmlGenericErrorContext,
2602 "xmlXPathNewBoolean: out of memory\n");
2603 return(NULL);
2604 }
2605 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2606 ret->type = XPATH_BOOLEAN;
2607 ret->boolval = (val != 0);
2608 return(ret);
2609}
2610
2611/**
2612 * xmlXPathNewString:
2613 * @val: the xmlChar * value
2614 *
2615 * Create a new xmlXPathObjectPtr of type string and of value @val
2616 *
2617 * Returns the newly created object.
2618 */
2619xmlXPathObjectPtr
2620xmlXPathNewString(const xmlChar *val) {
2621 xmlXPathObjectPtr ret;
2622
2623 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2624 if (ret == NULL) {
2625 xmlGenericError(xmlGenericErrorContext,
2626 "xmlXPathNewString: out of memory\n");
2627 return(NULL);
2628 }
2629 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2630 ret->type = XPATH_STRING;
2631 if (val != NULL)
2632 ret->stringval = xmlStrdup(val);
2633 else
2634 ret->stringval = xmlStrdup((const xmlChar *)"");
2635 return(ret);
2636}
2637
2638/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002639 * xmlXPathWrapString:
2640 * @val: the xmlChar * value
2641 *
2642 * Wraps the @val string into an XPath object.
2643 *
2644 * Returns the newly created object.
2645 */
2646xmlXPathObjectPtr
2647xmlXPathWrapString (xmlChar *val) {
2648 xmlXPathObjectPtr ret;
2649
2650 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2651 if (ret == NULL) {
2652 xmlGenericError(xmlGenericErrorContext,
2653 "xmlXPathWrapString: out of memory\n");
2654 return(NULL);
2655 }
2656 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2657 ret->type = XPATH_STRING;
2658 ret->stringval = val;
2659 return(ret);
2660}
2661
2662/**
Owen Taylor3473f882001-02-23 17:55:21 +00002663 * xmlXPathNewCString:
2664 * @val: the char * value
2665 *
2666 * Create a new xmlXPathObjectPtr of type string and of value @val
2667 *
2668 * Returns the newly created object.
2669 */
2670xmlXPathObjectPtr
2671xmlXPathNewCString(const char *val) {
2672 xmlXPathObjectPtr ret;
2673
2674 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2675 if (ret == NULL) {
2676 xmlGenericError(xmlGenericErrorContext,
2677 "xmlXPathNewCString: out of memory\n");
2678 return(NULL);
2679 }
2680 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2681 ret->type = XPATH_STRING;
2682 ret->stringval = xmlStrdup(BAD_CAST val);
2683 return(ret);
2684}
2685
2686/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002687 * xmlXPathWrapCString:
2688 * @val: the char * value
2689 *
2690 * Wraps a string into an XPath object.
2691 *
2692 * Returns the newly created object.
2693 */
2694xmlXPathObjectPtr
2695xmlXPathWrapCString (char * val) {
2696 return(xmlXPathWrapString((xmlChar *)(val)));
2697}
2698
2699/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002700 * xmlXPathWrapExternal:
2701 * @val: the user data
2702 *
2703 * Wraps the @val data into an XPath object.
2704 *
2705 * Returns the newly created object.
2706 */
2707xmlXPathObjectPtr
2708xmlXPathWrapExternal (void *val) {
2709 xmlXPathObjectPtr ret;
2710
2711 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2712 if (ret == NULL) {
2713 xmlGenericError(xmlGenericErrorContext,
2714 "xmlXPathWrapString: out of memory\n");
2715 return(NULL);
2716 }
2717 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2718 ret->type = XPATH_USERS;
2719 ret->user = val;
2720 return(ret);
2721}
2722
2723/**
Owen Taylor3473f882001-02-23 17:55:21 +00002724 * xmlXPathObjectCopy:
2725 * @val: the original object
2726 *
2727 * allocate a new copy of a given object
2728 *
2729 * Returns the newly created object.
2730 */
2731xmlXPathObjectPtr
2732xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2733 xmlXPathObjectPtr ret;
2734
2735 if (val == NULL)
2736 return(NULL);
2737
2738 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2739 if (ret == NULL) {
2740 xmlGenericError(xmlGenericErrorContext,
2741 "xmlXPathObjectCopy: out of memory\n");
2742 return(NULL);
2743 }
2744 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2745 switch (val->type) {
2746 case XPATH_BOOLEAN:
2747 case XPATH_NUMBER:
2748 case XPATH_POINT:
2749 case XPATH_RANGE:
2750 break;
2751 case XPATH_STRING:
2752 ret->stringval = xmlStrdup(val->stringval);
2753 break;
2754 case XPATH_XSLT_TREE:
2755 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002756 (val->nodesetval->nodeTab != NULL)) {
2757 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00002758 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
2759 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002760 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002761 (xmlNodePtr) ret->user);
2762 } else
Owen Taylor3473f882001-02-23 17:55:21 +00002763 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002764 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00002765 break;
2766 case XPATH_NODESET:
2767 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002768 /* Do not deallocate the copied tree value */
2769 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002770 break;
2771 case XPATH_LOCATIONSET:
2772#ifdef LIBXML_XPTR_ENABLED
2773 {
2774 xmlLocationSetPtr loc = val->user;
2775 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2776 break;
2777 }
2778#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00002779 case XPATH_USERS:
2780 ret->user = val->user;
2781 break;
2782 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00002783 xmlGenericError(xmlGenericErrorContext,
2784 "xmlXPathObjectCopy: unsupported type %d\n",
2785 val->type);
2786 break;
2787 }
2788 return(ret);
2789}
2790
2791/**
2792 * xmlXPathFreeObject:
2793 * @obj: the object to free
2794 *
2795 * Free up an xmlXPathObjectPtr object.
2796 */
2797void
2798xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2799 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002800 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00002801 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002802 if (obj->user != NULL) {
2803 xmlFreeNodeList((xmlNodePtr) obj->user);
2804 xmlXPathFreeNodeSet(obj->nodesetval);
2805 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00002806 xmlXPathFreeValueTree(obj->nodesetval);
2807 } else {
2808 if (obj->nodesetval != NULL)
2809 xmlXPathFreeNodeSet(obj->nodesetval);
2810 }
Owen Taylor3473f882001-02-23 17:55:21 +00002811#ifdef LIBXML_XPTR_ENABLED
2812 } else if (obj->type == XPATH_LOCATIONSET) {
2813 if (obj->user != NULL)
2814 xmlXPtrFreeLocationSet(obj->user);
2815#endif
2816 } else if (obj->type == XPATH_STRING) {
2817 if (obj->stringval != NULL)
2818 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00002819 }
2820
Owen Taylor3473f882001-02-23 17:55:21 +00002821 xmlFree(obj);
2822}
2823
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002824
2825/************************************************************************
2826 * *
2827 * Type Casting Routines *
2828 * *
2829 ************************************************************************/
2830
2831/**
2832 * xmlXPathCastBooleanToString:
2833 * @val: a boolean
2834 *
2835 * Converts a boolean to its string value.
2836 *
2837 * Returns a newly allocated string.
2838 */
2839xmlChar *
2840xmlXPathCastBooleanToString (int val) {
2841 xmlChar *ret;
2842 if (val)
2843 ret = xmlStrdup((const xmlChar *) "true");
2844 else
2845 ret = xmlStrdup((const xmlChar *) "false");
2846 return(ret);
2847}
2848
2849/**
2850 * xmlXPathCastNumberToString:
2851 * @val: a number
2852 *
2853 * Converts a number to its string value.
2854 *
2855 * Returns a newly allocated string.
2856 */
2857xmlChar *
2858xmlXPathCastNumberToString (double val) {
2859 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00002860 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002861 case 1:
2862 ret = xmlStrdup((const xmlChar *) "+Infinity");
2863 break;
2864 case -1:
2865 ret = xmlStrdup((const xmlChar *) "-Infinity");
2866 break;
2867 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002868 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002869 ret = xmlStrdup((const xmlChar *) "NaN");
2870 } else {
2871 /* could be improved */
2872 char buf[100];
2873 xmlXPathFormatNumber(val, buf, 100);
2874 ret = xmlStrdup((const xmlChar *) buf);
2875 }
2876 }
2877 return(ret);
2878}
2879
2880/**
2881 * xmlXPathCastNodeToString:
2882 * @node: a node
2883 *
2884 * Converts a node to its string value.
2885 *
2886 * Returns a newly allocated string.
2887 */
2888xmlChar *
2889xmlXPathCastNodeToString (xmlNodePtr node) {
2890 return(xmlNodeGetContent(node));
2891}
2892
2893/**
2894 * xmlXPathCastNodeSetToString:
2895 * @ns: a node-set
2896 *
2897 * Converts a node-set to its string value.
2898 *
2899 * Returns a newly allocated string.
2900 */
2901xmlChar *
2902xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2903 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2904 return(xmlStrdup((const xmlChar *) ""));
2905
2906 xmlXPathNodeSetSort(ns);
2907 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2908}
2909
2910/**
2911 * xmlXPathCastToString:
2912 * @val: an XPath object
2913 *
2914 * Converts an existing object to its string() equivalent
2915 *
2916 * Returns the string value of the object, NULL in case of error.
2917 * A new string is allocated only if needed (val isn't a
2918 * string object).
2919 */
2920xmlChar *
2921xmlXPathCastToString(xmlXPathObjectPtr val) {
2922 xmlChar *ret = NULL;
2923
2924 if (val == NULL)
2925 return(xmlStrdup((const xmlChar *) ""));
2926 switch (val->type) {
2927 case XPATH_UNDEFINED:
2928#ifdef DEBUG_EXPR
2929 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2930#endif
2931 ret = xmlStrdup((const xmlChar *) "");
2932 break;
2933 case XPATH_XSLT_TREE:
2934 case XPATH_NODESET:
2935 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2936 break;
2937 case XPATH_STRING:
2938 return(val->stringval);
2939 case XPATH_BOOLEAN:
2940 ret = xmlXPathCastBooleanToString(val->boolval);
2941 break;
2942 case XPATH_NUMBER: {
2943 ret = xmlXPathCastNumberToString(val->floatval);
2944 break;
2945 }
2946 case XPATH_USERS:
2947 case XPATH_POINT:
2948 case XPATH_RANGE:
2949 case XPATH_LOCATIONSET:
2950 TODO
2951 ret = xmlStrdup((const xmlChar *) "");
2952 break;
2953 }
2954 return(ret);
2955}
2956
2957/**
2958 * xmlXPathConvertString:
2959 * @val: an XPath object
2960 *
2961 * Converts an existing object to its string() equivalent
2962 *
2963 * Returns the new object, the old one is freed (or the operation
2964 * is done directly on @val)
2965 */
2966xmlXPathObjectPtr
2967xmlXPathConvertString(xmlXPathObjectPtr val) {
2968 xmlChar *res = NULL;
2969
2970 if (val == NULL)
2971 return(xmlXPathNewCString(""));
2972
2973 switch (val->type) {
2974 case XPATH_UNDEFINED:
2975#ifdef DEBUG_EXPR
2976 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2977#endif
2978 break;
2979 case XPATH_XSLT_TREE:
2980 case XPATH_NODESET:
2981 res = xmlXPathCastNodeSetToString(val->nodesetval);
2982 break;
2983 case XPATH_STRING:
2984 return(val);
2985 case XPATH_BOOLEAN:
2986 res = xmlXPathCastBooleanToString(val->boolval);
2987 break;
2988 case XPATH_NUMBER:
2989 res = xmlXPathCastNumberToString(val->floatval);
2990 break;
2991 case XPATH_USERS:
2992 case XPATH_POINT:
2993 case XPATH_RANGE:
2994 case XPATH_LOCATIONSET:
2995 TODO;
2996 break;
2997 }
2998 xmlXPathFreeObject(val);
2999 if (res == NULL)
3000 return(xmlXPathNewCString(""));
3001 return(xmlXPathWrapString(res));
3002}
3003
3004/**
3005 * xmlXPathCastBooleanToNumber:
3006 * @val: a boolean
3007 *
3008 * Converts a boolean to its number value
3009 *
3010 * Returns the number value
3011 */
3012double
3013xmlXPathCastBooleanToNumber(int val) {
3014 if (val)
3015 return(1.0);
3016 return(0.0);
3017}
3018
3019/**
3020 * xmlXPathCastStringToNumber:
3021 * @val: a string
3022 *
3023 * Converts a string to its number value
3024 *
3025 * Returns the number value
3026 */
3027double
3028xmlXPathCastStringToNumber(const xmlChar * val) {
3029 return(xmlXPathStringEvalNumber(val));
3030}
3031
3032/**
3033 * xmlXPathCastNodeToNumber:
3034 * @node: a node
3035 *
3036 * Converts a node to its number value
3037 *
3038 * Returns the number value
3039 */
3040double
3041xmlXPathCastNodeToNumber (xmlNodePtr node) {
3042 xmlChar *strval;
3043 double ret;
3044
3045 if (node == NULL)
3046 return(xmlXPathNAN);
3047 strval = xmlXPathCastNodeToString(node);
3048 if (strval == NULL)
3049 return(xmlXPathNAN);
3050 ret = xmlXPathCastStringToNumber(strval);
3051 xmlFree(strval);
3052
3053 return(ret);
3054}
3055
3056/**
3057 * xmlXPathCastNodeSetToNumber:
3058 * @ns: a node-set
3059 *
3060 * Converts a node-set to its number value
3061 *
3062 * Returns the number value
3063 */
3064double
3065xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3066 xmlChar *str;
3067 double ret;
3068
3069 if (ns == NULL)
3070 return(xmlXPathNAN);
3071 str = xmlXPathCastNodeSetToString(ns);
3072 ret = xmlXPathCastStringToNumber(str);
3073 xmlFree(str);
3074 return(ret);
3075}
3076
3077/**
3078 * xmlXPathCastToNumber:
3079 * @val: an XPath object
3080 *
3081 * Converts an XPath object to its number value
3082 *
3083 * Returns the number value
3084 */
3085double
3086xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3087 double ret = 0.0;
3088
3089 if (val == NULL)
3090 return(xmlXPathNAN);
3091 switch (val->type) {
3092 case XPATH_UNDEFINED:
3093#ifdef DEGUB_EXPR
3094 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3095#endif
3096 ret = xmlXPathNAN;
3097 break;
3098 case XPATH_XSLT_TREE:
3099 case XPATH_NODESET:
3100 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3101 break;
3102 case XPATH_STRING:
3103 ret = xmlXPathCastStringToNumber(val->stringval);
3104 break;
3105 case XPATH_NUMBER:
3106 ret = val->floatval;
3107 break;
3108 case XPATH_BOOLEAN:
3109 ret = xmlXPathCastBooleanToNumber(val->boolval);
3110 break;
3111 case XPATH_USERS:
3112 case XPATH_POINT:
3113 case XPATH_RANGE:
3114 case XPATH_LOCATIONSET:
3115 TODO;
3116 ret = xmlXPathNAN;
3117 break;
3118 }
3119 return(ret);
3120}
3121
3122/**
3123 * xmlXPathConvertNumber:
3124 * @val: an XPath object
3125 *
3126 * Converts an existing object to its number() equivalent
3127 *
3128 * Returns the new object, the old one is freed (or the operation
3129 * is done directly on @val)
3130 */
3131xmlXPathObjectPtr
3132xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3133 xmlXPathObjectPtr ret;
3134
3135 if (val == NULL)
3136 return(xmlXPathNewFloat(0.0));
3137 if (val->type == XPATH_NUMBER)
3138 return(val);
3139 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3140 xmlXPathFreeObject(val);
3141 return(ret);
3142}
3143
3144/**
3145 * xmlXPathCastNumberToBoolean:
3146 * @val: a number
3147 *
3148 * Converts a number to its boolean value
3149 *
3150 * Returns the boolean value
3151 */
3152int
3153xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003154 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003155 return(0);
3156 return(1);
3157}
3158
3159/**
3160 * xmlXPathCastStringToBoolean:
3161 * @val: a string
3162 *
3163 * Converts a string to its boolean value
3164 *
3165 * Returns the boolean value
3166 */
3167int
3168xmlXPathCastStringToBoolean (const xmlChar *val) {
3169 if ((val == NULL) || (xmlStrlen(val) == 0))
3170 return(0);
3171 return(1);
3172}
3173
3174/**
3175 * xmlXPathCastNodeSetToBoolean:
3176 * @ns: a node-set
3177 *
3178 * Converts a node-set to its boolean value
3179 *
3180 * Returns the boolean value
3181 */
3182int
3183xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3184 if ((ns == NULL) || (ns->nodeNr == 0))
3185 return(0);
3186 return(1);
3187}
3188
3189/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003190 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003191 * @val: an XPath object
3192 *
3193 * Converts an XPath object to its boolean value
3194 *
3195 * Returns the boolean value
3196 */
3197int
3198xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3199 int ret = 0;
3200
3201 if (val == NULL)
3202 return(0);
3203 switch (val->type) {
3204 case XPATH_UNDEFINED:
3205#ifdef DEBUG_EXPR
3206 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3207#endif
3208 ret = 0;
3209 break;
3210 case XPATH_XSLT_TREE:
3211 case XPATH_NODESET:
3212 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3213 break;
3214 case XPATH_STRING:
3215 ret = xmlXPathCastStringToBoolean(val->stringval);
3216 break;
3217 case XPATH_NUMBER:
3218 ret = xmlXPathCastNumberToBoolean(val->floatval);
3219 break;
3220 case XPATH_BOOLEAN:
3221 ret = val->boolval;
3222 break;
3223 case XPATH_USERS:
3224 case XPATH_POINT:
3225 case XPATH_RANGE:
3226 case XPATH_LOCATIONSET:
3227 TODO;
3228 ret = 0;
3229 break;
3230 }
3231 return(ret);
3232}
3233
3234
3235/**
3236 * xmlXPathConvertBoolean:
3237 * @val: an XPath object
3238 *
3239 * Converts an existing object to its boolean() equivalent
3240 *
3241 * Returns the new object, the old one is freed (or the operation
3242 * is done directly on @val)
3243 */
3244xmlXPathObjectPtr
3245xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3246 xmlXPathObjectPtr ret;
3247
3248 if (val == NULL)
3249 return(xmlXPathNewBoolean(0));
3250 if (val->type == XPATH_BOOLEAN)
3251 return(val);
3252 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3253 xmlXPathFreeObject(val);
3254 return(ret);
3255}
3256
Owen Taylor3473f882001-02-23 17:55:21 +00003257/************************************************************************
3258 * *
3259 * Routines to handle XPath contexts *
3260 * *
3261 ************************************************************************/
3262
3263/**
3264 * xmlXPathNewContext:
3265 * @doc: the XML document
3266 *
3267 * Create a new xmlXPathContext
3268 *
3269 * Returns the xmlXPathContext just allocated.
3270 */
3271xmlXPathContextPtr
3272xmlXPathNewContext(xmlDocPtr doc) {
3273 xmlXPathContextPtr ret;
3274
3275 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3276 if (ret == NULL) {
3277 xmlGenericError(xmlGenericErrorContext,
3278 "xmlXPathNewContext: out of memory\n");
3279 return(NULL);
3280 }
3281 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3282 ret->doc = doc;
3283 ret->node = NULL;
3284
3285 ret->varHash = NULL;
3286
3287 ret->nb_types = 0;
3288 ret->max_types = 0;
3289 ret->types = NULL;
3290
3291 ret->funcHash = xmlHashCreate(0);
3292
3293 ret->nb_axis = 0;
3294 ret->max_axis = 0;
3295 ret->axis = NULL;
3296
3297 ret->nsHash = NULL;
3298 ret->user = NULL;
3299
3300 ret->contextSize = -1;
3301 ret->proximityPosition = -1;
3302
3303 xmlXPathRegisterAllFunctions(ret);
3304
3305 return(ret);
3306}
3307
3308/**
3309 * xmlXPathFreeContext:
3310 * @ctxt: the context to free
3311 *
3312 * Free up an xmlXPathContext
3313 */
3314void
3315xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3316 xmlXPathRegisteredNsCleanup(ctxt);
3317 xmlXPathRegisteredFuncsCleanup(ctxt);
3318 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003319 xmlFree(ctxt);
3320}
3321
3322/************************************************************************
3323 * *
3324 * Routines to handle XPath parser contexts *
3325 * *
3326 ************************************************************************/
3327
3328#define CHECK_CTXT(ctxt) \
3329 if (ctxt == NULL) { \
3330 xmlGenericError(xmlGenericErrorContext, \
3331 "%s:%d Internal error: ctxt == NULL\n", \
3332 __FILE__, __LINE__); \
3333 } \
3334
3335
3336#define CHECK_CONTEXT(ctxt) \
3337 if (ctxt == NULL) { \
3338 xmlGenericError(xmlGenericErrorContext, \
3339 "%s:%d Internal error: no context\n", \
3340 __FILE__, __LINE__); \
3341 } \
3342 else if (ctxt->doc == NULL) { \
3343 xmlGenericError(xmlGenericErrorContext, \
3344 "%s:%d Internal error: no document\n", \
3345 __FILE__, __LINE__); \
3346 } \
3347 else if (ctxt->doc->children == NULL) { \
3348 xmlGenericError(xmlGenericErrorContext, \
3349 "%s:%d Internal error: document without root\n", \
3350 __FILE__, __LINE__); \
3351 } \
3352
3353
3354/**
3355 * xmlXPathNewParserContext:
3356 * @str: the XPath expression
3357 * @ctxt: the XPath context
3358 *
3359 * Create a new xmlXPathParserContext
3360 *
3361 * Returns the xmlXPathParserContext just allocated.
3362 */
3363xmlXPathParserContextPtr
3364xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3365 xmlXPathParserContextPtr ret;
3366
3367 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3368 if (ret == NULL) {
3369 xmlGenericError(xmlGenericErrorContext,
3370 "xmlXPathNewParserContext: out of memory\n");
3371 return(NULL);
3372 }
3373 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3374 ret->cur = ret->base = str;
3375 ret->context = ctxt;
3376
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003377 ret->comp = xmlXPathNewCompExpr();
3378 if (ret->comp == NULL) {
3379 xmlFree(ret->valueTab);
3380 xmlFree(ret);
3381 return(NULL);
3382 }
3383
3384 return(ret);
3385}
3386
3387/**
3388 * xmlXPathCompParserContext:
3389 * @comp: the XPath compiled expression
3390 * @ctxt: the XPath context
3391 *
3392 * Create a new xmlXPathParserContext when processing a compiled expression
3393 *
3394 * Returns the xmlXPathParserContext just allocated.
3395 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003396static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003397xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3398 xmlXPathParserContextPtr ret;
3399
3400 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3401 if (ret == NULL) {
3402 xmlGenericError(xmlGenericErrorContext,
3403 "xmlXPathNewParserContext: out of memory\n");
3404 return(NULL);
3405 }
3406 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3407
Owen Taylor3473f882001-02-23 17:55:21 +00003408 /* Allocate the value stack */
3409 ret->valueTab = (xmlXPathObjectPtr *)
3410 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003411 if (ret->valueTab == NULL) {
3412 xmlFree(ret);
3413 xmlGenericError(xmlGenericErrorContext,
3414 "xmlXPathNewParserContext: out of memory\n");
3415 return(NULL);
3416 }
Owen Taylor3473f882001-02-23 17:55:21 +00003417 ret->valueNr = 0;
3418 ret->valueMax = 10;
3419 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003420
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003421 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003422 ret->comp = comp;
3423
Owen Taylor3473f882001-02-23 17:55:21 +00003424 return(ret);
3425}
3426
3427/**
3428 * xmlXPathFreeParserContext:
3429 * @ctxt: the context to free
3430 *
3431 * Free up an xmlXPathParserContext
3432 */
3433void
3434xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3435 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003436 xmlFree(ctxt->valueTab);
3437 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003438 if (ctxt->comp)
3439 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003440 xmlFree(ctxt);
3441}
3442
3443/************************************************************************
3444 * *
3445 * The implicit core function library *
3446 * *
3447 ************************************************************************/
3448
Owen Taylor3473f882001-02-23 17:55:21 +00003449/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003450 * xmlXPathNodeStringHash:
3451 * @node: a node pointer
3452 *
3453 * Function computing the beginning of the string value of the node,
3454 * used to speed up comparisons
3455 *
3456 * Returns an int usable as a hash
3457 */
3458static unsigned int
3459xmlXPathNodeValHash(xmlNodePtr node) {
3460 int len = 2;
3461 const xmlChar * string = NULL;
3462 xmlNodePtr tmp = NULL;
3463 unsigned int ret = 0;
3464
3465 if (node == NULL)
3466 return(0);
3467
3468
3469 switch (node->type) {
3470 case XML_COMMENT_NODE:
3471 case XML_PI_NODE:
3472 case XML_CDATA_SECTION_NODE:
3473 case XML_TEXT_NODE:
3474 string = node->content;
3475 if (string == NULL)
3476 return(0);
3477 if (string[0] == 0)
3478 return(0);
3479 return(((unsigned int) string[0]) +
3480 (((unsigned int) string[1]) << 8));
3481 case XML_NAMESPACE_DECL:
3482 string = ((xmlNsPtr)node)->href;
3483 if (string == NULL)
3484 return(0);
3485 if (string[0] == 0)
3486 return(0);
3487 return(((unsigned int) string[0]) +
3488 (((unsigned int) string[1]) << 8));
3489 case XML_ATTRIBUTE_NODE:
3490 tmp = ((xmlAttrPtr) node)->children;
3491 break;
3492 case XML_ELEMENT_NODE:
3493 tmp = node->children;
3494 break;
3495 default:
3496 return(0);
3497 }
3498 while (tmp != NULL) {
3499 switch (tmp->type) {
3500 case XML_COMMENT_NODE:
3501 case XML_PI_NODE:
3502 case XML_CDATA_SECTION_NODE:
3503 case XML_TEXT_NODE:
3504 string = tmp->content;
3505 break;
3506 case XML_NAMESPACE_DECL:
3507 string = ((xmlNsPtr)tmp)->href;
3508 break;
3509 default:
3510 break;
3511 }
3512 if ((string != NULL) && (string[0] != 0)) {
3513 if (string[0] == 0)
3514 return(0);
3515 if (len == 1) {
3516 return(ret + (((unsigned int) string[0]) << 8));
3517 }
3518 if (string[1] == 0) {
3519 len = 1;
3520 ret = (unsigned int) string[0];
3521 } else {
3522 return(((unsigned int) string[0]) +
3523 (((unsigned int) string[1]) << 8));
3524 }
3525 }
3526 /*
3527 * Skip to next node
3528 */
3529 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3530 if (tmp->children->type != XML_ENTITY_DECL) {
3531 tmp = tmp->children;
3532 continue;
3533 }
3534 }
3535 if (tmp == node)
3536 break;
3537
3538 if (tmp->next != NULL) {
3539 tmp = tmp->next;
3540 continue;
3541 }
3542
3543 do {
3544 tmp = tmp->parent;
3545 if (tmp == NULL)
3546 break;
3547 if (tmp == node) {
3548 tmp = NULL;
3549 break;
3550 }
3551 if (tmp->next != NULL) {
3552 tmp = tmp->next;
3553 break;
3554 }
3555 } while (tmp != NULL);
3556 }
3557 return(ret);
3558}
3559
3560/**
3561 * xmlXPathStringHash:
3562 * @string: a string
3563 *
3564 * Function computing the beginning of the string value of the node,
3565 * used to speed up comparisons
3566 *
3567 * Returns an int usable as a hash
3568 */
3569static unsigned int
3570xmlXPathStringHash(const xmlChar * string) {
3571 if (string == NULL)
3572 return((unsigned int) 0);
3573 if (string[0] == 0)
3574 return(0);
3575 return(((unsigned int) string[0]) +
3576 (((unsigned int) string[1]) << 8));
3577}
3578
3579/**
Owen Taylor3473f882001-02-23 17:55:21 +00003580 * xmlXPathCompareNodeSetFloat:
3581 * @ctxt: the XPath Parser context
3582 * @inf: less than (1) or greater than (0)
3583 * @strict: is the comparison strict
3584 * @arg: the node set
3585 * @f: the value
3586 *
3587 * Implement the compare operation between a nodeset and a number
3588 * @ns < @val (1, 1, ...
3589 * @ns <= @val (1, 0, ...
3590 * @ns > @val (0, 1, ...
3591 * @ns >= @val (0, 0, ...
3592 *
3593 * If one object to be compared is a node-set and the other is a number,
3594 * then the comparison will be true if and only if there is a node in the
3595 * node-set such that the result of performing the comparison on the number
3596 * to be compared and on the result of converting the string-value of that
3597 * node to a number using the number function is true.
3598 *
3599 * Returns 0 or 1 depending on the results of the test.
3600 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003601static int
Owen Taylor3473f882001-02-23 17:55:21 +00003602xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3603 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3604 int i, ret = 0;
3605 xmlNodeSetPtr ns;
3606 xmlChar *str2;
3607
3608 if ((f == NULL) || (arg == NULL) ||
3609 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3610 xmlXPathFreeObject(arg);
3611 xmlXPathFreeObject(f);
3612 return(0);
3613 }
3614 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003615 if (ns != NULL) {
3616 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003617 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003618 if (str2 != NULL) {
3619 valuePush(ctxt,
3620 xmlXPathNewString(str2));
3621 xmlFree(str2);
3622 xmlXPathNumberFunction(ctxt, 1);
3623 valuePush(ctxt, xmlXPathObjectCopy(f));
3624 ret = xmlXPathCompareValues(ctxt, inf, strict);
3625 if (ret)
3626 break;
3627 }
3628 }
Owen Taylor3473f882001-02-23 17:55:21 +00003629 }
3630 xmlXPathFreeObject(arg);
3631 xmlXPathFreeObject(f);
3632 return(ret);
3633}
3634
3635/**
3636 * xmlXPathCompareNodeSetString:
3637 * @ctxt: the XPath Parser context
3638 * @inf: less than (1) or greater than (0)
3639 * @strict: is the comparison strict
3640 * @arg: the node set
3641 * @s: the value
3642 *
3643 * Implement the compare operation between a nodeset and a string
3644 * @ns < @val (1, 1, ...
3645 * @ns <= @val (1, 0, ...
3646 * @ns > @val (0, 1, ...
3647 * @ns >= @val (0, 0, ...
3648 *
3649 * If one object to be compared is a node-set and the other is a string,
3650 * then the comparison will be true if and only if there is a node in
3651 * the node-set such that the result of performing the comparison on the
3652 * string-value of the node and the other string is true.
3653 *
3654 * Returns 0 or 1 depending on the results of the test.
3655 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003656static int
Owen Taylor3473f882001-02-23 17:55:21 +00003657xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3658 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3659 int i, ret = 0;
3660 xmlNodeSetPtr ns;
3661 xmlChar *str2;
3662
3663 if ((s == NULL) || (arg == NULL) ||
3664 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3665 xmlXPathFreeObject(arg);
3666 xmlXPathFreeObject(s);
3667 return(0);
3668 }
3669 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003670 if (ns != NULL) {
3671 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003672 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003673 if (str2 != NULL) {
3674 valuePush(ctxt,
3675 xmlXPathNewString(str2));
3676 xmlFree(str2);
3677 valuePush(ctxt, xmlXPathObjectCopy(s));
3678 ret = xmlXPathCompareValues(ctxt, inf, strict);
3679 if (ret)
3680 break;
3681 }
3682 }
Owen Taylor3473f882001-02-23 17:55:21 +00003683 }
3684 xmlXPathFreeObject(arg);
3685 xmlXPathFreeObject(s);
3686 return(ret);
3687}
3688
3689/**
3690 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003691 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003692 * @strict: is the comparison strict
3693 * @arg1: the fist node set object
3694 * @arg2: the second node set object
3695 *
3696 * Implement the compare operation on nodesets:
3697 *
3698 * If both objects to be compared are node-sets, then the comparison
3699 * will be true if and only if there is a node in the first node-set
3700 * and a node in the second node-set such that the result of performing
3701 * the comparison on the string-values of the two nodes is true.
3702 * ....
3703 * When neither object to be compared is a node-set and the operator
3704 * is <=, <, >= or >, then the objects are compared by converting both
3705 * objects to numbers and comparing the numbers according to IEEE 754.
3706 * ....
3707 * The number function converts its argument to a number as follows:
3708 * - a string that consists of optional whitespace followed by an
3709 * optional minus sign followed by a Number followed by whitespace
3710 * is converted to the IEEE 754 number that is nearest (according
3711 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3712 * represented by the string; any other string is converted to NaN
3713 *
3714 * Conclusion all nodes need to be converted first to their string value
3715 * and then the comparison must be done when possible
3716 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003717static int
3718xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003719 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3720 int i, j, init = 0;
3721 double val1;
3722 double *values2;
3723 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003724 xmlNodeSetPtr ns1;
3725 xmlNodeSetPtr ns2;
3726
3727 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003728 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3729 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003730 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003731 }
Owen Taylor3473f882001-02-23 17:55:21 +00003732 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003733 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3734 xmlXPathFreeObject(arg1);
3735 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003736 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003737 }
Owen Taylor3473f882001-02-23 17:55:21 +00003738
3739 ns1 = arg1->nodesetval;
3740 ns2 = arg2->nodesetval;
3741
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003742 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003743 xmlXPathFreeObject(arg1);
3744 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003745 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003746 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003747 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003748 xmlXPathFreeObject(arg1);
3749 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003750 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003751 }
Owen Taylor3473f882001-02-23 17:55:21 +00003752
3753 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3754 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003755 xmlXPathFreeObject(arg1);
3756 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003757 return(0);
3758 }
3759 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003760 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00003761 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00003762 continue;
3763 for (j = 0;j < ns2->nodeNr;j++) {
3764 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003765 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003766 }
Daniel Veillardcda96922001-08-21 10:56:31 +00003767 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00003768 continue;
3769 if (inf && strict)
3770 ret = (val1 < values2[j]);
3771 else if (inf && !strict)
3772 ret = (val1 <= values2[j]);
3773 else if (!inf && strict)
3774 ret = (val1 > values2[j]);
3775 else if (!inf && !strict)
3776 ret = (val1 >= values2[j]);
3777 if (ret)
3778 break;
3779 }
3780 if (ret)
3781 break;
3782 init = 1;
3783 }
3784 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003785 xmlXPathFreeObject(arg1);
3786 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003787 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003788}
3789
3790/**
3791 * xmlXPathCompareNodeSetValue:
3792 * @ctxt: the XPath Parser context
3793 * @inf: less than (1) or greater than (0)
3794 * @strict: is the comparison strict
3795 * @arg: the node set
3796 * @val: the value
3797 *
3798 * Implement the compare operation between a nodeset and a value
3799 * @ns < @val (1, 1, ...
3800 * @ns <= @val (1, 0, ...
3801 * @ns > @val (0, 1, ...
3802 * @ns >= @val (0, 0, ...
3803 *
3804 * If one object to be compared is a node-set and the other is a boolean,
3805 * then the comparison will be true if and only if the result of performing
3806 * the comparison on the boolean and on the result of converting
3807 * the node-set to a boolean using the boolean function is true.
3808 *
3809 * Returns 0 or 1 depending on the results of the test.
3810 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003811static int
Owen Taylor3473f882001-02-23 17:55:21 +00003812xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3813 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3814 if ((val == NULL) || (arg == NULL) ||
3815 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3816 return(0);
3817
3818 switch(val->type) {
3819 case XPATH_NUMBER:
3820 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3821 case XPATH_NODESET:
3822 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003823 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003824 case XPATH_STRING:
3825 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3826 case XPATH_BOOLEAN:
3827 valuePush(ctxt, arg);
3828 xmlXPathBooleanFunction(ctxt, 1);
3829 valuePush(ctxt, val);
3830 return(xmlXPathCompareValues(ctxt, inf, strict));
3831 default:
3832 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00003833 }
3834 return(0);
3835}
3836
3837/**
3838 * xmlXPathEqualNodeSetString
3839 * @arg: the nodeset object argument
3840 * @str: the string to compare to.
3841 *
3842 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3843 * If one object to be compared is a node-set and the other is a string,
3844 * then the comparison will be true if and only if there is a node in
3845 * the node-set such that the result of performing the comparison on the
3846 * string-value of the node and the other string is true.
3847 *
3848 * Returns 0 or 1 depending on the results of the test.
3849 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003850static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003851xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3852{
Owen Taylor3473f882001-02-23 17:55:21 +00003853 int i;
3854 xmlNodeSetPtr ns;
3855 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003856 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003857
3858 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003859 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3860 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003861 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003862 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003863 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003864 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003865 if (ns->nodeNr <= 0) {
3866 if (hash == 0)
3867 return(1);
3868 return(0);
3869 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003870 for (i = 0; i < ns->nodeNr; i++) {
3871 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3872 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3873 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3874 xmlFree(str2);
3875 return (1);
3876 }
3877 if (str2 != NULL)
3878 xmlFree(str2);
3879 }
Owen Taylor3473f882001-02-23 17:55:21 +00003880 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003881 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003882}
3883
3884/**
3885 * xmlXPathEqualNodeSetFloat
3886 * @arg: the nodeset object argument
3887 * @f: the float to compare to
3888 *
3889 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3890 * If one object to be compared is a node-set and the other is a number,
3891 * then the comparison will be true if and only if there is a node in
3892 * the node-set such that the result of performing the comparison on the
3893 * number to be compared and on the result of converting the string-value
3894 * of that node to a number using the number function is true.
3895 *
3896 * Returns 0 or 1 depending on the results of the test.
3897 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003898static int
Owen Taylor3473f882001-02-23 17:55:21 +00003899xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3900 char buf[100] = "";
3901
3902 if ((arg == NULL) ||
3903 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3904 return(0);
3905
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003906 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003907 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3908}
3909
3910
3911/**
3912 * xmlXPathEqualNodeSets
3913 * @arg1: first nodeset object argument
3914 * @arg2: second nodeset object argument
3915 *
3916 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3917 * If both objects to be compared are node-sets, then the comparison
3918 * will be true if and only if there is a node in the first node-set and
3919 * a node in the second node-set such that the result of performing the
3920 * comparison on the string-values of the two nodes is true.
3921 *
3922 * (needless to say, this is a costly operation)
3923 *
3924 * Returns 0 or 1 depending on the results of the test.
3925 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003926static int
Owen Taylor3473f882001-02-23 17:55:21 +00003927xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3928 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003929 unsigned int *hashs1;
3930 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003931 xmlChar **values1;
3932 xmlChar **values2;
3933 int ret = 0;
3934 xmlNodeSetPtr ns1;
3935 xmlNodeSetPtr ns2;
3936
3937 if ((arg1 == NULL) ||
3938 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3939 return(0);
3940 if ((arg2 == NULL) ||
3941 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3942 return(0);
3943
3944 ns1 = arg1->nodesetval;
3945 ns2 = arg2->nodesetval;
3946
Daniel Veillard911f49a2001-04-07 15:39:35 +00003947 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003948 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003949 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003950 return(0);
3951
3952 /*
3953 * check if there is a node pertaining to both sets
3954 */
3955 for (i = 0;i < ns1->nodeNr;i++)
3956 for (j = 0;j < ns2->nodeNr;j++)
3957 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3958 return(1);
3959
3960 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3961 if (values1 == NULL)
3962 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003963 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3964 if (hashs1 == NULL) {
3965 xmlFree(values1);
3966 return(0);
3967 }
Owen Taylor3473f882001-02-23 17:55:21 +00003968 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3969 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3970 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003971 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003972 xmlFree(values1);
3973 return(0);
3974 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003975 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3976 if (hashs2 == NULL) {
3977 xmlFree(hashs1);
3978 xmlFree(values1);
3979 xmlFree(values2);
3980 return(0);
3981 }
Owen Taylor3473f882001-02-23 17:55:21 +00003982 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3983 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003984 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003985 for (j = 0;j < ns2->nodeNr;j++) {
3986 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003987 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
3988 if (hashs1[i] == hashs2[j]) {
3989 if (values1[i] == NULL)
3990 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3991 if (values2[j] == NULL)
3992 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3993 ret = xmlStrEqual(values1[i], values2[j]);
3994 if (ret)
3995 break;
3996 }
Owen Taylor3473f882001-02-23 17:55:21 +00003997 }
3998 if (ret)
3999 break;
4000 }
4001 for (i = 0;i < ns1->nodeNr;i++)
4002 if (values1[i] != NULL)
4003 xmlFree(values1[i]);
4004 for (j = 0;j < ns2->nodeNr;j++)
4005 if (values2[j] != NULL)
4006 xmlFree(values2[j]);
4007 xmlFree(values1);
4008 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004009 xmlFree(hashs1);
4010 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004011 return(ret);
4012}
4013
4014/**
4015 * xmlXPathEqualValues:
4016 * @ctxt: the XPath Parser context
4017 *
4018 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4019 *
4020 * Returns 0 or 1 depending on the results of the test.
4021 */
4022int
4023xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4024 xmlXPathObjectPtr arg1, arg2;
4025 int ret = 0;
4026
4027 arg1 = valuePop(ctxt);
4028 if (arg1 == NULL)
4029 XP_ERROR0(XPATH_INVALID_OPERAND);
4030
4031 arg2 = valuePop(ctxt);
4032 if (arg2 == NULL) {
4033 xmlXPathFreeObject(arg1);
4034 XP_ERROR0(XPATH_INVALID_OPERAND);
4035 }
4036
4037 if (arg1 == arg2) {
4038#ifdef DEBUG_EXPR
4039 xmlGenericError(xmlGenericErrorContext,
4040 "Equal: by pointer\n");
4041#endif
4042 return(1);
4043 }
4044
4045 switch (arg1->type) {
4046 case XPATH_UNDEFINED:
4047#ifdef DEBUG_EXPR
4048 xmlGenericError(xmlGenericErrorContext,
4049 "Equal: undefined\n");
4050#endif
4051 break;
4052 case XPATH_XSLT_TREE:
4053 case XPATH_NODESET:
4054 switch (arg2->type) {
4055 case XPATH_UNDEFINED:
4056#ifdef DEBUG_EXPR
4057 xmlGenericError(xmlGenericErrorContext,
4058 "Equal: undefined\n");
4059#endif
4060 break;
4061 case XPATH_XSLT_TREE:
4062 case XPATH_NODESET:
4063 ret = xmlXPathEqualNodeSets(arg1, arg2);
4064 break;
4065 case XPATH_BOOLEAN:
4066 if ((arg1->nodesetval == NULL) ||
4067 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4068 else
4069 ret = 1;
4070 ret = (ret == arg2->boolval);
4071 break;
4072 case XPATH_NUMBER:
4073 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4074 break;
4075 case XPATH_STRING:
4076 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4077 break;
4078 case XPATH_USERS:
4079 case XPATH_POINT:
4080 case XPATH_RANGE:
4081 case XPATH_LOCATIONSET:
4082 TODO
4083 break;
4084 }
4085 break;
4086 case XPATH_BOOLEAN:
4087 switch (arg2->type) {
4088 case XPATH_UNDEFINED:
4089#ifdef DEBUG_EXPR
4090 xmlGenericError(xmlGenericErrorContext,
4091 "Equal: undefined\n");
4092#endif
4093 break;
4094 case XPATH_NODESET:
4095 case XPATH_XSLT_TREE:
4096 if ((arg2->nodesetval == NULL) ||
4097 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4098 else
4099 ret = 1;
4100 break;
4101 case XPATH_BOOLEAN:
4102#ifdef DEBUG_EXPR
4103 xmlGenericError(xmlGenericErrorContext,
4104 "Equal: %d boolean %d \n",
4105 arg1->boolval, arg2->boolval);
4106#endif
4107 ret = (arg1->boolval == arg2->boolval);
4108 break;
4109 case XPATH_NUMBER:
4110 if (arg2->floatval) ret = 1;
4111 else ret = 0;
4112 ret = (arg1->boolval == ret);
4113 break;
4114 case XPATH_STRING:
4115 if ((arg2->stringval == NULL) ||
4116 (arg2->stringval[0] == 0)) ret = 0;
4117 else
4118 ret = 1;
4119 ret = (arg1->boolval == ret);
4120 break;
4121 case XPATH_USERS:
4122 case XPATH_POINT:
4123 case XPATH_RANGE:
4124 case XPATH_LOCATIONSET:
4125 TODO
4126 break;
4127 }
4128 break;
4129 case XPATH_NUMBER:
4130 switch (arg2->type) {
4131 case XPATH_UNDEFINED:
4132#ifdef DEBUG_EXPR
4133 xmlGenericError(xmlGenericErrorContext,
4134 "Equal: undefined\n");
4135#endif
4136 break;
4137 case XPATH_NODESET:
4138 case XPATH_XSLT_TREE:
4139 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4140 break;
4141 case XPATH_BOOLEAN:
4142 if (arg1->floatval) ret = 1;
4143 else ret = 0;
4144 ret = (arg2->boolval == ret);
4145 break;
4146 case XPATH_STRING:
4147 valuePush(ctxt, arg2);
4148 xmlXPathNumberFunction(ctxt, 1);
4149 arg2 = valuePop(ctxt);
4150 /* no break on purpose */
4151 case XPATH_NUMBER:
4152 ret = (arg1->floatval == arg2->floatval);
4153 break;
4154 case XPATH_USERS:
4155 case XPATH_POINT:
4156 case XPATH_RANGE:
4157 case XPATH_LOCATIONSET:
4158 TODO
4159 break;
4160 }
4161 break;
4162 case XPATH_STRING:
4163 switch (arg2->type) {
4164 case XPATH_UNDEFINED:
4165#ifdef DEBUG_EXPR
4166 xmlGenericError(xmlGenericErrorContext,
4167 "Equal: undefined\n");
4168#endif
4169 break;
4170 case XPATH_NODESET:
4171 case XPATH_XSLT_TREE:
4172 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4173 break;
4174 case XPATH_BOOLEAN:
4175 if ((arg1->stringval == NULL) ||
4176 (arg1->stringval[0] == 0)) ret = 0;
4177 else
4178 ret = 1;
4179 ret = (arg2->boolval == ret);
4180 break;
4181 case XPATH_STRING:
4182 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4183 break;
4184 case XPATH_NUMBER:
4185 valuePush(ctxt, arg1);
4186 xmlXPathNumberFunction(ctxt, 1);
4187 arg1 = valuePop(ctxt);
4188 ret = (arg1->floatval == arg2->floatval);
4189 break;
4190 case XPATH_USERS:
4191 case XPATH_POINT:
4192 case XPATH_RANGE:
4193 case XPATH_LOCATIONSET:
4194 TODO
4195 break;
4196 }
4197 break;
4198 case XPATH_USERS:
4199 case XPATH_POINT:
4200 case XPATH_RANGE:
4201 case XPATH_LOCATIONSET:
4202 TODO
4203 break;
4204 }
4205 xmlXPathFreeObject(arg1);
4206 xmlXPathFreeObject(arg2);
4207 return(ret);
4208}
4209
4210
4211/**
4212 * xmlXPathCompareValues:
4213 * @ctxt: the XPath Parser context
4214 * @inf: less than (1) or greater than (0)
4215 * @strict: is the comparison strict
4216 *
4217 * Implement the compare operation on XPath objects:
4218 * @arg1 < @arg2 (1, 1, ...
4219 * @arg1 <= @arg2 (1, 0, ...
4220 * @arg1 > @arg2 (0, 1, ...
4221 * @arg1 >= @arg2 (0, 0, ...
4222 *
4223 * When neither object to be compared is a node-set and the operator is
4224 * <=, <, >=, >, then the objects are compared by converted both objects
4225 * to numbers and comparing the numbers according to IEEE 754. The <
4226 * comparison will be true if and only if the first number is less than the
4227 * second number. The <= comparison will be true if and only if the first
4228 * number is less than or equal to the second number. The > comparison
4229 * will be true if and only if the first number is greater than the second
4230 * number. The >= comparison will be true if and only if the first number
4231 * is greater than or equal to the second number.
4232 *
4233 * Returns 1 if the comparaison succeeded, 0 if it failed
4234 */
4235int
4236xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4237 int ret = 0;
4238 xmlXPathObjectPtr arg1, arg2;
4239
4240 arg2 = valuePop(ctxt);
4241 if (arg2 == NULL) {
4242 XP_ERROR0(XPATH_INVALID_OPERAND);
4243 }
4244
4245 arg1 = valuePop(ctxt);
4246 if (arg1 == NULL) {
4247 xmlXPathFreeObject(arg2);
4248 XP_ERROR0(XPATH_INVALID_OPERAND);
4249 }
4250
4251 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4252 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004253 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004254 } else {
4255 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004256 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4257 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004258 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004259 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4260 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004261 }
4262 }
4263 return(ret);
4264 }
4265
4266 if (arg1->type != XPATH_NUMBER) {
4267 valuePush(ctxt, arg1);
4268 xmlXPathNumberFunction(ctxt, 1);
4269 arg1 = valuePop(ctxt);
4270 }
4271 if (arg1->type != XPATH_NUMBER) {
4272 xmlXPathFreeObject(arg1);
4273 xmlXPathFreeObject(arg2);
4274 XP_ERROR0(XPATH_INVALID_OPERAND);
4275 }
4276 if (arg2->type != XPATH_NUMBER) {
4277 valuePush(ctxt, arg2);
4278 xmlXPathNumberFunction(ctxt, 1);
4279 arg2 = valuePop(ctxt);
4280 }
4281 if (arg2->type != XPATH_NUMBER) {
4282 xmlXPathFreeObject(arg1);
4283 xmlXPathFreeObject(arg2);
4284 XP_ERROR0(XPATH_INVALID_OPERAND);
4285 }
4286 /*
4287 * Add tests for infinity and nan
4288 * => feedback on 3.4 for Inf and NaN
4289 */
4290 if (inf && strict)
4291 ret = (arg1->floatval < arg2->floatval);
4292 else if (inf && !strict)
4293 ret = (arg1->floatval <= arg2->floatval);
4294 else if (!inf && strict)
4295 ret = (arg1->floatval > arg2->floatval);
4296 else if (!inf && !strict)
4297 ret = (arg1->floatval >= arg2->floatval);
4298 xmlXPathFreeObject(arg1);
4299 xmlXPathFreeObject(arg2);
4300 return(ret);
4301}
4302
4303/**
4304 * xmlXPathValueFlipSign:
4305 * @ctxt: the XPath Parser context
4306 *
4307 * Implement the unary - operation on an XPath object
4308 * The numeric operators convert their operands to numbers as if
4309 * by calling the number function.
4310 */
4311void
4312xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004313 CAST_TO_NUMBER;
4314 CHECK_TYPE(XPATH_NUMBER);
4315 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004316}
4317
4318/**
4319 * xmlXPathAddValues:
4320 * @ctxt: the XPath Parser context
4321 *
4322 * Implement the add operation on XPath objects:
4323 * The numeric operators convert their operands to numbers as if
4324 * by calling the number function.
4325 */
4326void
4327xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4328 xmlXPathObjectPtr arg;
4329 double val;
4330
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004331 arg = valuePop(ctxt);
4332 if (arg == NULL)
4333 XP_ERROR(XPATH_INVALID_OPERAND);
4334 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004335 xmlXPathFreeObject(arg);
4336
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004337 CAST_TO_NUMBER;
4338 CHECK_TYPE(XPATH_NUMBER);
4339 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004340}
4341
4342/**
4343 * xmlXPathSubValues:
4344 * @ctxt: the XPath Parser context
4345 *
4346 * Implement the substraction operation on XPath objects:
4347 * The numeric operators convert their operands to numbers as if
4348 * by calling the number function.
4349 */
4350void
4351xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4352 xmlXPathObjectPtr arg;
4353 double val;
4354
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004355 arg = valuePop(ctxt);
4356 if (arg == NULL)
4357 XP_ERROR(XPATH_INVALID_OPERAND);
4358 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004359 xmlXPathFreeObject(arg);
4360
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004361 CAST_TO_NUMBER;
4362 CHECK_TYPE(XPATH_NUMBER);
4363 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004364}
4365
4366/**
4367 * xmlXPathMultValues:
4368 * @ctxt: the XPath Parser context
4369 *
4370 * Implement the multiply operation on XPath objects:
4371 * The numeric operators convert their operands to numbers as if
4372 * by calling the number function.
4373 */
4374void
4375xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4376 xmlXPathObjectPtr arg;
4377 double val;
4378
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004379 arg = valuePop(ctxt);
4380 if (arg == NULL)
4381 XP_ERROR(XPATH_INVALID_OPERAND);
4382 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004383 xmlXPathFreeObject(arg);
4384
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004385 CAST_TO_NUMBER;
4386 CHECK_TYPE(XPATH_NUMBER);
4387 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004388}
4389
4390/**
4391 * xmlXPathDivValues:
4392 * @ctxt: the XPath Parser context
4393 *
4394 * Implement the div operation on XPath objects @arg1 / @arg2:
4395 * The numeric operators convert their operands to numbers as if
4396 * by calling the number function.
4397 */
4398void
4399xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4400 xmlXPathObjectPtr arg;
4401 double val;
4402
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004403 arg = valuePop(ctxt);
4404 if (arg == NULL)
4405 XP_ERROR(XPATH_INVALID_OPERAND);
4406 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004407 xmlXPathFreeObject(arg);
4408
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004409 CAST_TO_NUMBER;
4410 CHECK_TYPE(XPATH_NUMBER);
4411 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004412}
4413
4414/**
4415 * xmlXPathModValues:
4416 * @ctxt: the XPath Parser context
4417 *
4418 * Implement the mod operation on XPath objects: @arg1 / @arg2
4419 * The numeric operators convert their operands to numbers as if
4420 * by calling the number function.
4421 */
4422void
4423xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4424 xmlXPathObjectPtr arg;
4425 int arg1, arg2;
4426
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004427 arg = valuePop(ctxt);
4428 if (arg == NULL)
4429 XP_ERROR(XPATH_INVALID_OPERAND);
4430 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004431 xmlXPathFreeObject(arg);
4432
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004433 CAST_TO_NUMBER;
4434 CHECK_TYPE(XPATH_NUMBER);
4435 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004436 if (arg2 == 0)
4437 ctxt->value->floatval = xmlXPathNAN;
4438 else
4439 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004440}
4441
4442/************************************************************************
4443 * *
4444 * The traversal functions *
4445 * *
4446 ************************************************************************/
4447
Owen Taylor3473f882001-02-23 17:55:21 +00004448/*
4449 * A traversal function enumerates nodes along an axis.
4450 * Initially it must be called with NULL, and it indicates
4451 * termination on the axis by returning NULL.
4452 */
4453typedef xmlNodePtr (*xmlXPathTraversalFunction)
4454 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4455
4456/**
4457 * xmlXPathNextSelf:
4458 * @ctxt: the XPath Parser context
4459 * @cur: the current node in the traversal
4460 *
4461 * Traversal function for the "self" direction
4462 * The self axis contains just the context node itself
4463 *
4464 * Returns the next element following that axis
4465 */
4466xmlNodePtr
4467xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4468 if (cur == NULL)
4469 return(ctxt->context->node);
4470 return(NULL);
4471}
4472
4473/**
4474 * xmlXPathNextChild:
4475 * @ctxt: the XPath Parser context
4476 * @cur: the current node in the traversal
4477 *
4478 * Traversal function for the "child" direction
4479 * The child axis contains the children of the context node in document order.
4480 *
4481 * Returns the next element following that axis
4482 */
4483xmlNodePtr
4484xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4485 if (cur == NULL) {
4486 if (ctxt->context->node == NULL) return(NULL);
4487 switch (ctxt->context->node->type) {
4488 case XML_ELEMENT_NODE:
4489 case XML_TEXT_NODE:
4490 case XML_CDATA_SECTION_NODE:
4491 case XML_ENTITY_REF_NODE:
4492 case XML_ENTITY_NODE:
4493 case XML_PI_NODE:
4494 case XML_COMMENT_NODE:
4495 case XML_NOTATION_NODE:
4496 case XML_DTD_NODE:
4497 return(ctxt->context->node->children);
4498 case XML_DOCUMENT_NODE:
4499 case XML_DOCUMENT_TYPE_NODE:
4500 case XML_DOCUMENT_FRAG_NODE:
4501 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004502#ifdef LIBXML_DOCB_ENABLED
4503 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004504#endif
4505 return(((xmlDocPtr) ctxt->context->node)->children);
4506 case XML_ELEMENT_DECL:
4507 case XML_ATTRIBUTE_DECL:
4508 case XML_ENTITY_DECL:
4509 case XML_ATTRIBUTE_NODE:
4510 case XML_NAMESPACE_DECL:
4511 case XML_XINCLUDE_START:
4512 case XML_XINCLUDE_END:
4513 return(NULL);
4514 }
4515 return(NULL);
4516 }
4517 if ((cur->type == XML_DOCUMENT_NODE) ||
4518 (cur->type == XML_HTML_DOCUMENT_NODE))
4519 return(NULL);
4520 return(cur->next);
4521}
4522
4523/**
4524 * xmlXPathNextDescendant:
4525 * @ctxt: the XPath Parser context
4526 * @cur: the current node in the traversal
4527 *
4528 * Traversal function for the "descendant" direction
4529 * the descendant axis contains the descendants of the context node in document
4530 * order; a descendant is a child or a child of a child and so on.
4531 *
4532 * Returns the next element following that axis
4533 */
4534xmlNodePtr
4535xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4536 if (cur == NULL) {
4537 if (ctxt->context->node == NULL)
4538 return(NULL);
4539 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4540 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4541 return(NULL);
4542
4543 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4544 return(ctxt->context->doc->children);
4545 return(ctxt->context->node->children);
4546 }
4547
Daniel Veillard567e1b42001-08-01 15:53:47 +00004548 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004549 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004550 return(cur->children);
4551 }
4552
4553 if (cur == ctxt->context->node) return(NULL);
4554
Owen Taylor3473f882001-02-23 17:55:21 +00004555 if (cur->next != NULL) return(cur->next);
4556
4557 do {
4558 cur = cur->parent;
4559 if (cur == NULL) return(NULL);
4560 if (cur == ctxt->context->node) return(NULL);
4561 if (cur->next != NULL) {
4562 cur = cur->next;
4563 return(cur);
4564 }
4565 } while (cur != NULL);
4566 return(cur);
4567}
4568
4569/**
4570 * xmlXPathNextDescendantOrSelf:
4571 * @ctxt: the XPath Parser context
4572 * @cur: the current node in the traversal
4573 *
4574 * Traversal function for the "descendant-or-self" direction
4575 * the descendant-or-self axis contains the context node and the descendants
4576 * of the context node in document order; thus the context node is the first
4577 * node on the axis, and the first child of the context node is the second node
4578 * on the axis
4579 *
4580 * Returns the next element following that axis
4581 */
4582xmlNodePtr
4583xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4584 if (cur == NULL) {
4585 if (ctxt->context->node == NULL)
4586 return(NULL);
4587 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4588 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4589 return(NULL);
4590 return(ctxt->context->node);
4591 }
4592
4593 return(xmlXPathNextDescendant(ctxt, cur));
4594}
4595
4596/**
4597 * xmlXPathNextParent:
4598 * @ctxt: the XPath Parser context
4599 * @cur: the current node in the traversal
4600 *
4601 * Traversal function for the "parent" direction
4602 * The parent axis contains the parent of the context node, if there is one.
4603 *
4604 * Returns the next element following that axis
4605 */
4606xmlNodePtr
4607xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4608 /*
4609 * the parent of an attribute or namespace node is the element
4610 * to which the attribute or namespace node is attached
4611 * Namespace handling !!!
4612 */
4613 if (cur == NULL) {
4614 if (ctxt->context->node == NULL) return(NULL);
4615 switch (ctxt->context->node->type) {
4616 case XML_ELEMENT_NODE:
4617 case XML_TEXT_NODE:
4618 case XML_CDATA_SECTION_NODE:
4619 case XML_ENTITY_REF_NODE:
4620 case XML_ENTITY_NODE:
4621 case XML_PI_NODE:
4622 case XML_COMMENT_NODE:
4623 case XML_NOTATION_NODE:
4624 case XML_DTD_NODE:
4625 case XML_ELEMENT_DECL:
4626 case XML_ATTRIBUTE_DECL:
4627 case XML_XINCLUDE_START:
4628 case XML_XINCLUDE_END:
4629 case XML_ENTITY_DECL:
4630 if (ctxt->context->node->parent == NULL)
4631 return((xmlNodePtr) ctxt->context->doc);
4632 return(ctxt->context->node->parent);
4633 case XML_ATTRIBUTE_NODE: {
4634 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4635
4636 return(att->parent);
4637 }
4638 case XML_DOCUMENT_NODE:
4639 case XML_DOCUMENT_TYPE_NODE:
4640 case XML_DOCUMENT_FRAG_NODE:
4641 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004642#ifdef LIBXML_DOCB_ENABLED
4643 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004644#endif
4645 return(NULL);
4646 case XML_NAMESPACE_DECL:
4647 /*
4648 * TODO !!! may require extending struct _xmlNs with
4649 * parent field
4650 * C.f. Infoset case...
4651 */
4652 return(NULL);
4653 }
4654 }
4655 return(NULL);
4656}
4657
4658/**
4659 * xmlXPathNextAncestor:
4660 * @ctxt: the XPath Parser context
4661 * @cur: the current node in the traversal
4662 *
4663 * Traversal function for the "ancestor" direction
4664 * the ancestor axis contains the ancestors of the context node; the ancestors
4665 * of the context node consist of the parent of context node and the parent's
4666 * parent and so on; the nodes are ordered in reverse document order; thus the
4667 * parent is the first node on the axis, and the parent's parent is the second
4668 * node on the axis
4669 *
4670 * Returns the next element following that axis
4671 */
4672xmlNodePtr
4673xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4674 /*
4675 * the parent of an attribute or namespace node is the element
4676 * to which the attribute or namespace node is attached
4677 * !!!!!!!!!!!!!
4678 */
4679 if (cur == NULL) {
4680 if (ctxt->context->node == NULL) return(NULL);
4681 switch (ctxt->context->node->type) {
4682 case XML_ELEMENT_NODE:
4683 case XML_TEXT_NODE:
4684 case XML_CDATA_SECTION_NODE:
4685 case XML_ENTITY_REF_NODE:
4686 case XML_ENTITY_NODE:
4687 case XML_PI_NODE:
4688 case XML_COMMENT_NODE:
4689 case XML_DTD_NODE:
4690 case XML_ELEMENT_DECL:
4691 case XML_ATTRIBUTE_DECL:
4692 case XML_ENTITY_DECL:
4693 case XML_NOTATION_NODE:
4694 case XML_XINCLUDE_START:
4695 case XML_XINCLUDE_END:
4696 if (ctxt->context->node->parent == NULL)
4697 return((xmlNodePtr) ctxt->context->doc);
4698 return(ctxt->context->node->parent);
4699 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004700 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004701
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004702 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004703 }
4704 case XML_DOCUMENT_NODE:
4705 case XML_DOCUMENT_TYPE_NODE:
4706 case XML_DOCUMENT_FRAG_NODE:
4707 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004708#ifdef LIBXML_DOCB_ENABLED
4709 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004710#endif
4711 return(NULL);
4712 case XML_NAMESPACE_DECL:
4713 /*
4714 * TODO !!! may require extending struct _xmlNs with
4715 * parent field
4716 * C.f. Infoset case...
4717 */
4718 return(NULL);
4719 }
4720 return(NULL);
4721 }
4722 if (cur == ctxt->context->doc->children)
4723 return((xmlNodePtr) ctxt->context->doc);
4724 if (cur == (xmlNodePtr) ctxt->context->doc)
4725 return(NULL);
4726 switch (cur->type) {
4727 case XML_ELEMENT_NODE:
4728 case XML_TEXT_NODE:
4729 case XML_CDATA_SECTION_NODE:
4730 case XML_ENTITY_REF_NODE:
4731 case XML_ENTITY_NODE:
4732 case XML_PI_NODE:
4733 case XML_COMMENT_NODE:
4734 case XML_NOTATION_NODE:
4735 case XML_DTD_NODE:
4736 case XML_ELEMENT_DECL:
4737 case XML_ATTRIBUTE_DECL:
4738 case XML_ENTITY_DECL:
4739 case XML_XINCLUDE_START:
4740 case XML_XINCLUDE_END:
4741 return(cur->parent);
4742 case XML_ATTRIBUTE_NODE: {
4743 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4744
4745 return(att->parent);
4746 }
4747 case XML_DOCUMENT_NODE:
4748 case XML_DOCUMENT_TYPE_NODE:
4749 case XML_DOCUMENT_FRAG_NODE:
4750 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004751#ifdef LIBXML_DOCB_ENABLED
4752 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004753#endif
4754 return(NULL);
4755 case XML_NAMESPACE_DECL:
4756 /*
4757 * TODO !!! may require extending struct _xmlNs with
4758 * parent field
4759 * C.f. Infoset case...
4760 */
4761 return(NULL);
4762 }
4763 return(NULL);
4764}
4765
4766/**
4767 * xmlXPathNextAncestorOrSelf:
4768 * @ctxt: the XPath Parser context
4769 * @cur: the current node in the traversal
4770 *
4771 * Traversal function for the "ancestor-or-self" direction
4772 * he ancestor-or-self axis contains the context node and ancestors of
4773 * the context node in reverse document order; thus the context node is
4774 * the first node on the axis, and the context node's parent the second;
4775 * parent here is defined the same as with the parent axis.
4776 *
4777 * Returns the next element following that axis
4778 */
4779xmlNodePtr
4780xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4781 if (cur == NULL)
4782 return(ctxt->context->node);
4783 return(xmlXPathNextAncestor(ctxt, cur));
4784}
4785
4786/**
4787 * xmlXPathNextFollowingSibling:
4788 * @ctxt: the XPath Parser context
4789 * @cur: the current node in the traversal
4790 *
4791 * Traversal function for the "following-sibling" direction
4792 * The following-sibling axis contains the following siblings of the context
4793 * node in document order.
4794 *
4795 * Returns the next element following that axis
4796 */
4797xmlNodePtr
4798xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4799 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4800 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4801 return(NULL);
4802 if (cur == (xmlNodePtr) ctxt->context->doc)
4803 return(NULL);
4804 if (cur == NULL)
4805 return(ctxt->context->node->next);
4806 return(cur->next);
4807}
4808
4809/**
4810 * xmlXPathNextPrecedingSibling:
4811 * @ctxt: the XPath Parser context
4812 * @cur: the current node in the traversal
4813 *
4814 * Traversal function for the "preceding-sibling" direction
4815 * The preceding-sibling axis contains the preceding siblings of the context
4816 * node in reverse document order; the first preceding sibling is first on the
4817 * axis; the sibling preceding that node is the second on the axis and so on.
4818 *
4819 * Returns the next element following that axis
4820 */
4821xmlNodePtr
4822xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4823 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4824 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4825 return(NULL);
4826 if (cur == (xmlNodePtr) ctxt->context->doc)
4827 return(NULL);
4828 if (cur == NULL)
4829 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004830 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4831 cur = cur->prev;
4832 if (cur == NULL)
4833 return(ctxt->context->node->prev);
4834 }
Owen Taylor3473f882001-02-23 17:55:21 +00004835 return(cur->prev);
4836}
4837
4838/**
4839 * xmlXPathNextFollowing:
4840 * @ctxt: the XPath Parser context
4841 * @cur: the current node in the traversal
4842 *
4843 * Traversal function for the "following" direction
4844 * The following axis contains all nodes in the same document as the context
4845 * node that are after the context node in document order, excluding any
4846 * descendants and excluding attribute nodes and namespace nodes; the nodes
4847 * are ordered in document order
4848 *
4849 * Returns the next element following that axis
4850 */
4851xmlNodePtr
4852xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4853 if (cur != NULL && cur->children != NULL)
4854 return cur->children ;
4855 if (cur == NULL) cur = ctxt->context->node;
4856 if (cur == NULL) return(NULL) ; /* ERROR */
4857 if (cur->next != NULL) return(cur->next) ;
4858 do {
4859 cur = cur->parent;
4860 if (cur == NULL) return(NULL);
4861 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4862 if (cur->next != NULL) return(cur->next);
4863 } while (cur != NULL);
4864 return(cur);
4865}
4866
4867/*
4868 * xmlXPathIsAncestor:
4869 * @ancestor: the ancestor node
4870 * @node: the current node
4871 *
4872 * Check that @ancestor is a @node's ancestor
4873 *
4874 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4875 */
4876static int
4877xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4878 if ((ancestor == NULL) || (node == NULL)) return(0);
4879 /* nodes need to be in the same document */
4880 if (ancestor->doc != node->doc) return(0);
4881 /* avoid searching if ancestor or node is the root node */
4882 if (ancestor == (xmlNodePtr) node->doc) return(1);
4883 if (node == (xmlNodePtr) ancestor->doc) return(0);
4884 while (node->parent != NULL) {
4885 if (node->parent == ancestor)
4886 return(1);
4887 node = node->parent;
4888 }
4889 return(0);
4890}
4891
4892/**
4893 * xmlXPathNextPreceding:
4894 * @ctxt: the XPath Parser context
4895 * @cur: the current node in the traversal
4896 *
4897 * Traversal function for the "preceding" direction
4898 * the preceding axis contains all nodes in the same document as the context
4899 * node that are before the context node in document order, excluding any
4900 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4901 * ordered in reverse document order
4902 *
4903 * Returns the next element following that axis
4904 */
4905xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004906xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4907{
Owen Taylor3473f882001-02-23 17:55:21 +00004908 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004909 cur = ctxt->context->node;
4910 if (cur == NULL)
4911 return (NULL);
4912 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4913 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004914 do {
4915 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004916 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4917 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004918 }
4919
4920 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004921 if (cur == NULL)
4922 return (NULL);
4923 if (cur == ctxt->context->doc->children)
4924 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004925 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004926 return (cur);
4927}
4928
4929/**
4930 * xmlXPathNextPrecedingInternal:
4931 * @ctxt: the XPath Parser context
4932 * @cur: the current node in the traversal
4933 *
4934 * Traversal function for the "preceding" direction
4935 * the preceding axis contains all nodes in the same document as the context
4936 * node that are before the context node in document order, excluding any
4937 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4938 * ordered in reverse document order
4939 * This is a faster implementation but internal only since it requires a
4940 * state kept in the parser context: ctxt->ancestor.
4941 *
4942 * Returns the next element following that axis
4943 */
4944static xmlNodePtr
4945xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4946 xmlNodePtr cur)
4947{
4948 if (cur == NULL) {
4949 cur = ctxt->context->node;
4950 if (cur == NULL)
4951 return (NULL);
4952 ctxt->ancestor = cur->parent;
4953 }
4954 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4955 cur = cur->prev;
4956 while (cur->prev == NULL) {
4957 cur = cur->parent;
4958 if (cur == NULL)
4959 return (NULL);
4960 if (cur == ctxt->context->doc->children)
4961 return (NULL);
4962 if (cur != ctxt->ancestor)
4963 return (cur);
4964 ctxt->ancestor = cur->parent;
4965 }
4966 cur = cur->prev;
4967 while (cur->last != NULL)
4968 cur = cur->last;
4969 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004970}
4971
4972/**
4973 * xmlXPathNextNamespace:
4974 * @ctxt: the XPath Parser context
4975 * @cur: the current attribute in the traversal
4976 *
4977 * Traversal function for the "namespace" direction
4978 * the namespace axis contains the namespace nodes of the context node;
4979 * the order of nodes on this axis is implementation-defined; the axis will
4980 * be empty unless the context node is an element
4981 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00004982 * We keep the XML namespace node at the end of the list.
4983 *
Owen Taylor3473f882001-02-23 17:55:21 +00004984 * Returns the next element following that axis
4985 */
4986xmlNodePtr
4987xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004988 xmlNodePtr ret;
4989
Owen Taylor3473f882001-02-23 17:55:21 +00004990 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00004991 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
4992 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004993 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
4994 if (ctxt->context->tmpNsList != NULL)
4995 xmlFree(ctxt->context->tmpNsList);
4996 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00004997 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004998 if (ctxt->context->tmpNsList == NULL) return(NULL);
4999 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005000 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005001 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5002 if (ret == NULL) {
5003 xmlFree(ctxt->context->tmpNsList);
5004 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005005 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005006 }
5007 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005008}
5009
5010/**
5011 * xmlXPathNextAttribute:
5012 * @ctxt: the XPath Parser context
5013 * @cur: the current attribute in the traversal
5014 *
5015 * Traversal function for the "attribute" direction
5016 * TODO: support DTD inherited default attributes
5017 *
5018 * Returns the next element following that axis
5019 */
5020xmlNodePtr
5021xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005022 if (ctxt->context->node == NULL)
5023 return(NULL);
5024 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5025 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005026 if (cur == NULL) {
5027 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5028 return(NULL);
5029 return((xmlNodePtr)ctxt->context->node->properties);
5030 }
5031 return((xmlNodePtr)cur->next);
5032}
5033
5034/************************************************************************
5035 * *
5036 * NodeTest Functions *
5037 * *
5038 ************************************************************************/
5039
Owen Taylor3473f882001-02-23 17:55:21 +00005040#define IS_FUNCTION 200
5041
Owen Taylor3473f882001-02-23 17:55:21 +00005042
5043/************************************************************************
5044 * *
5045 * Implicit tree core function library *
5046 * *
5047 ************************************************************************/
5048
5049/**
5050 * xmlXPathRoot:
5051 * @ctxt: the XPath Parser context
5052 *
5053 * Initialize the context to the root of the document
5054 */
5055void
5056xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5057 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5058 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5059}
5060
5061/************************************************************************
5062 * *
5063 * The explicit core function library *
5064 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5065 * *
5066 ************************************************************************/
5067
5068
5069/**
5070 * xmlXPathLastFunction:
5071 * @ctxt: the XPath Parser context
5072 * @nargs: the number of arguments
5073 *
5074 * Implement the last() XPath function
5075 * number last()
5076 * The last function returns the number of nodes in the context node list.
5077 */
5078void
5079xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5080 CHECK_ARITY(0);
5081 if (ctxt->context->contextSize >= 0) {
5082 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5083#ifdef DEBUG_EXPR
5084 xmlGenericError(xmlGenericErrorContext,
5085 "last() : %d\n", ctxt->context->contextSize);
5086#endif
5087 } else {
5088 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5089 }
5090}
5091
5092/**
5093 * xmlXPathPositionFunction:
5094 * @ctxt: the XPath Parser context
5095 * @nargs: the number of arguments
5096 *
5097 * Implement the position() XPath function
5098 * number position()
5099 * The position function returns the position of the context node in the
5100 * context node list. The first position is 1, and so the last positionr
5101 * will be equal to last().
5102 */
5103void
5104xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5105 CHECK_ARITY(0);
5106 if (ctxt->context->proximityPosition >= 0) {
5107 valuePush(ctxt,
5108 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5109#ifdef DEBUG_EXPR
5110 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5111 ctxt->context->proximityPosition);
5112#endif
5113 } else {
5114 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5115 }
5116}
5117
5118/**
5119 * xmlXPathCountFunction:
5120 * @ctxt: the XPath Parser context
5121 * @nargs: the number of arguments
5122 *
5123 * Implement the count() XPath function
5124 * number count(node-set)
5125 */
5126void
5127xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5128 xmlXPathObjectPtr cur;
5129
5130 CHECK_ARITY(1);
5131 if ((ctxt->value == NULL) ||
5132 ((ctxt->value->type != XPATH_NODESET) &&
5133 (ctxt->value->type != XPATH_XSLT_TREE)))
5134 XP_ERROR(XPATH_INVALID_TYPE);
5135 cur = valuePop(ctxt);
5136
Daniel Veillard911f49a2001-04-07 15:39:35 +00005137 if ((cur == NULL) || (cur->nodesetval == NULL))
5138 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005139 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005140 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005141 } else {
5142 if ((cur->nodesetval->nodeNr != 1) ||
5143 (cur->nodesetval->nodeTab == NULL)) {
5144 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5145 } else {
5146 xmlNodePtr tmp;
5147 int i = 0;
5148
5149 tmp = cur->nodesetval->nodeTab[0];
5150 if (tmp != NULL) {
5151 tmp = tmp->children;
5152 while (tmp != NULL) {
5153 tmp = tmp->next;
5154 i++;
5155 }
5156 }
5157 valuePush(ctxt, xmlXPathNewFloat((double) i));
5158 }
5159 }
Owen Taylor3473f882001-02-23 17:55:21 +00005160 xmlXPathFreeObject(cur);
5161}
5162
5163/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005164 * xmlXPathGetElementsByIds:
5165 * @doc: the document
5166 * @ids: a whitespace separated list of IDs
5167 *
5168 * Selects elements by their unique ID.
5169 *
5170 * Returns a node-set of selected elements.
5171 */
5172static xmlNodeSetPtr
5173xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5174 xmlNodeSetPtr ret;
5175 const xmlChar *cur = ids;
5176 xmlChar *ID;
5177 xmlAttrPtr attr;
5178 xmlNodePtr elem = NULL;
5179
5180 ret = xmlXPathNodeSetCreate(NULL);
5181
5182 while (IS_BLANK(*cur)) cur++;
5183 while (*cur != 0) {
5184 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5185 (*cur == '.') || (*cur == '-') ||
5186 (*cur == '_') || (*cur == ':') ||
5187 (IS_COMBINING(*cur)) ||
5188 (IS_EXTENDER(*cur)))
5189 cur++;
5190
5191 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5192
5193 ID = xmlStrndup(ids, cur - ids);
5194 attr = xmlGetID(doc, ID);
5195 if (attr != NULL) {
5196 elem = attr->parent;
5197 xmlXPathNodeSetAdd(ret, elem);
5198 }
5199 if (ID != NULL)
5200 xmlFree(ID);
5201
5202 while (IS_BLANK(*cur)) cur++;
5203 ids = cur;
5204 }
5205 return(ret);
5206}
5207
5208/**
Owen Taylor3473f882001-02-23 17:55:21 +00005209 * xmlXPathIdFunction:
5210 * @ctxt: the XPath Parser context
5211 * @nargs: the number of arguments
5212 *
5213 * Implement the id() XPath function
5214 * node-set id(object)
5215 * The id function selects elements by their unique ID
5216 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5217 * then the result is the union of the result of applying id to the
5218 * string value of each of the nodes in the argument node-set. When the
5219 * argument to id is of any other type, the argument is converted to a
5220 * string as if by a call to the string function; the string is split
5221 * into a whitespace-separated list of tokens (whitespace is any sequence
5222 * of characters matching the production S); the result is a node-set
5223 * containing the elements in the same document as the context node that
5224 * have a unique ID equal to any of the tokens in the list.
5225 */
5226void
5227xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005228 xmlChar *tokens;
5229 xmlNodeSetPtr ret;
5230 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005231
5232 CHECK_ARITY(1);
5233 obj = valuePop(ctxt);
5234 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5235 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005236 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005237 int i;
5238
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005239 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005240
Daniel Veillard911f49a2001-04-07 15:39:35 +00005241 if (obj->nodesetval != NULL) {
5242 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005243 tokens =
5244 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5245 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5246 ret = xmlXPathNodeSetMerge(ret, ns);
5247 xmlXPathFreeNodeSet(ns);
5248 if (tokens != NULL)
5249 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005250 }
Owen Taylor3473f882001-02-23 17:55:21 +00005251 }
5252
5253 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005254 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005255 return;
5256 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005257 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005258
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005259 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5260 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005261
Owen Taylor3473f882001-02-23 17:55:21 +00005262 xmlXPathFreeObject(obj);
5263 return;
5264}
5265
5266/**
5267 * xmlXPathLocalNameFunction:
5268 * @ctxt: the XPath Parser context
5269 * @nargs: the number of arguments
5270 *
5271 * Implement the local-name() XPath function
5272 * string local-name(node-set?)
5273 * The local-name function returns a string containing the local part
5274 * of the name of the node in the argument node-set that is first in
5275 * document order. If the node-set is empty or the first node has no
5276 * name, an empty string is returned. If the argument is omitted it
5277 * defaults to the context node.
5278 */
5279void
5280xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5281 xmlXPathObjectPtr cur;
5282
5283 if (nargs == 0) {
5284 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5285 nargs = 1;
5286 }
5287
5288 CHECK_ARITY(1);
5289 if ((ctxt->value == NULL) ||
5290 ((ctxt->value->type != XPATH_NODESET) &&
5291 (ctxt->value->type != XPATH_XSLT_TREE)))
5292 XP_ERROR(XPATH_INVALID_TYPE);
5293 cur = valuePop(ctxt);
5294
Daniel Veillard911f49a2001-04-07 15:39:35 +00005295 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005296 valuePush(ctxt, xmlXPathNewCString(""));
5297 } else {
5298 int i = 0; /* Should be first in document order !!!!! */
5299 switch (cur->nodesetval->nodeTab[i]->type) {
5300 case XML_ELEMENT_NODE:
5301 case XML_ATTRIBUTE_NODE:
5302 case XML_PI_NODE:
5303 valuePush(ctxt,
5304 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5305 break;
5306 case XML_NAMESPACE_DECL:
5307 valuePush(ctxt, xmlXPathNewString(
5308 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5309 break;
5310 default:
5311 valuePush(ctxt, xmlXPathNewCString(""));
5312 }
5313 }
5314 xmlXPathFreeObject(cur);
5315}
5316
5317/**
5318 * xmlXPathNamespaceURIFunction:
5319 * @ctxt: the XPath Parser context
5320 * @nargs: the number of arguments
5321 *
5322 * Implement the namespace-uri() XPath function
5323 * string namespace-uri(node-set?)
5324 * The namespace-uri function returns a string containing the
5325 * namespace URI of the expanded name of the node in the argument
5326 * node-set that is first in document order. If the node-set is empty,
5327 * the first node has no name, or the expanded name has no namespace
5328 * URI, an empty string is returned. If the argument is omitted it
5329 * defaults to the context node.
5330 */
5331void
5332xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5333 xmlXPathObjectPtr cur;
5334
5335 if (nargs == 0) {
5336 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5337 nargs = 1;
5338 }
5339 CHECK_ARITY(1);
5340 if ((ctxt->value == NULL) ||
5341 ((ctxt->value->type != XPATH_NODESET) &&
5342 (ctxt->value->type != XPATH_XSLT_TREE)))
5343 XP_ERROR(XPATH_INVALID_TYPE);
5344 cur = valuePop(ctxt);
5345
Daniel Veillard911f49a2001-04-07 15:39:35 +00005346 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005347 valuePush(ctxt, xmlXPathNewCString(""));
5348 } else {
5349 int i = 0; /* Should be first in document order !!!!! */
5350 switch (cur->nodesetval->nodeTab[i]->type) {
5351 case XML_ELEMENT_NODE:
5352 case XML_ATTRIBUTE_NODE:
5353 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5354 valuePush(ctxt, xmlXPathNewCString(""));
5355 else
5356 valuePush(ctxt, xmlXPathNewString(
5357 cur->nodesetval->nodeTab[i]->ns->href));
5358 break;
5359 default:
5360 valuePush(ctxt, xmlXPathNewCString(""));
5361 }
5362 }
5363 xmlXPathFreeObject(cur);
5364}
5365
5366/**
5367 * xmlXPathNameFunction:
5368 * @ctxt: the XPath Parser context
5369 * @nargs: the number of arguments
5370 *
5371 * Implement the name() XPath function
5372 * string name(node-set?)
5373 * The name function returns a string containing a QName representing
5374 * the name of the node in the argument node-set that is first in documenti
5375 * order. The QName must represent the name with respect to the namespace
5376 * declarations in effect on the node whose name is being represented.
5377 * Typically, this will be the form in which the name occurred in the XML
5378 * source. This need not be the case if there are namespace declarations
5379 * in effect on the node that associate multiple prefixes with the same
5380 * namespace. However, an implementation may include information about
5381 * the original prefix in its representation of nodes; in this case, an
5382 * implementation can ensure that the returned string is always the same
5383 * as the QName used in the XML source. If the argument it omitted it
5384 * defaults to the context node.
5385 * Libxml keep the original prefix so the "real qualified name" used is
5386 * returned.
5387 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005388static void
Daniel Veillard04383752001-07-08 14:27:15 +00005389xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5390{
Owen Taylor3473f882001-02-23 17:55:21 +00005391 xmlXPathObjectPtr cur;
5392
5393 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005394 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5395 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005396 }
5397
5398 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005399 if ((ctxt->value == NULL) ||
5400 ((ctxt->value->type != XPATH_NODESET) &&
5401 (ctxt->value->type != XPATH_XSLT_TREE)))
5402 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005403 cur = valuePop(ctxt);
5404
Daniel Veillard911f49a2001-04-07 15:39:35 +00005405 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005406 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005407 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005408 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005409
Daniel Veillard04383752001-07-08 14:27:15 +00005410 switch (cur->nodesetval->nodeTab[i]->type) {
5411 case XML_ELEMENT_NODE:
5412 case XML_ATTRIBUTE_NODE:
5413 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5414 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5415 valuePush(ctxt,
5416 xmlXPathNewString(cur->nodesetval->
5417 nodeTab[i]->name));
5418
5419 else {
5420 char name[2000];
5421
5422 snprintf(name, sizeof(name), "%s:%s",
5423 (char *) cur->nodesetval->nodeTab[i]->ns->
5424 prefix,
5425 (char *) cur->nodesetval->nodeTab[i]->name);
5426 name[sizeof(name) - 1] = 0;
5427 valuePush(ctxt, xmlXPathNewCString(name));
5428 }
5429 break;
5430 default:
5431 valuePush(ctxt,
5432 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5433 xmlXPathLocalNameFunction(ctxt, 1);
5434 }
Owen Taylor3473f882001-02-23 17:55:21 +00005435 }
5436 xmlXPathFreeObject(cur);
5437}
5438
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005439
5440/**
Owen Taylor3473f882001-02-23 17:55:21 +00005441 * xmlXPathStringFunction:
5442 * @ctxt: the XPath Parser context
5443 * @nargs: the number of arguments
5444 *
5445 * Implement the string() XPath function
5446 * string string(object?)
5447 * he string function converts an object to a string as follows:
5448 * - A node-set is converted to a string by returning the value of
5449 * the node in the node-set that is first in document order.
5450 * If the node-set is empty, an empty string is returned.
5451 * - A number is converted to a string as follows
5452 * + NaN is converted to the string NaN
5453 * + positive zero is converted to the string 0
5454 * + negative zero is converted to the string 0
5455 * + positive infinity is converted to the string Infinity
5456 * + negative infinity is converted to the string -Infinity
5457 * + if the number is an integer, the number is represented in
5458 * decimal form as a Number with no decimal point and no leading
5459 * zeros, preceded by a minus sign (-) if the number is negative
5460 * + otherwise, the number is represented in decimal form as a
5461 * Number including a decimal point with at least one digit
5462 * before the decimal point and at least one digit after the
5463 * decimal point, preceded by a minus sign (-) if the number
5464 * is negative; there must be no leading zeros before the decimal
5465 * point apart possibly from the one required digit immediatelyi
5466 * before the decimal point; beyond the one required digit
5467 * after the decimal point there must be as many, but only as
5468 * many, more digits as are needed to uniquely distinguish the
5469 * number from all other IEEE 754 numeric values.
5470 * - The boolean false value is converted to the string false.
5471 * The boolean true value is converted to the string true.
5472 *
5473 * If the argument is omitted, it defaults to a node-set with the
5474 * context node as its only member.
5475 */
5476void
5477xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5478 xmlXPathObjectPtr cur;
5479
5480 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005481 valuePush(ctxt,
5482 xmlXPathWrapString(
5483 xmlXPathCastNodeToString(ctxt->context->node)));
5484 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005485 }
5486
5487 CHECK_ARITY(1);
5488 cur = valuePop(ctxt);
5489 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005490 cur = xmlXPathConvertString(cur);
5491 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005492}
5493
5494/**
5495 * xmlXPathStringLengthFunction:
5496 * @ctxt: the XPath Parser context
5497 * @nargs: the number of arguments
5498 *
5499 * Implement the string-length() XPath function
5500 * number string-length(string?)
5501 * The string-length returns the number of characters in the string
5502 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5503 * the context node converted to a string, in other words the value
5504 * of the context node.
5505 */
5506void
5507xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5508 xmlXPathObjectPtr cur;
5509
5510 if (nargs == 0) {
5511 if (ctxt->context->node == NULL) {
5512 valuePush(ctxt, xmlXPathNewFloat(0));
5513 } else {
5514 xmlChar *content;
5515
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005516 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005517 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005518 xmlFree(content);
5519 }
5520 return;
5521 }
5522 CHECK_ARITY(1);
5523 CAST_TO_STRING;
5524 CHECK_TYPE(XPATH_STRING);
5525 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005526 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005527 xmlXPathFreeObject(cur);
5528}
5529
5530/**
5531 * xmlXPathConcatFunction:
5532 * @ctxt: the XPath Parser context
5533 * @nargs: the number of arguments
5534 *
5535 * Implement the concat() XPath function
5536 * string concat(string, string, string*)
5537 * The concat function returns the concatenation of its arguments.
5538 */
5539void
5540xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5541 xmlXPathObjectPtr cur, newobj;
5542 xmlChar *tmp;
5543
5544 if (nargs < 2) {
5545 CHECK_ARITY(2);
5546 }
5547
5548 CAST_TO_STRING;
5549 cur = valuePop(ctxt);
5550 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5551 xmlXPathFreeObject(cur);
5552 return;
5553 }
5554 nargs--;
5555
5556 while (nargs > 0) {
5557 CAST_TO_STRING;
5558 newobj = valuePop(ctxt);
5559 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5560 xmlXPathFreeObject(newobj);
5561 xmlXPathFreeObject(cur);
5562 XP_ERROR(XPATH_INVALID_TYPE);
5563 }
5564 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5565 newobj->stringval = cur->stringval;
5566 cur->stringval = tmp;
5567
5568 xmlXPathFreeObject(newobj);
5569 nargs--;
5570 }
5571 valuePush(ctxt, cur);
5572}
5573
5574/**
5575 * xmlXPathContainsFunction:
5576 * @ctxt: the XPath Parser context
5577 * @nargs: the number of arguments
5578 *
5579 * Implement the contains() XPath function
5580 * boolean contains(string, string)
5581 * The contains function returns true if the first argument string
5582 * contains the second argument string, and otherwise returns false.
5583 */
5584void
5585xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5586 xmlXPathObjectPtr hay, needle;
5587
5588 CHECK_ARITY(2);
5589 CAST_TO_STRING;
5590 CHECK_TYPE(XPATH_STRING);
5591 needle = valuePop(ctxt);
5592 CAST_TO_STRING;
5593 hay = valuePop(ctxt);
5594 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5595 xmlXPathFreeObject(hay);
5596 xmlXPathFreeObject(needle);
5597 XP_ERROR(XPATH_INVALID_TYPE);
5598 }
5599 if (xmlStrstr(hay->stringval, needle->stringval))
5600 valuePush(ctxt, xmlXPathNewBoolean(1));
5601 else
5602 valuePush(ctxt, xmlXPathNewBoolean(0));
5603 xmlXPathFreeObject(hay);
5604 xmlXPathFreeObject(needle);
5605}
5606
5607/**
5608 * xmlXPathStartsWithFunction:
5609 * @ctxt: the XPath Parser context
5610 * @nargs: the number of arguments
5611 *
5612 * Implement the starts-with() XPath function
5613 * boolean starts-with(string, string)
5614 * The starts-with function returns true if the first argument string
5615 * starts with the second argument string, and otherwise returns false.
5616 */
5617void
5618xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5619 xmlXPathObjectPtr hay, needle;
5620 int n;
5621
5622 CHECK_ARITY(2);
5623 CAST_TO_STRING;
5624 CHECK_TYPE(XPATH_STRING);
5625 needle = valuePop(ctxt);
5626 CAST_TO_STRING;
5627 hay = valuePop(ctxt);
5628 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5629 xmlXPathFreeObject(hay);
5630 xmlXPathFreeObject(needle);
5631 XP_ERROR(XPATH_INVALID_TYPE);
5632 }
5633 n = xmlStrlen(needle->stringval);
5634 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5635 valuePush(ctxt, xmlXPathNewBoolean(0));
5636 else
5637 valuePush(ctxt, xmlXPathNewBoolean(1));
5638 xmlXPathFreeObject(hay);
5639 xmlXPathFreeObject(needle);
5640}
5641
5642/**
5643 * xmlXPathSubstringFunction:
5644 * @ctxt: the XPath Parser context
5645 * @nargs: the number of arguments
5646 *
5647 * Implement the substring() XPath function
5648 * string substring(string, number, number?)
5649 * The substring function returns the substring of the first argument
5650 * starting at the position specified in the second argument with
5651 * length specified in the third argument. For example,
5652 * substring("12345",2,3) returns "234". If the third argument is not
5653 * specified, it returns the substring starting at the position specified
5654 * in the second argument and continuing to the end of the string. For
5655 * example, substring("12345",2) returns "2345". More precisely, each
5656 * character in the string (see [3.6 Strings]) is considered to have a
5657 * numeric position: the position of the first character is 1, the position
5658 * of the second character is 2 and so on. The returned substring contains
5659 * those characters for which the position of the character is greater than
5660 * or equal to the second argument and, if the third argument is specified,
5661 * less than the sum of the second and third arguments; the comparisons
5662 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5663 * - substring("12345", 1.5, 2.6) returns "234"
5664 * - substring("12345", 0, 3) returns "12"
5665 * - substring("12345", 0 div 0, 3) returns ""
5666 * - substring("12345", 1, 0 div 0) returns ""
5667 * - substring("12345", -42, 1 div 0) returns "12345"
5668 * - substring("12345", -1 div 0, 1 div 0) returns ""
5669 */
5670void
5671xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5672 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005673 double le=0, in;
5674 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005675 xmlChar *ret;
5676
Owen Taylor3473f882001-02-23 17:55:21 +00005677 if (nargs < 2) {
5678 CHECK_ARITY(2);
5679 }
5680 if (nargs > 3) {
5681 CHECK_ARITY(3);
5682 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005683 /*
5684 * take care of possible last (position) argument
5685 */
Owen Taylor3473f882001-02-23 17:55:21 +00005686 if (nargs == 3) {
5687 CAST_TO_NUMBER;
5688 CHECK_TYPE(XPATH_NUMBER);
5689 len = valuePop(ctxt);
5690 le = len->floatval;
5691 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005692 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005693
Owen Taylor3473f882001-02-23 17:55:21 +00005694 CAST_TO_NUMBER;
5695 CHECK_TYPE(XPATH_NUMBER);
5696 start = valuePop(ctxt);
5697 in = start->floatval;
5698 xmlXPathFreeObject(start);
5699 CAST_TO_STRING;
5700 CHECK_TYPE(XPATH_STRING);
5701 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005702 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005703
Daniel Veillard97ac1312001-05-30 19:14:17 +00005704 /*
5705 * If last pos not present, calculate last position
5706 */
5707 if (nargs != 3)
5708 le = m;
5709
5710 /*
5711 * To meet our requirements, initial index calculations
5712 * must be done before we convert to integer format
5713 *
5714 * First we normalize indices
5715 */
5716 in -= 1.0;
5717 le += in;
5718 if (in < 0.0)
5719 in = 0.0;
5720 if (le > (double)m)
5721 le = (double)m;
5722
5723 /*
5724 * Now we go to integer form, rounding up
5725 */
Owen Taylor3473f882001-02-23 17:55:21 +00005726 i = (int) in;
5727 if (((double)i) != in) i++;
5728
Owen Taylor3473f882001-02-23 17:55:21 +00005729 l = (int) le;
5730 if (((double)l) != le) l++;
5731
Daniel Veillard97ac1312001-05-30 19:14:17 +00005732 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005733
5734 /* number of chars to copy */
5735 l -= i;
5736
Daniel Veillard97ac1312001-05-30 19:14:17 +00005737 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005738 if (ret == NULL)
5739 valuePush(ctxt, xmlXPathNewCString(""));
5740 else {
5741 valuePush(ctxt, xmlXPathNewString(ret));
5742 xmlFree(ret);
5743 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005744
Owen Taylor3473f882001-02-23 17:55:21 +00005745 xmlXPathFreeObject(str);
5746}
5747
5748/**
5749 * xmlXPathSubstringBeforeFunction:
5750 * @ctxt: the XPath Parser context
5751 * @nargs: the number of arguments
5752 *
5753 * Implement the substring-before() XPath function
5754 * string substring-before(string, string)
5755 * The substring-before function returns the substring of the first
5756 * argument string that precedes the first occurrence of the second
5757 * argument string in the first argument string, or the empty string
5758 * if the first argument string does not contain the second argument
5759 * string. For example, substring-before("1999/04/01","/") returns 1999.
5760 */
5761void
5762xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5763 xmlXPathObjectPtr str;
5764 xmlXPathObjectPtr find;
5765 xmlBufferPtr target;
5766 const xmlChar *point;
5767 int offset;
5768
5769 CHECK_ARITY(2);
5770 CAST_TO_STRING;
5771 find = valuePop(ctxt);
5772 CAST_TO_STRING;
5773 str = valuePop(ctxt);
5774
5775 target = xmlBufferCreate();
5776 if (target) {
5777 point = xmlStrstr(str->stringval, find->stringval);
5778 if (point) {
5779 offset = (int)(point - str->stringval);
5780 xmlBufferAdd(target, str->stringval, offset);
5781 }
5782 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5783 xmlBufferFree(target);
5784 }
5785
5786 xmlXPathFreeObject(str);
5787 xmlXPathFreeObject(find);
5788}
5789
5790/**
5791 * xmlXPathSubstringAfterFunction:
5792 * @ctxt: the XPath Parser context
5793 * @nargs: the number of arguments
5794 *
5795 * Implement the substring-after() XPath function
5796 * string substring-after(string, string)
5797 * The substring-after function returns the substring of the first
5798 * argument string that follows the first occurrence of the second
5799 * argument string in the first argument string, or the empty stringi
5800 * if the first argument string does not contain the second argument
5801 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5802 * and substring-after("1999/04/01","19") returns 99/04/01.
5803 */
5804void
5805xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5806 xmlXPathObjectPtr str;
5807 xmlXPathObjectPtr find;
5808 xmlBufferPtr target;
5809 const xmlChar *point;
5810 int offset;
5811
5812 CHECK_ARITY(2);
5813 CAST_TO_STRING;
5814 find = valuePop(ctxt);
5815 CAST_TO_STRING;
5816 str = valuePop(ctxt);
5817
5818 target = xmlBufferCreate();
5819 if (target) {
5820 point = xmlStrstr(str->stringval, find->stringval);
5821 if (point) {
5822 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5823 xmlBufferAdd(target, &str->stringval[offset],
5824 xmlStrlen(str->stringval) - offset);
5825 }
5826 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5827 xmlBufferFree(target);
5828 }
5829
5830 xmlXPathFreeObject(str);
5831 xmlXPathFreeObject(find);
5832}
5833
5834/**
5835 * xmlXPathNormalizeFunction:
5836 * @ctxt: the XPath Parser context
5837 * @nargs: the number of arguments
5838 *
5839 * Implement the normalize-space() XPath function
5840 * string normalize-space(string?)
5841 * The normalize-space function returns the argument string with white
5842 * space normalized by stripping leading and trailing whitespace
5843 * and replacing sequences of whitespace characters by a single
5844 * space. Whitespace characters are the same allowed by the S production
5845 * in XML. If the argument is omitted, it defaults to the context
5846 * node converted to a string, in other words the value of the context node.
5847 */
5848void
5849xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5850 xmlXPathObjectPtr obj = NULL;
5851 xmlChar *source = NULL;
5852 xmlBufferPtr target;
5853 xmlChar blank;
5854
5855 if (nargs == 0) {
5856 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005857 valuePush(ctxt,
5858 xmlXPathWrapString(
5859 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005860 nargs = 1;
5861 }
5862
5863 CHECK_ARITY(1);
5864 CAST_TO_STRING;
5865 CHECK_TYPE(XPATH_STRING);
5866 obj = valuePop(ctxt);
5867 source = obj->stringval;
5868
5869 target = xmlBufferCreate();
5870 if (target && source) {
5871
5872 /* Skip leading whitespaces */
5873 while (IS_BLANK(*source))
5874 source++;
5875
5876 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5877 blank = 0;
5878 while (*source) {
5879 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005880 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005881 } else {
5882 if (blank) {
5883 xmlBufferAdd(target, &blank, 1);
5884 blank = 0;
5885 }
5886 xmlBufferAdd(target, source, 1);
5887 }
5888 source++;
5889 }
5890
5891 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5892 xmlBufferFree(target);
5893 }
5894 xmlXPathFreeObject(obj);
5895}
5896
5897/**
5898 * xmlXPathTranslateFunction:
5899 * @ctxt: the XPath Parser context
5900 * @nargs: the number of arguments
5901 *
5902 * Implement the translate() XPath function
5903 * string translate(string, string, string)
5904 * The translate function returns the first argument string with
5905 * occurrences of characters in the second argument string replaced
5906 * by the character at the corresponding position in the third argument
5907 * string. For example, translate("bar","abc","ABC") returns the string
5908 * BAr. If there is a character in the second argument string with no
5909 * character at a corresponding position in the third argument string
5910 * (because the second argument string is longer than the third argument
5911 * string), then occurrences of that character in the first argument
5912 * string are removed. For example, translate("--aaa--","abc-","ABC")
5913 * returns "AAA". If a character occurs more than once in second
5914 * argument string, then the first occurrence determines the replacement
5915 * character. If the third argument string is longer than the second
5916 * argument string, then excess characters are ignored.
5917 */
5918void
5919xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005920 xmlXPathObjectPtr str;
5921 xmlXPathObjectPtr from;
5922 xmlXPathObjectPtr to;
5923 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005924 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005925 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005926 xmlChar *point;
5927 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005928
Daniel Veillarde043ee12001-04-16 14:08:07 +00005929 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005930
Daniel Veillarde043ee12001-04-16 14:08:07 +00005931 CAST_TO_STRING;
5932 to = valuePop(ctxt);
5933 CAST_TO_STRING;
5934 from = valuePop(ctxt);
5935 CAST_TO_STRING;
5936 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005937
Daniel Veillarde043ee12001-04-16 14:08:07 +00005938 target = xmlBufferCreate();
5939 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005940 max = xmlUTF8Strlen(to->stringval);
5941 for (cptr = str->stringval; (ch=*cptr); ) {
5942 offset = xmlUTF8Strloc(from->stringval, cptr);
5943 if (offset >= 0) {
5944 if (offset < max) {
5945 point = xmlUTF8Strpos(to->stringval, offset);
5946 if (point)
5947 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5948 }
5949 } else
5950 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5951
5952 /* Step to next character in input */
5953 cptr++;
5954 if ( ch & 0x80 ) {
5955 /* if not simple ascii, verify proper format */
5956 if ( (ch & 0xc0) != 0xc0 ) {
5957 xmlGenericError(xmlGenericErrorContext,
5958 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5959 break;
5960 }
5961 /* then skip over remaining bytes for this char */
5962 while ( (ch <<= 1) & 0x80 )
5963 if ( (*cptr++ & 0xc0) != 0x80 ) {
5964 xmlGenericError(xmlGenericErrorContext,
5965 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5966 break;
5967 }
5968 if (ch & 0x80) /* must have had error encountered */
5969 break;
5970 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005971 }
Owen Taylor3473f882001-02-23 17:55:21 +00005972 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005973 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5974 xmlBufferFree(target);
5975 xmlXPathFreeObject(str);
5976 xmlXPathFreeObject(from);
5977 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005978}
5979
5980/**
5981 * xmlXPathBooleanFunction:
5982 * @ctxt: the XPath Parser context
5983 * @nargs: the number of arguments
5984 *
5985 * Implement the boolean() XPath function
5986 * boolean boolean(object)
5987 * he boolean function converts its argument to a boolean as follows:
5988 * - a number is true if and only if it is neither positive or
5989 * negative zero nor NaN
5990 * - a node-set is true if and only if it is non-empty
5991 * - a string is true if and only if its length is non-zero
5992 */
5993void
5994xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5995 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005996
5997 CHECK_ARITY(1);
5998 cur = valuePop(ctxt);
5999 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006000 cur = xmlXPathConvertBoolean(cur);
6001 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006002}
6003
6004/**
6005 * xmlXPathNotFunction:
6006 * @ctxt: the XPath Parser context
6007 * @nargs: the number of arguments
6008 *
6009 * Implement the not() XPath function
6010 * boolean not(boolean)
6011 * The not function returns true if its argument is false,
6012 * and false otherwise.
6013 */
6014void
6015xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6016 CHECK_ARITY(1);
6017 CAST_TO_BOOLEAN;
6018 CHECK_TYPE(XPATH_BOOLEAN);
6019 ctxt->value->boolval = ! ctxt->value->boolval;
6020}
6021
6022/**
6023 * xmlXPathTrueFunction:
6024 * @ctxt: the XPath Parser context
6025 * @nargs: the number of arguments
6026 *
6027 * Implement the true() XPath function
6028 * boolean true()
6029 */
6030void
6031xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6032 CHECK_ARITY(0);
6033 valuePush(ctxt, xmlXPathNewBoolean(1));
6034}
6035
6036/**
6037 * xmlXPathFalseFunction:
6038 * @ctxt: the XPath Parser context
6039 * @nargs: the number of arguments
6040 *
6041 * Implement the false() XPath function
6042 * boolean false()
6043 */
6044void
6045xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6046 CHECK_ARITY(0);
6047 valuePush(ctxt, xmlXPathNewBoolean(0));
6048}
6049
6050/**
6051 * xmlXPathLangFunction:
6052 * @ctxt: the XPath Parser context
6053 * @nargs: the number of arguments
6054 *
6055 * Implement the lang() XPath function
6056 * boolean lang(string)
6057 * The lang function returns true or false depending on whether the
6058 * language of the context node as specified by xml:lang attributes
6059 * is the same as or is a sublanguage of the language specified by
6060 * the argument string. The language of the context node is determined
6061 * by the value of the xml:lang attribute on the context node, or, if
6062 * the context node has no xml:lang attribute, by the value of the
6063 * xml:lang attribute on the nearest ancestor of the context node that
6064 * has an xml:lang attribute. If there is no such attribute, then lang
6065 * returns false. If there is such an attribute, then lang returns
6066 * true if the attribute value is equal to the argument ignoring case,
6067 * or if there is some suffix starting with - such that the attribute
6068 * value is equal to the argument ignoring that suffix of the attribute
6069 * value and ignoring case.
6070 */
6071void
6072xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6073 xmlXPathObjectPtr val;
6074 const xmlChar *theLang;
6075 const xmlChar *lang;
6076 int ret = 0;
6077 int i;
6078
6079 CHECK_ARITY(1);
6080 CAST_TO_STRING;
6081 CHECK_TYPE(XPATH_STRING);
6082 val = valuePop(ctxt);
6083 lang = val->stringval;
6084 theLang = xmlNodeGetLang(ctxt->context->node);
6085 if ((theLang != NULL) && (lang != NULL)) {
6086 for (i = 0;lang[i] != 0;i++)
6087 if (toupper(lang[i]) != toupper(theLang[i]))
6088 goto not_equal;
6089 ret = 1;
6090 }
6091not_equal:
6092 xmlXPathFreeObject(val);
6093 valuePush(ctxt, xmlXPathNewBoolean(ret));
6094}
6095
6096/**
6097 * xmlXPathNumberFunction:
6098 * @ctxt: the XPath Parser context
6099 * @nargs: the number of arguments
6100 *
6101 * Implement the number() XPath function
6102 * number number(object?)
6103 */
6104void
6105xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6106 xmlXPathObjectPtr cur;
6107 double res;
6108
6109 if (nargs == 0) {
6110 if (ctxt->context->node == NULL) {
6111 valuePush(ctxt, xmlXPathNewFloat(0.0));
6112 } else {
6113 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6114
6115 res = xmlXPathStringEvalNumber(content);
6116 valuePush(ctxt, xmlXPathNewFloat(res));
6117 xmlFree(content);
6118 }
6119 return;
6120 }
6121
6122 CHECK_ARITY(1);
6123 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006124 cur = xmlXPathConvertNumber(cur);
6125 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006126}
6127
6128/**
6129 * xmlXPathSumFunction:
6130 * @ctxt: the XPath Parser context
6131 * @nargs: the number of arguments
6132 *
6133 * Implement the sum() XPath function
6134 * number sum(node-set)
6135 * The sum function returns the sum of the values of the nodes in
6136 * the argument node-set.
6137 */
6138void
6139xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6140 xmlXPathObjectPtr cur;
6141 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006142 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006143
6144 CHECK_ARITY(1);
6145 if ((ctxt->value == NULL) ||
6146 ((ctxt->value->type != XPATH_NODESET) &&
6147 (ctxt->value->type != XPATH_XSLT_TREE)))
6148 XP_ERROR(XPATH_INVALID_TYPE);
6149 cur = valuePop(ctxt);
6150
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006151 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006152 valuePush(ctxt, xmlXPathNewFloat(0.0));
6153 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006154 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6155 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006156 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006157 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006158 }
6159 xmlXPathFreeObject(cur);
6160}
6161
6162/**
6163 * xmlXPathFloorFunction:
6164 * @ctxt: the XPath Parser context
6165 * @nargs: the number of arguments
6166 *
6167 * Implement the floor() XPath function
6168 * number floor(number)
6169 * The floor function returns the largest (closest to positive infinity)
6170 * number that is not greater than the argument and that is an integer.
6171 */
6172void
6173xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6174 CHECK_ARITY(1);
6175 CAST_TO_NUMBER;
6176 CHECK_TYPE(XPATH_NUMBER);
6177#if 0
6178 ctxt->value->floatval = floor(ctxt->value->floatval);
6179#else
6180 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6181 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6182#endif
6183}
6184
6185/**
6186 * xmlXPathCeilingFunction:
6187 * @ctxt: the XPath Parser context
6188 * @nargs: the number of arguments
6189 *
6190 * Implement the ceiling() XPath function
6191 * number ceiling(number)
6192 * The ceiling function returns the smallest (closest to negative infinity)
6193 * number that is not less than the argument and that is an integer.
6194 */
6195void
6196xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6197 double f;
6198
6199 CHECK_ARITY(1);
6200 CAST_TO_NUMBER;
6201 CHECK_TYPE(XPATH_NUMBER);
6202
6203#if 0
6204 ctxt->value->floatval = ceil(ctxt->value->floatval);
6205#else
6206 f = (double)((int) ctxt->value->floatval);
6207 if (f != ctxt->value->floatval)
6208 ctxt->value->floatval = f + 1;
6209#endif
6210}
6211
6212/**
6213 * xmlXPathRoundFunction:
6214 * @ctxt: the XPath Parser context
6215 * @nargs: the number of arguments
6216 *
6217 * Implement the round() XPath function
6218 * number round(number)
6219 * The round function returns the number that is closest to the
6220 * argument and that is an integer. If there are two such numbers,
6221 * then the one that is even is returned.
6222 */
6223void
6224xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6225 double f;
6226
6227 CHECK_ARITY(1);
6228 CAST_TO_NUMBER;
6229 CHECK_TYPE(XPATH_NUMBER);
6230
Daniel Veillardcda96922001-08-21 10:56:31 +00006231 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6232 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6233 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006234 (ctxt->value->floatval == 0.0))
6235 return;
6236
6237#if 0
6238 f = floor(ctxt->value->floatval);
6239#else
6240 f = (double)((int) ctxt->value->floatval);
6241#endif
6242 if (ctxt->value->floatval < f + 0.5)
6243 ctxt->value->floatval = f;
6244 else
6245 ctxt->value->floatval = f + 1;
6246}
6247
6248/************************************************************************
6249 * *
6250 * The Parser *
6251 * *
6252 ************************************************************************/
6253
6254/*
6255 * a couple of forward declarations since we use a recursive call based
6256 * implementation.
6257 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006258static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006259static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006260static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006261#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006262static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6263#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006264#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006265static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006266#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006267static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6268 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006269
6270/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006271 * xmlXPathCurrentChar:
6272 * @ctxt: the XPath parser context
6273 * @cur: pointer to the beginning of the char
6274 * @len: pointer to the length of the char read
6275 *
6276 * The current char value, if using UTF-8 this may actaully span multiple
6277 * bytes in the input buffer.
6278 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006279 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006280 */
6281
6282static int
6283xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6284 unsigned char c;
6285 unsigned int val;
6286 const xmlChar *cur;
6287
6288 if (ctxt == NULL)
6289 return(0);
6290 cur = ctxt->cur;
6291
6292 /*
6293 * We are supposed to handle UTF8, check it's valid
6294 * From rfc2044: encoding of the Unicode values on UTF-8:
6295 *
6296 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6297 * 0000 0000-0000 007F 0xxxxxxx
6298 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6299 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6300 *
6301 * Check for the 0x110000 limit too
6302 */
6303 c = *cur;
6304 if (c & 0x80) {
6305 if ((cur[1] & 0xc0) != 0x80)
6306 goto encoding_error;
6307 if ((c & 0xe0) == 0xe0) {
6308
6309 if ((cur[2] & 0xc0) != 0x80)
6310 goto encoding_error;
6311 if ((c & 0xf0) == 0xf0) {
6312 if (((c & 0xf8) != 0xf0) ||
6313 ((cur[3] & 0xc0) != 0x80))
6314 goto encoding_error;
6315 /* 4-byte code */
6316 *len = 4;
6317 val = (cur[0] & 0x7) << 18;
6318 val |= (cur[1] & 0x3f) << 12;
6319 val |= (cur[2] & 0x3f) << 6;
6320 val |= cur[3] & 0x3f;
6321 } else {
6322 /* 3-byte code */
6323 *len = 3;
6324 val = (cur[0] & 0xf) << 12;
6325 val |= (cur[1] & 0x3f) << 6;
6326 val |= cur[2] & 0x3f;
6327 }
6328 } else {
6329 /* 2-byte code */
6330 *len = 2;
6331 val = (cur[0] & 0x1f) << 6;
6332 val |= cur[1] & 0x3f;
6333 }
6334 if (!IS_CHAR(val)) {
6335 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6336 }
6337 return(val);
6338 } else {
6339 /* 1-byte code */
6340 *len = 1;
6341 return((int) *cur);
6342 }
6343encoding_error:
6344 /*
6345 * If we detect an UTF8 error that probably mean that the
6346 * input encoding didn't get properly advertized in the
6347 * declaration header. Report the error and switch the encoding
6348 * to ISO-Latin-1 (if you don't like this policy, just declare the
6349 * encoding !)
6350 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006351 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006352 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006353}
6354
6355/**
Owen Taylor3473f882001-02-23 17:55:21 +00006356 * xmlXPathParseNCName:
6357 * @ctxt: the XPath Parser context
6358 *
6359 * parse an XML namespace non qualified name.
6360 *
6361 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6362 *
6363 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6364 * CombiningChar | Extender
6365 *
6366 * Returns the namespace name or NULL
6367 */
6368
6369xmlChar *
6370xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006371 const xmlChar *in;
6372 xmlChar *ret;
6373 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006374
Daniel Veillard2156a562001-04-28 12:24:34 +00006375 /*
6376 * Accelerator for simple ASCII names
6377 */
6378 in = ctxt->cur;
6379 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6380 ((*in >= 0x41) && (*in <= 0x5A)) ||
6381 (*in == '_')) {
6382 in++;
6383 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6384 ((*in >= 0x41) && (*in <= 0x5A)) ||
6385 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006386 (*in == '_') || (*in == '.') ||
6387 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006388 in++;
6389 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6390 (*in == '[') || (*in == ']') || (*in == ':') ||
6391 (*in == '@') || (*in == '*')) {
6392 count = in - ctxt->cur;
6393 if (count == 0)
6394 return(NULL);
6395 ret = xmlStrndup(ctxt->cur, count);
6396 ctxt->cur = in;
6397 return(ret);
6398 }
6399 }
6400 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006401}
6402
Daniel Veillard2156a562001-04-28 12:24:34 +00006403
Owen Taylor3473f882001-02-23 17:55:21 +00006404/**
6405 * xmlXPathParseQName:
6406 * @ctxt: the XPath Parser context
6407 * @prefix: a xmlChar **
6408 *
6409 * parse an XML qualified name
6410 *
6411 * [NS 5] QName ::= (Prefix ':')? LocalPart
6412 *
6413 * [NS 6] Prefix ::= NCName
6414 *
6415 * [NS 7] LocalPart ::= NCName
6416 *
6417 * Returns the function returns the local part, and prefix is updated
6418 * to get the Prefix if any.
6419 */
6420
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006421static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006422xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6423 xmlChar *ret = NULL;
6424
6425 *prefix = NULL;
6426 ret = xmlXPathParseNCName(ctxt);
6427 if (CUR == ':') {
6428 *prefix = ret;
6429 NEXT;
6430 ret = xmlXPathParseNCName(ctxt);
6431 }
6432 return(ret);
6433}
6434
6435/**
6436 * xmlXPathParseName:
6437 * @ctxt: the XPath Parser context
6438 *
6439 * parse an XML name
6440 *
6441 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6442 * CombiningChar | Extender
6443 *
6444 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6445 *
6446 * Returns the namespace name or NULL
6447 */
6448
6449xmlChar *
6450xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006451 const xmlChar *in;
6452 xmlChar *ret;
6453 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006454
Daniel Veillard61d80a22001-04-27 17:13:01 +00006455 /*
6456 * Accelerator for simple ASCII names
6457 */
6458 in = ctxt->cur;
6459 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6460 ((*in >= 0x41) && (*in <= 0x5A)) ||
6461 (*in == '_') || (*in == ':')) {
6462 in++;
6463 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6464 ((*in >= 0x41) && (*in <= 0x5A)) ||
6465 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006466 (*in == '_') || (*in == '-') ||
6467 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006468 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006469 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006470 count = in - ctxt->cur;
6471 ret = xmlStrndup(ctxt->cur, count);
6472 ctxt->cur = in;
6473 return(ret);
6474 }
6475 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006476 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006477}
6478
Daniel Veillard61d80a22001-04-27 17:13:01 +00006479static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006480xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006481 xmlChar buf[XML_MAX_NAMELEN + 5];
6482 int len = 0, l;
6483 int c;
6484
6485 /*
6486 * Handler for more complex cases
6487 */
6488 c = CUR_CHAR(l);
6489 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006490 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6491 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006492 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006493 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006494 return(NULL);
6495 }
6496
6497 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6498 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6499 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006500 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006501 (IS_COMBINING(c)) ||
6502 (IS_EXTENDER(c)))) {
6503 COPY_BUF(l,buf,len,c);
6504 NEXTL(l);
6505 c = CUR_CHAR(l);
6506 if (len >= XML_MAX_NAMELEN) {
6507 /*
6508 * Okay someone managed to make a huge name, so he's ready to pay
6509 * for the processing speed.
6510 */
6511 xmlChar *buffer;
6512 int max = len * 2;
6513
6514 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6515 if (buffer == NULL) {
6516 XP_ERROR0(XPATH_MEMORY_ERROR);
6517 }
6518 memcpy(buffer, buf, len);
6519 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6520 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006521 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006522 (IS_COMBINING(c)) ||
6523 (IS_EXTENDER(c))) {
6524 if (len + 10 > max) {
6525 max *= 2;
6526 buffer = (xmlChar *) xmlRealloc(buffer,
6527 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006528 if (buffer == NULL) {
6529 XP_ERROR0(XPATH_MEMORY_ERROR);
6530 }
6531 }
6532 COPY_BUF(l,buffer,len,c);
6533 NEXTL(l);
6534 c = CUR_CHAR(l);
6535 }
6536 buffer[len] = 0;
6537 return(buffer);
6538 }
6539 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006540 if (len == 0)
6541 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006542 return(xmlStrndup(buf, len));
6543}
Owen Taylor3473f882001-02-23 17:55:21 +00006544/**
6545 * xmlXPathStringEvalNumber:
6546 * @str: A string to scan
6547 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006548 * [30a] Float ::= Number ('e' Digits?)?
6549 *
Owen Taylor3473f882001-02-23 17:55:21 +00006550 * [30] Number ::= Digits ('.' Digits?)?
6551 * | '.' Digits
6552 * [31] Digits ::= [0-9]+
6553 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006554 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006555 * In complement of the Number expression, this function also handles
6556 * negative values : '-' Number.
6557 *
6558 * Returns the double value.
6559 */
6560double
6561xmlXPathStringEvalNumber(const xmlChar *str) {
6562 const xmlChar *cur = str;
6563 double ret = 0.0;
6564 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006565 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006566 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006567 int exponent = 0;
6568 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006569#ifdef __GNUC__
6570 unsigned long tmp = 0;
6571#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006572
Owen Taylor3473f882001-02-23 17:55:21 +00006573 while (IS_BLANK(*cur)) cur++;
6574 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6575 return(xmlXPathNAN);
6576 }
6577 if (*cur == '-') {
6578 isneg = 1;
6579 cur++;
6580 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006581
6582#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006583 /*
Daniel Veillardb06c6142001-08-27 14:26:30 +00006584 * tmp is a workaround against a gcc compiler bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006585 */
Owen Taylor3473f882001-02-23 17:55:21 +00006586 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006587 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006588 ok = 1;
6589 cur++;
6590 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006591 ret = (double) tmp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006592#else
6593 while ((*cur >= '0') && (*cur <= '9')) {
6594 ret = ret * 10 + (*cur - '0');
6595 ok = 1;
6596 cur++;
6597 }
6598#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006599
Owen Taylor3473f882001-02-23 17:55:21 +00006600 if (*cur == '.') {
6601 cur++;
6602 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6603 return(xmlXPathNAN);
6604 }
6605 while ((*cur >= '0') && (*cur <= '9')) {
6606 mult /= 10;
6607 ret = ret + (*cur - '0') * mult;
6608 cur++;
6609 }
6610 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006611 if ((*cur == 'e') || (*cur == 'E')) {
6612 cur++;
6613 if (*cur == '-') {
6614 is_exponent_negative = 1;
6615 cur++;
6616 }
6617 while ((*cur >= '0') && (*cur <= '9')) {
6618 exponent = exponent * 10 + (*cur - '0');
6619 cur++;
6620 }
6621 }
Owen Taylor3473f882001-02-23 17:55:21 +00006622 while (IS_BLANK(*cur)) cur++;
6623 if (*cur != 0) return(xmlXPathNAN);
6624 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006625 if (is_exponent_negative) exponent = -exponent;
6626 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006627 return(ret);
6628}
6629
6630/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006631 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006632 * @ctxt: the XPath Parser context
6633 *
6634 * [30] Number ::= Digits ('.' Digits?)?
6635 * | '.' Digits
6636 * [31] Digits ::= [0-9]+
6637 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006638 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006639 *
6640 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006641static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006642xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6643{
Owen Taylor3473f882001-02-23 17:55:21 +00006644 double ret = 0.0;
6645 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006646 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006647 int exponent = 0;
6648 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006649
6650 CHECK_ERROR;
6651 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6652 XP_ERROR(XPATH_NUMBER_ERROR);
6653 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006654 /*
6655 * Try to work around a gcc optimizer bug
6656 */
Owen Taylor3473f882001-02-23 17:55:21 +00006657 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006658 tmp = tmp * 10 + (CUR - '0');
6659 ok = 1;
6660 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006661 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006662 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006663 if (CUR == '.') {
6664 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006665 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6666 XP_ERROR(XPATH_NUMBER_ERROR);
6667 }
6668 while ((CUR >= '0') && (CUR <= '9')) {
6669 mult /= 10;
6670 ret = ret + (CUR - '0') * mult;
6671 NEXT;
6672 }
Owen Taylor3473f882001-02-23 17:55:21 +00006673 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006674 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006675 NEXT;
6676 if (CUR == '-') {
6677 is_exponent_negative = 1;
6678 NEXT;
6679 }
6680 while ((CUR >= '0') && (CUR <= '9')) {
6681 exponent = exponent * 10 + (CUR - '0');
6682 NEXT;
6683 }
6684 if (is_exponent_negative)
6685 exponent = -exponent;
6686 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006687 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006688 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006689 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006690}
6691
6692/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006693 * xmlXPathParseLiteral:
6694 * @ctxt: the XPath Parser context
6695 *
6696 * Parse a Literal
6697 *
6698 * [29] Literal ::= '"' [^"]* '"'
6699 * | "'" [^']* "'"
6700 *
6701 * Returns the value found or NULL in case of error
6702 */
6703static xmlChar *
6704xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6705 const xmlChar *q;
6706 xmlChar *ret = NULL;
6707
6708 if (CUR == '"') {
6709 NEXT;
6710 q = CUR_PTR;
6711 while ((IS_CHAR(CUR)) && (CUR != '"'))
6712 NEXT;
6713 if (!IS_CHAR(CUR)) {
6714 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6715 } else {
6716 ret = xmlStrndup(q, CUR_PTR - q);
6717 NEXT;
6718 }
6719 } else if (CUR == '\'') {
6720 NEXT;
6721 q = CUR_PTR;
6722 while ((IS_CHAR(CUR)) && (CUR != '\''))
6723 NEXT;
6724 if (!IS_CHAR(CUR)) {
6725 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6726 } else {
6727 ret = xmlStrndup(q, CUR_PTR - q);
6728 NEXT;
6729 }
6730 } else {
6731 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6732 }
6733 return(ret);
6734}
6735
6736/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006737 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006738 * @ctxt: the XPath Parser context
6739 *
6740 * Parse a Literal and push it on the stack.
6741 *
6742 * [29] Literal ::= '"' [^"]* '"'
6743 * | "'" [^']* "'"
6744 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006745 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006746 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006747static void
6748xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006749 const xmlChar *q;
6750 xmlChar *ret = NULL;
6751
6752 if (CUR == '"') {
6753 NEXT;
6754 q = CUR_PTR;
6755 while ((IS_CHAR(CUR)) && (CUR != '"'))
6756 NEXT;
6757 if (!IS_CHAR(CUR)) {
6758 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6759 } else {
6760 ret = xmlStrndup(q, CUR_PTR - q);
6761 NEXT;
6762 }
6763 } else if (CUR == '\'') {
6764 NEXT;
6765 q = CUR_PTR;
6766 while ((IS_CHAR(CUR)) && (CUR != '\''))
6767 NEXT;
6768 if (!IS_CHAR(CUR)) {
6769 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6770 } else {
6771 ret = xmlStrndup(q, CUR_PTR - q);
6772 NEXT;
6773 }
6774 } else {
6775 XP_ERROR(XPATH_START_LITERAL_ERROR);
6776 }
6777 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006778 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6779 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006780 xmlFree(ret);
6781}
6782
6783/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006784 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006785 * @ctxt: the XPath Parser context
6786 *
6787 * Parse a VariableReference, evaluate it and push it on the stack.
6788 *
6789 * The variable bindings consist of a mapping from variable names
6790 * to variable values. The value of a variable is an object, which
6791 * of any of the types that are possible for the value of an expression,
6792 * and may also be of additional types not specified here.
6793 *
6794 * Early evaluation is possible since:
6795 * The variable bindings [...] used to evaluate a subexpression are
6796 * always the same as those used to evaluate the containing expression.
6797 *
6798 * [36] VariableReference ::= '$' QName
6799 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006800static void
6801xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006802 xmlChar *name;
6803 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006804
6805 SKIP_BLANKS;
6806 if (CUR != '$') {
6807 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6808 }
6809 NEXT;
6810 name = xmlXPathParseQName(ctxt, &prefix);
6811 if (name == NULL) {
6812 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6813 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006814 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006815 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6816 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006817 SKIP_BLANKS;
6818}
6819
6820/**
6821 * xmlXPathIsNodeType:
6822 * @ctxt: the XPath Parser context
6823 * @name: a name string
6824 *
6825 * Is the name given a NodeType one.
6826 *
6827 * [38] NodeType ::= 'comment'
6828 * | 'text'
6829 * | 'processing-instruction'
6830 * | 'node'
6831 *
6832 * Returns 1 if true 0 otherwise
6833 */
6834int
6835xmlXPathIsNodeType(const xmlChar *name) {
6836 if (name == NULL)
6837 return(0);
6838
6839 if (xmlStrEqual(name, BAD_CAST "comment"))
6840 return(1);
6841 if (xmlStrEqual(name, BAD_CAST "text"))
6842 return(1);
6843 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6844 return(1);
6845 if (xmlStrEqual(name, BAD_CAST "node"))
6846 return(1);
6847 return(0);
6848}
6849
6850/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006851 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006852 * @ctxt: the XPath Parser context
6853 *
6854 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6855 * [17] Argument ::= Expr
6856 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006857 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006858 * pushed on the stack
6859 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006860static void
6861xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006862 xmlChar *name;
6863 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006864 int nbargs = 0;
6865
6866 name = xmlXPathParseQName(ctxt, &prefix);
6867 if (name == NULL) {
6868 XP_ERROR(XPATH_EXPR_ERROR);
6869 }
6870 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006871#ifdef DEBUG_EXPR
6872 if (prefix == NULL)
6873 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6874 name);
6875 else
6876 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6877 prefix, name);
6878#endif
6879
Owen Taylor3473f882001-02-23 17:55:21 +00006880 if (CUR != '(') {
6881 XP_ERROR(XPATH_EXPR_ERROR);
6882 }
6883 NEXT;
6884 SKIP_BLANKS;
6885
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006886 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006887 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006888 int op1 = ctxt->comp->last;
6889 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006890 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006891 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006892 nbargs++;
6893 if (CUR == ')') break;
6894 if (CUR != ',') {
6895 XP_ERROR(XPATH_EXPR_ERROR);
6896 }
6897 NEXT;
6898 SKIP_BLANKS;
6899 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006900 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6901 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006902 NEXT;
6903 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006904}
6905
6906/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006907 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006908 * @ctxt: the XPath Parser context
6909 *
6910 * [15] PrimaryExpr ::= VariableReference
6911 * | '(' Expr ')'
6912 * | Literal
6913 * | Number
6914 * | FunctionCall
6915 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006916 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006917 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006918static void
6919xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006920 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006921 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006922 else if (CUR == '(') {
6923 NEXT;
6924 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006925 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006926 if (CUR != ')') {
6927 XP_ERROR(XPATH_EXPR_ERROR);
6928 }
6929 NEXT;
6930 SKIP_BLANKS;
6931 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006932 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006933 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006934 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006935 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006936 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006937 }
6938 SKIP_BLANKS;
6939}
6940
6941/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006942 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006943 * @ctxt: the XPath Parser context
6944 *
6945 * [20] FilterExpr ::= PrimaryExpr
6946 * | FilterExpr Predicate
6947 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006948 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006949 * Square brackets are used to filter expressions in the same way that
6950 * they are used in location paths. It is an error if the expression to
6951 * be filtered does not evaluate to a node-set. The context node list
6952 * used for evaluating the expression in square brackets is the node-set
6953 * to be filtered listed in document order.
6954 */
6955
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006956static void
6957xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6958 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006959 CHECK_ERROR;
6960 SKIP_BLANKS;
6961
6962 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006963 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006964 SKIP_BLANKS;
6965 }
6966
6967
6968}
6969
6970/**
6971 * xmlXPathScanName:
6972 * @ctxt: the XPath Parser context
6973 *
6974 * Trickery: parse an XML name but without consuming the input flow
6975 * Needed to avoid insanity in the parser state.
6976 *
6977 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6978 * CombiningChar | Extender
6979 *
6980 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6981 *
6982 * [6] Names ::= Name (S Name)*
6983 *
6984 * Returns the Name parsed or NULL
6985 */
6986
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006987static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006988xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6989 xmlChar buf[XML_MAX_NAMELEN];
6990 int len = 0;
6991
6992 SKIP_BLANKS;
6993 if (!IS_LETTER(CUR) && (CUR != '_') &&
6994 (CUR != ':')) {
6995 return(NULL);
6996 }
6997
6998 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6999 (NXT(len) == '.') || (NXT(len) == '-') ||
7000 (NXT(len) == '_') || (NXT(len) == ':') ||
7001 (IS_COMBINING(NXT(len))) ||
7002 (IS_EXTENDER(NXT(len)))) {
7003 buf[len] = NXT(len);
7004 len++;
7005 if (len >= XML_MAX_NAMELEN) {
7006 xmlGenericError(xmlGenericErrorContext,
7007 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7008 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7009 (NXT(len) == '.') || (NXT(len) == '-') ||
7010 (NXT(len) == '_') || (NXT(len) == ':') ||
7011 (IS_COMBINING(NXT(len))) ||
7012 (IS_EXTENDER(NXT(len))))
7013 len++;
7014 break;
7015 }
7016 }
7017 return(xmlStrndup(buf, len));
7018}
7019
7020/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007021 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007022 * @ctxt: the XPath Parser context
7023 *
7024 * [19] PathExpr ::= LocationPath
7025 * | FilterExpr
7026 * | FilterExpr '/' RelativeLocationPath
7027 * | FilterExpr '//' RelativeLocationPath
7028 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007029 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007030 * The / operator and // operators combine an arbitrary expression
7031 * and a relative location path. It is an error if the expression
7032 * does not evaluate to a node-set.
7033 * The / operator does composition in the same way as when / is
7034 * used in a location path. As in location paths, // is short for
7035 * /descendant-or-self::node()/.
7036 */
7037
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007038static void
7039xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007040 int lc = 1; /* Should we branch to LocationPath ? */
7041 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7042
7043 SKIP_BLANKS;
7044 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7045 (CUR == '\'') || (CUR == '"')) {
7046 lc = 0;
7047 } else if (CUR == '*') {
7048 /* relative or absolute location path */
7049 lc = 1;
7050 } else if (CUR == '/') {
7051 /* relative or absolute location path */
7052 lc = 1;
7053 } else if (CUR == '@') {
7054 /* relative abbreviated attribute location path */
7055 lc = 1;
7056 } else if (CUR == '.') {
7057 /* relative abbreviated attribute location path */
7058 lc = 1;
7059 } else {
7060 /*
7061 * Problem is finding if we have a name here whether it's:
7062 * - a nodetype
7063 * - a function call in which case it's followed by '('
7064 * - an axis in which case it's followed by ':'
7065 * - a element name
7066 * We do an a priori analysis here rather than having to
7067 * maintain parsed token content through the recursive function
7068 * calls. This looks uglier but makes the code quite easier to
7069 * read/write/debug.
7070 */
7071 SKIP_BLANKS;
7072 name = xmlXPathScanName(ctxt);
7073 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7074#ifdef DEBUG_STEP
7075 xmlGenericError(xmlGenericErrorContext,
7076 "PathExpr: Axis\n");
7077#endif
7078 lc = 1;
7079 xmlFree(name);
7080 } else if (name != NULL) {
7081 int len =xmlStrlen(name);
7082 int blank = 0;
7083
7084
7085 while (NXT(len) != 0) {
7086 if (NXT(len) == '/') {
7087 /* element name */
7088#ifdef DEBUG_STEP
7089 xmlGenericError(xmlGenericErrorContext,
7090 "PathExpr: AbbrRelLocation\n");
7091#endif
7092 lc = 1;
7093 break;
7094 } else if (IS_BLANK(NXT(len))) {
7095 /* skip to next */
7096 blank = 1;
7097 } else if (NXT(len) == ':') {
7098#ifdef DEBUG_STEP
7099 xmlGenericError(xmlGenericErrorContext,
7100 "PathExpr: AbbrRelLocation\n");
7101#endif
7102 lc = 1;
7103 break;
7104 } else if ((NXT(len) == '(')) {
7105 /* Note Type or Function */
7106 if (xmlXPathIsNodeType(name)) {
7107#ifdef DEBUG_STEP
7108 xmlGenericError(xmlGenericErrorContext,
7109 "PathExpr: Type search\n");
7110#endif
7111 lc = 1;
7112 } else {
7113#ifdef DEBUG_STEP
7114 xmlGenericError(xmlGenericErrorContext,
7115 "PathExpr: function call\n");
7116#endif
7117 lc = 0;
7118 }
7119 break;
7120 } else if ((NXT(len) == '[')) {
7121 /* element name */
7122#ifdef DEBUG_STEP
7123 xmlGenericError(xmlGenericErrorContext,
7124 "PathExpr: AbbrRelLocation\n");
7125#endif
7126 lc = 1;
7127 break;
7128 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7129 (NXT(len) == '=')) {
7130 lc = 1;
7131 break;
7132 } else {
7133 lc = 1;
7134 break;
7135 }
7136 len++;
7137 }
7138 if (NXT(len) == 0) {
7139#ifdef DEBUG_STEP
7140 xmlGenericError(xmlGenericErrorContext,
7141 "PathExpr: AbbrRelLocation\n");
7142#endif
7143 /* element name */
7144 lc = 1;
7145 }
7146 xmlFree(name);
7147 } else {
7148 /* make sure all cases are covered explicitely */
7149 XP_ERROR(XPATH_EXPR_ERROR);
7150 }
7151 }
7152
7153 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007154 if (CUR == '/') {
7155 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7156 } else {
7157 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007158 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007159 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007160 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007161 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007162 CHECK_ERROR;
7163 if ((CUR == '/') && (NXT(1) == '/')) {
7164 SKIP(2);
7165 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007166
7167 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7168 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7169 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7170
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007171 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007172 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007173 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007174 }
7175 }
7176 SKIP_BLANKS;
7177}
7178
7179/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007180 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007181 * @ctxt: the XPath Parser context
7182 *
7183 * [18] UnionExpr ::= PathExpr
7184 * | UnionExpr '|' PathExpr
7185 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007186 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007187 */
7188
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007189static void
7190xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7191 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007192 CHECK_ERROR;
7193 SKIP_BLANKS;
7194 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007195 int op1 = ctxt->comp->last;
7196 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007197
7198 NEXT;
7199 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007200 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007201
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007202 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7203
Owen Taylor3473f882001-02-23 17:55:21 +00007204 SKIP_BLANKS;
7205 }
Owen Taylor3473f882001-02-23 17:55:21 +00007206}
7207
7208/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007209 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007210 * @ctxt: the XPath Parser context
7211 *
7212 * [27] UnaryExpr ::= UnionExpr
7213 * | '-' UnaryExpr
7214 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007215 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007216 */
7217
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007218static void
7219xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007220 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007221 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007222
7223 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007224 while (CUR == '-') {
7225 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007226 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007227 NEXT;
7228 SKIP_BLANKS;
7229 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007230
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007231 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007232 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007233 if (found) {
7234 if (minus)
7235 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7236 else
7237 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007238 }
7239}
7240
7241/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007242 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007243 * @ctxt: the XPath Parser context
7244 *
7245 * [26] MultiplicativeExpr ::= UnaryExpr
7246 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7247 * | MultiplicativeExpr 'div' UnaryExpr
7248 * | MultiplicativeExpr 'mod' UnaryExpr
7249 * [34] MultiplyOperator ::= '*'
7250 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007251 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007252 */
7253
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007254static void
7255xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7256 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007257 CHECK_ERROR;
7258 SKIP_BLANKS;
7259 while ((CUR == '*') ||
7260 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7261 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7262 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007263 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007264
7265 if (CUR == '*') {
7266 op = 0;
7267 NEXT;
7268 } else if (CUR == 'd') {
7269 op = 1;
7270 SKIP(3);
7271 } else if (CUR == 'm') {
7272 op = 2;
7273 SKIP(3);
7274 }
7275 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007276 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007277 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007278 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007279 SKIP_BLANKS;
7280 }
7281}
7282
7283/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007284 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007285 * @ctxt: the XPath Parser context
7286 *
7287 * [25] AdditiveExpr ::= MultiplicativeExpr
7288 * | AdditiveExpr '+' MultiplicativeExpr
7289 * | AdditiveExpr '-' MultiplicativeExpr
7290 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007291 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007292 */
7293
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007294static void
7295xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007296
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007297 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007298 CHECK_ERROR;
7299 SKIP_BLANKS;
7300 while ((CUR == '+') || (CUR == '-')) {
7301 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007302 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007303
7304 if (CUR == '+') plus = 1;
7305 else plus = 0;
7306 NEXT;
7307 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007308 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007309 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007310 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007311 SKIP_BLANKS;
7312 }
7313}
7314
7315/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007316 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007317 * @ctxt: the XPath Parser context
7318 *
7319 * [24] RelationalExpr ::= AdditiveExpr
7320 * | RelationalExpr '<' AdditiveExpr
7321 * | RelationalExpr '>' AdditiveExpr
7322 * | RelationalExpr '<=' AdditiveExpr
7323 * | RelationalExpr '>=' AdditiveExpr
7324 *
7325 * A <= B > C is allowed ? Answer from James, yes with
7326 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7327 * which is basically what got implemented.
7328 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007329 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007330 * on the stack
7331 */
7332
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007333static void
7334xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7335 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007336 CHECK_ERROR;
7337 SKIP_BLANKS;
7338 while ((CUR == '<') ||
7339 (CUR == '>') ||
7340 ((CUR == '<') && (NXT(1) == '=')) ||
7341 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007342 int inf, strict;
7343 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007344
7345 if (CUR == '<') inf = 1;
7346 else inf = 0;
7347 if (NXT(1) == '=') strict = 0;
7348 else strict = 1;
7349 NEXT;
7350 if (!strict) NEXT;
7351 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007352 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007353 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007354 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007355 SKIP_BLANKS;
7356 }
7357}
7358
7359/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007360 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007361 * @ctxt: the XPath Parser context
7362 *
7363 * [23] EqualityExpr ::= RelationalExpr
7364 * | EqualityExpr '=' RelationalExpr
7365 * | EqualityExpr '!=' RelationalExpr
7366 *
7367 * A != B != C is allowed ? Answer from James, yes with
7368 * (RelationalExpr = RelationalExpr) = RelationalExpr
7369 * (RelationalExpr != RelationalExpr) != RelationalExpr
7370 * which is basically what got implemented.
7371 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007372 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007373 *
7374 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007375static void
7376xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7377 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007378 CHECK_ERROR;
7379 SKIP_BLANKS;
7380 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007381 int eq;
7382 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007383
7384 if (CUR == '=') eq = 1;
7385 else eq = 0;
7386 NEXT;
7387 if (!eq) NEXT;
7388 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007389 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007390 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007391 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007392 SKIP_BLANKS;
7393 }
7394}
7395
7396/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007397 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007398 * @ctxt: the XPath Parser context
7399 *
7400 * [22] AndExpr ::= EqualityExpr
7401 * | AndExpr 'and' EqualityExpr
7402 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007403 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007404 *
7405 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007406static void
7407xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7408 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007409 CHECK_ERROR;
7410 SKIP_BLANKS;
7411 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007412 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007413 SKIP(3);
7414 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007415 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007416 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007417 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007418 SKIP_BLANKS;
7419 }
7420}
7421
7422/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007423 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007424 * @ctxt: the XPath Parser context
7425 *
7426 * [14] Expr ::= OrExpr
7427 * [21] OrExpr ::= AndExpr
7428 * | OrExpr 'or' AndExpr
7429 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007430 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007431 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007432static void
7433xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7434 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007435 CHECK_ERROR;
7436 SKIP_BLANKS;
7437 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007438 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007439 SKIP(2);
7440 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007441 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007442 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007443 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7444 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007445 SKIP_BLANKS;
7446 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007447 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7448 /* more ops could be optimized too */
7449 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7450 }
Owen Taylor3473f882001-02-23 17:55:21 +00007451}
7452
7453/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007454 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007455 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007456 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007457 *
7458 * [8] Predicate ::= '[' PredicateExpr ']'
7459 * [9] PredicateExpr ::= Expr
7460 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007461 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007462 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007463static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007464xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007465 int op1 = ctxt->comp->last;
7466
7467 SKIP_BLANKS;
7468 if (CUR != '[') {
7469 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7470 }
7471 NEXT;
7472 SKIP_BLANKS;
7473
7474 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007475 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007476 CHECK_ERROR;
7477
7478 if (CUR != ']') {
7479 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7480 }
7481
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007482 if (filter)
7483 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7484 else
7485 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007486
7487 NEXT;
7488 SKIP_BLANKS;
7489}
7490
7491/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007492 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007493 * @ctxt: the XPath Parser context
7494 * @test: pointer to a xmlXPathTestVal
7495 * @type: pointer to a xmlXPathTypeVal
7496 * @prefix: placeholder for a possible name prefix
7497 *
7498 * [7] NodeTest ::= NameTest
7499 * | NodeType '(' ')'
7500 * | 'processing-instruction' '(' Literal ')'
7501 *
7502 * [37] NameTest ::= '*'
7503 * | NCName ':' '*'
7504 * | QName
7505 * [38] NodeType ::= 'comment'
7506 * | 'text'
7507 * | 'processing-instruction'
7508 * | 'node'
7509 *
7510 * Returns the name found and update @test, @type and @prefix appropriately
7511 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007512static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007513xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7514 xmlXPathTypeVal *type, const xmlChar **prefix,
7515 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007516 int blanks;
7517
7518 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7519 STRANGE;
7520 return(NULL);
7521 }
7522 *type = 0;
7523 *test = 0;
7524 *prefix = NULL;
7525 SKIP_BLANKS;
7526
7527 if ((name == NULL) && (CUR == '*')) {
7528 /*
7529 * All elements
7530 */
7531 NEXT;
7532 *test = NODE_TEST_ALL;
7533 return(NULL);
7534 }
7535
7536 if (name == NULL)
7537 name = xmlXPathParseNCName(ctxt);
7538 if (name == NULL) {
7539 XP_ERROR0(XPATH_EXPR_ERROR);
7540 }
7541
7542 blanks = IS_BLANK(CUR);
7543 SKIP_BLANKS;
7544 if (CUR == '(') {
7545 NEXT;
7546 /*
7547 * NodeType or PI search
7548 */
7549 if (xmlStrEqual(name, BAD_CAST "comment"))
7550 *type = NODE_TYPE_COMMENT;
7551 else if (xmlStrEqual(name, BAD_CAST "node"))
7552 *type = NODE_TYPE_NODE;
7553 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7554 *type = NODE_TYPE_PI;
7555 else if (xmlStrEqual(name, BAD_CAST "text"))
7556 *type = NODE_TYPE_TEXT;
7557 else {
7558 if (name != NULL)
7559 xmlFree(name);
7560 XP_ERROR0(XPATH_EXPR_ERROR);
7561 }
7562
7563 *test = NODE_TEST_TYPE;
7564
7565 SKIP_BLANKS;
7566 if (*type == NODE_TYPE_PI) {
7567 /*
7568 * Specific case: search a PI by name.
7569 */
Owen Taylor3473f882001-02-23 17:55:21 +00007570 if (name != NULL)
7571 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007572 name = NULL;
7573 if (CUR != ')') {
7574 name = xmlXPathParseLiteral(ctxt);
7575 CHECK_ERROR 0;
7576 SKIP_BLANKS;
7577 }
Owen Taylor3473f882001-02-23 17:55:21 +00007578 }
7579 if (CUR != ')') {
7580 if (name != NULL)
7581 xmlFree(name);
7582 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7583 }
7584 NEXT;
7585 return(name);
7586 }
7587 *test = NODE_TEST_NAME;
7588 if ((!blanks) && (CUR == ':')) {
7589 NEXT;
7590
7591 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007592 * Since currently the parser context don't have a
7593 * namespace list associated:
7594 * The namespace name for this prefix can be computed
7595 * only at evaluation time. The compilation is done
7596 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007597 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007598#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007599 *prefix = xmlXPathNsLookup(ctxt->context, name);
7600 if (name != NULL)
7601 xmlFree(name);
7602 if (*prefix == NULL) {
7603 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7604 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007605#else
7606 *prefix = name;
7607#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007608
7609 if (CUR == '*') {
7610 /*
7611 * All elements
7612 */
7613 NEXT;
7614 *test = NODE_TEST_ALL;
7615 return(NULL);
7616 }
7617
7618 name = xmlXPathParseNCName(ctxt);
7619 if (name == NULL) {
7620 XP_ERROR0(XPATH_EXPR_ERROR);
7621 }
7622 }
7623 return(name);
7624}
7625
7626/**
7627 * xmlXPathIsAxisName:
7628 * @name: a preparsed name token
7629 *
7630 * [6] AxisName ::= 'ancestor'
7631 * | 'ancestor-or-self'
7632 * | 'attribute'
7633 * | 'child'
7634 * | 'descendant'
7635 * | 'descendant-or-self'
7636 * | 'following'
7637 * | 'following-sibling'
7638 * | 'namespace'
7639 * | 'parent'
7640 * | 'preceding'
7641 * | 'preceding-sibling'
7642 * | 'self'
7643 *
7644 * Returns the axis or 0
7645 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007646static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007647xmlXPathIsAxisName(const xmlChar *name) {
7648 xmlXPathAxisVal ret = 0;
7649 switch (name[0]) {
7650 case 'a':
7651 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7652 ret = AXIS_ANCESTOR;
7653 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7654 ret = AXIS_ANCESTOR_OR_SELF;
7655 if (xmlStrEqual(name, BAD_CAST "attribute"))
7656 ret = AXIS_ATTRIBUTE;
7657 break;
7658 case 'c':
7659 if (xmlStrEqual(name, BAD_CAST "child"))
7660 ret = AXIS_CHILD;
7661 break;
7662 case 'd':
7663 if (xmlStrEqual(name, BAD_CAST "descendant"))
7664 ret = AXIS_DESCENDANT;
7665 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7666 ret = AXIS_DESCENDANT_OR_SELF;
7667 break;
7668 case 'f':
7669 if (xmlStrEqual(name, BAD_CAST "following"))
7670 ret = AXIS_FOLLOWING;
7671 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7672 ret = AXIS_FOLLOWING_SIBLING;
7673 break;
7674 case 'n':
7675 if (xmlStrEqual(name, BAD_CAST "namespace"))
7676 ret = AXIS_NAMESPACE;
7677 break;
7678 case 'p':
7679 if (xmlStrEqual(name, BAD_CAST "parent"))
7680 ret = AXIS_PARENT;
7681 if (xmlStrEqual(name, BAD_CAST "preceding"))
7682 ret = AXIS_PRECEDING;
7683 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7684 ret = AXIS_PRECEDING_SIBLING;
7685 break;
7686 case 's':
7687 if (xmlStrEqual(name, BAD_CAST "self"))
7688 ret = AXIS_SELF;
7689 break;
7690 }
7691 return(ret);
7692}
7693
7694/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007695 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007696 * @ctxt: the XPath Parser context
7697 *
7698 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7699 * | AbbreviatedStep
7700 *
7701 * [12] AbbreviatedStep ::= '.' | '..'
7702 *
7703 * [5] AxisSpecifier ::= AxisName '::'
7704 * | AbbreviatedAxisSpecifier
7705 *
7706 * [13] AbbreviatedAxisSpecifier ::= '@'?
7707 *
7708 * Modified for XPtr range support as:
7709 *
7710 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7711 * | AbbreviatedStep
7712 * | 'range-to' '(' Expr ')' Predicate*
7713 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007714 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007715 * A location step of . is short for self::node(). This is
7716 * particularly useful in conjunction with //. For example, the
7717 * location path .//para is short for
7718 * self::node()/descendant-or-self::node()/child::para
7719 * and so will select all para descendant elements of the context
7720 * node.
7721 * Similarly, a location step of .. is short for parent::node().
7722 * For example, ../title is short for parent::node()/child::title
7723 * and so will select the title children of the parent of the context
7724 * node.
7725 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007726static void
7727xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007728#ifdef LIBXML_XPTR_ENABLED
7729 int rangeto = 0;
7730 int op2 = -1;
7731#endif
7732
Owen Taylor3473f882001-02-23 17:55:21 +00007733 SKIP_BLANKS;
7734 if ((CUR == '.') && (NXT(1) == '.')) {
7735 SKIP(2);
7736 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007737 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7738 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007739 } else if (CUR == '.') {
7740 NEXT;
7741 SKIP_BLANKS;
7742 } else {
7743 xmlChar *name = NULL;
7744 const xmlChar *prefix = NULL;
7745 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007746 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007747 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007748 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007749
7750 /*
7751 * The modification needed for XPointer change to the production
7752 */
7753#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007754 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007755 name = xmlXPathParseNCName(ctxt);
7756 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007757 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007758 xmlFree(name);
7759 SKIP_BLANKS;
7760 if (CUR != '(') {
7761 XP_ERROR(XPATH_EXPR_ERROR);
7762 }
7763 NEXT;
7764 SKIP_BLANKS;
7765
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007766 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007767 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007768 CHECK_ERROR;
7769
7770 SKIP_BLANKS;
7771 if (CUR != ')') {
7772 XP_ERROR(XPATH_EXPR_ERROR);
7773 }
7774 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007775 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007776 goto eval_predicates;
7777 }
7778 }
7779#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007780 if (CUR == '*') {
7781 axis = AXIS_CHILD;
7782 } else {
7783 if (name == NULL)
7784 name = xmlXPathParseNCName(ctxt);
7785 if (name != NULL) {
7786 axis = xmlXPathIsAxisName(name);
7787 if (axis != 0) {
7788 SKIP_BLANKS;
7789 if ((CUR == ':') && (NXT(1) == ':')) {
7790 SKIP(2);
7791 xmlFree(name);
7792 name = NULL;
7793 } else {
7794 /* an element name can conflict with an axis one :-\ */
7795 axis = AXIS_CHILD;
7796 }
Owen Taylor3473f882001-02-23 17:55:21 +00007797 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007798 axis = AXIS_CHILD;
7799 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007800 } else if (CUR == '@') {
7801 NEXT;
7802 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007803 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007804 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007805 }
Owen Taylor3473f882001-02-23 17:55:21 +00007806 }
7807
7808 CHECK_ERROR;
7809
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007810 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007811 if (test == 0)
7812 return;
7813
7814#ifdef DEBUG_STEP
7815 xmlGenericError(xmlGenericErrorContext,
7816 "Basis : computing new set\n");
7817#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007818
Owen Taylor3473f882001-02-23 17:55:21 +00007819#ifdef DEBUG_STEP
7820 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007821 if (ctxt->value == NULL)
7822 xmlGenericError(xmlGenericErrorContext, "no value\n");
7823 else if (ctxt->value->nodesetval == NULL)
7824 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7825 else
7826 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007827#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007828
7829eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007830 op1 = ctxt->comp->last;
7831 ctxt->comp->last = -1;
7832
Owen Taylor3473f882001-02-23 17:55:21 +00007833 SKIP_BLANKS;
7834 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007835 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007836 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007837
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007838#ifdef LIBXML_XPTR_ENABLED
7839 if (rangeto) {
7840 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7841 } else
7842#endif
7843 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7844 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007845
Owen Taylor3473f882001-02-23 17:55:21 +00007846 }
7847#ifdef DEBUG_STEP
7848 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007849 if (ctxt->value == NULL)
7850 xmlGenericError(xmlGenericErrorContext, "no value\n");
7851 else if (ctxt->value->nodesetval == NULL)
7852 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7853 else
7854 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7855 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007856#endif
7857}
7858
7859/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007860 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007861 * @ctxt: the XPath Parser context
7862 *
7863 * [3] RelativeLocationPath ::= Step
7864 * | RelativeLocationPath '/' Step
7865 * | AbbreviatedRelativeLocationPath
7866 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7867 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007868 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007869 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007870static void
Owen Taylor3473f882001-02-23 17:55:21 +00007871#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007872xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007873#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007874xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007875#endif
7876(xmlXPathParserContextPtr ctxt) {
7877 SKIP_BLANKS;
7878 if ((CUR == '/') && (NXT(1) == '/')) {
7879 SKIP(2);
7880 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007881 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7882 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007883 } else if (CUR == '/') {
7884 NEXT;
7885 SKIP_BLANKS;
7886 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007887 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007888 SKIP_BLANKS;
7889 while (CUR == '/') {
7890 if ((CUR == '/') && (NXT(1) == '/')) {
7891 SKIP(2);
7892 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007893 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007894 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007895 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007896 } else if (CUR == '/') {
7897 NEXT;
7898 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007899 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007900 }
7901 SKIP_BLANKS;
7902 }
7903}
7904
7905/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007906 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007907 * @ctxt: the XPath Parser context
7908 *
7909 * [1] LocationPath ::= RelativeLocationPath
7910 * | AbsoluteLocationPath
7911 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7912 * | AbbreviatedAbsoluteLocationPath
7913 * [10] AbbreviatedAbsoluteLocationPath ::=
7914 * '//' RelativeLocationPath
7915 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007916 * Compile a location path
7917 *
Owen Taylor3473f882001-02-23 17:55:21 +00007918 * // is short for /descendant-or-self::node()/. For example,
7919 * //para is short for /descendant-or-self::node()/child::para and
7920 * so will select any para element in the document (even a para element
7921 * that is a document element will be selected by //para since the
7922 * document element node is a child of the root node); div//para is
7923 * short for div/descendant-or-self::node()/child::para and so will
7924 * select all para descendants of div children.
7925 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007926static void
7927xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007928 SKIP_BLANKS;
7929 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007930 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007931 } else {
7932 while (CUR == '/') {
7933 if ((CUR == '/') && (NXT(1) == '/')) {
7934 SKIP(2);
7935 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007936 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7937 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007938 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007939 } else if (CUR == '/') {
7940 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007941 SKIP_BLANKS;
7942 if ((CUR != 0 ) &&
7943 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7944 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007945 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007946 }
7947 }
7948 }
7949}
7950
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007951/************************************************************************
7952 * *
7953 * XPath precompiled expression evaluation *
7954 * *
7955 ************************************************************************/
7956
Daniel Veillardf06307e2001-07-03 10:35:50 +00007957static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007958xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7959
7960/**
7961 * xmlXPathNodeCollectAndTest:
7962 * @ctxt: the XPath Parser context
7963 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007964 * @first: pointer to the first element in document order
7965 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007966 *
7967 * This is the function implementing a step: based on the current list
7968 * of nodes, it builds up a new list, looking at all nodes under that
7969 * axis and selecting them it also do the predicate filtering
7970 *
7971 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007972 *
7973 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007974 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007975static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007976xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007977 xmlXPathStepOpPtr op,
7978 xmlNodePtr * first, xmlNodePtr * last)
7979{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007980 xmlXPathAxisVal axis = op->value;
7981 xmlXPathTestVal test = op->value2;
7982 xmlXPathTypeVal type = op->value3;
7983 const xmlChar *prefix = op->value4;
7984 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007985 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007986
7987#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007988 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007989#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007990 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007991 xmlNodeSetPtr ret, list;
7992 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007993 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007994 xmlNodePtr cur = NULL;
7995 xmlXPathObjectPtr obj;
7996 xmlNodeSetPtr nodelist;
7997 xmlNodePtr tmp;
7998
Daniel Veillardf06307e2001-07-03 10:35:50 +00007999 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008000 obj = valuePop(ctxt);
8001 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008002 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008003 URI = xmlXPathNsLookup(ctxt->context, prefix);
8004 if (URI == NULL)
8005 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008006 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008007#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008008 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008009#endif
8010 switch (axis) {
8011 case AXIS_ANCESTOR:
8012#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008013 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008014#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008015 first = NULL;
8016 next = xmlXPathNextAncestor;
8017 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008018 case AXIS_ANCESTOR_OR_SELF:
8019#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008020 xmlGenericError(xmlGenericErrorContext,
8021 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008022#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008023 first = NULL;
8024 next = xmlXPathNextAncestorOrSelf;
8025 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008026 case AXIS_ATTRIBUTE:
8027#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008028 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008029#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008030 first = NULL;
8031 last = NULL;
8032 next = xmlXPathNextAttribute;
8033 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008034 case AXIS_CHILD:
8035#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008036 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008037#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008038 last = NULL;
8039 next = xmlXPathNextChild;
8040 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008041 case AXIS_DESCENDANT:
8042#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008043 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008044#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008045 last = NULL;
8046 next = xmlXPathNextDescendant;
8047 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008048 case AXIS_DESCENDANT_OR_SELF:
8049#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008050 xmlGenericError(xmlGenericErrorContext,
8051 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008052#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008053 last = NULL;
8054 next = xmlXPathNextDescendantOrSelf;
8055 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008056 case AXIS_FOLLOWING:
8057#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008058 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008059#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008060 last = NULL;
8061 next = xmlXPathNextFollowing;
8062 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008063 case AXIS_FOLLOWING_SIBLING:
8064#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008065 xmlGenericError(xmlGenericErrorContext,
8066 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008067#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008068 last = NULL;
8069 next = xmlXPathNextFollowingSibling;
8070 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008071 case AXIS_NAMESPACE:
8072#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008073 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008074#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008075 first = NULL;
8076 last = NULL;
8077 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8078 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008079 case AXIS_PARENT:
8080#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008081 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008082#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008083 first = NULL;
8084 next = xmlXPathNextParent;
8085 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008086 case AXIS_PRECEDING:
8087#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008088 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008089#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008090 first = NULL;
8091 next = xmlXPathNextPrecedingInternal;
8092 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008093 case AXIS_PRECEDING_SIBLING:
8094#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008095 xmlGenericError(xmlGenericErrorContext,
8096 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008097#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008098 first = NULL;
8099 next = xmlXPathNextPrecedingSibling;
8100 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008101 case AXIS_SELF:
8102#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008103 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008104#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008105 first = NULL;
8106 last = NULL;
8107 next = xmlXPathNextSelf;
8108 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008109 }
8110 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008111 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008112
8113 nodelist = obj->nodesetval;
8114 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008115 xmlXPathFreeObject(obj);
8116 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8117 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008118 }
8119 addNode = xmlXPathNodeSetAddUnique;
8120 ret = NULL;
8121#ifdef DEBUG_STEP
8122 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008123 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008124 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008125 case NODE_TEST_NONE:
8126 xmlGenericError(xmlGenericErrorContext,
8127 " searching for none !!!\n");
8128 break;
8129 case NODE_TEST_TYPE:
8130 xmlGenericError(xmlGenericErrorContext,
8131 " searching for type %d\n", type);
8132 break;
8133 case NODE_TEST_PI:
8134 xmlGenericError(xmlGenericErrorContext,
8135 " searching for PI !!!\n");
8136 break;
8137 case NODE_TEST_ALL:
8138 xmlGenericError(xmlGenericErrorContext,
8139 " searching for *\n");
8140 break;
8141 case NODE_TEST_NS:
8142 xmlGenericError(xmlGenericErrorContext,
8143 " searching for namespace %s\n",
8144 prefix);
8145 break;
8146 case NODE_TEST_NAME:
8147 xmlGenericError(xmlGenericErrorContext,
8148 " searching for name %s\n", name);
8149 if (prefix != NULL)
8150 xmlGenericError(xmlGenericErrorContext,
8151 " with namespace %s\n", prefix);
8152 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008153 }
8154 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8155#endif
8156 /*
8157 * 2.3 Node Tests
8158 * - For the attribute axis, the principal node type is attribute.
8159 * - For the namespace axis, the principal node type is namespace.
8160 * - For other axes, the principal node type is element.
8161 *
8162 * A node test * is true for any node of the
8163 * principal node type. For example, child::* willi
8164 * select all element children of the context node
8165 */
8166 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008167 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008168 ctxt->context->node = nodelist->nodeTab[i];
8169
Daniel Veillardf06307e2001-07-03 10:35:50 +00008170 cur = NULL;
8171 list = xmlXPathNodeSetCreate(NULL);
8172 do {
8173 cur = next(ctxt, cur);
8174 if (cur == NULL)
8175 break;
8176 if ((first != NULL) && (*first == cur))
8177 break;
8178 if (((t % 256) == 0) &&
8179 (first != NULL) && (*first != NULL) &&
8180 (xmlXPathCmpNodes(*first, cur) >= 0))
8181 break;
8182 if ((last != NULL) && (*last == cur))
8183 break;
8184 if (((t % 256) == 0) &&
8185 (last != NULL) && (*last != NULL) &&
8186 (xmlXPathCmpNodes(cur, *last) >= 0))
8187 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008188 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008189#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008190 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8191#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008192 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008193 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008194 ctxt->context->node = tmp;
8195 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008196 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008197 if ((cur->type == type) ||
8198 ((type == NODE_TYPE_NODE) &&
8199 ((cur->type == XML_DOCUMENT_NODE) ||
8200 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8201 (cur->type == XML_ELEMENT_NODE) ||
8202 (cur->type == XML_PI_NODE) ||
8203 (cur->type == XML_COMMENT_NODE) ||
8204 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008205 (cur->type == XML_TEXT_NODE))) ||
8206 ((type == NODE_TYPE_TEXT) &&
8207 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008208#ifdef DEBUG_STEP
8209 n++;
8210#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008211 addNode(list, cur);
8212 }
8213 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008214 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008215 if (cur->type == XML_PI_NODE) {
8216 if ((name != NULL) &&
8217 (!xmlStrEqual(name, cur->name)))
8218 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008219#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008220 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008221#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008222 addNode(list, cur);
8223 }
8224 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008225 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008226 if (axis == AXIS_ATTRIBUTE) {
8227 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008228#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008229 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008230#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008231 addNode(list, cur);
8232 }
8233 } else if (axis == AXIS_NAMESPACE) {
8234 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008235#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008236 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008237#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008238 addNode(list, cur);
8239 }
8240 } else {
8241 if (cur->type == XML_ELEMENT_NODE) {
8242 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008243#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008244 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008245#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008246 addNode(list, cur);
8247 } else if ((cur->ns != NULL) &&
8248 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008249#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008250 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008251#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008252 addNode(list, cur);
8253 }
8254 }
8255 }
8256 break;
8257 case NODE_TEST_NS:{
8258 TODO;
8259 break;
8260 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008261 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008262 switch (cur->type) {
8263 case XML_ELEMENT_NODE:
8264 if (xmlStrEqual(name, cur->name)) {
8265 if (prefix == NULL) {
8266 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008267#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008268 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008269#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008270 addNode(list, cur);
8271 }
8272 } else {
8273 if ((cur->ns != NULL) &&
8274 (xmlStrEqual(URI,
8275 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008276#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008277 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008278#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008279 addNode(list, cur);
8280 }
8281 }
8282 }
8283 break;
8284 case XML_ATTRIBUTE_NODE:{
8285 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008286
Daniel Veillardf06307e2001-07-03 10:35:50 +00008287 if (xmlStrEqual(name, attr->name)) {
8288 if (prefix == NULL) {
8289 if ((attr->ns == NULL) ||
8290 (attr->ns->prefix == NULL)) {
8291#ifdef DEBUG_STEP
8292 n++;
8293#endif
8294 addNode(list,
8295 (xmlNodePtr) attr);
8296 }
8297 } else {
8298 if ((attr->ns != NULL) &&
8299 (xmlStrEqual(URI,
8300 attr->ns->
8301 href))) {
8302#ifdef DEBUG_STEP
8303 n++;
8304#endif
8305 addNode(list,
8306 (xmlNodePtr) attr);
8307 }
8308 }
8309 }
8310 break;
8311 }
8312 case XML_NAMESPACE_DECL:
8313 if (cur->type == XML_NAMESPACE_DECL) {
8314 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008315
Daniel Veillardf06307e2001-07-03 10:35:50 +00008316 if ((ns->prefix != NULL) && (name != NULL)
8317 && (xmlStrEqual(ns->prefix, name))) {
8318#ifdef DEBUG_STEP
8319 n++;
8320#endif
8321 addNode(list, cur);
8322 }
8323 }
8324 break;
8325 default:
8326 break;
8327 }
8328 break;
8329 break;
8330 }
8331 } while (cur != NULL);
8332
8333 /*
8334 * If there is some predicate filtering do it now
8335 */
8336 if (op->ch2 != -1) {
8337 xmlXPathObjectPtr obj2;
8338
8339 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8340 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8341 CHECK_TYPE0(XPATH_NODESET);
8342 obj2 = valuePop(ctxt);
8343 list = obj2->nodesetval;
8344 obj2->nodesetval = NULL;
8345 xmlXPathFreeObject(obj2);
8346 }
8347 if (ret == NULL) {
8348 ret = list;
8349 } else {
8350 ret = xmlXPathNodeSetMerge(ret, list);
8351 xmlXPathFreeNodeSet(list);
8352 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008353 }
8354 ctxt->context->node = tmp;
8355#ifdef DEBUG_STEP
8356 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008357 "\nExamined %d nodes, found %d nodes at that step\n",
8358 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008359#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008360 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008361 if ((obj->boolval) && (obj->user != NULL)) {
8362 ctxt->value->boolval = 1;
8363 ctxt->value->user = obj->user;
8364 obj->user = NULL;
8365 obj->boolval = 0;
8366 }
8367 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008368 return(t);
8369}
8370
8371/**
8372 * xmlXPathNodeCollectAndTestNth:
8373 * @ctxt: the XPath Parser context
8374 * @op: the XPath precompiled step operation
8375 * @indx: the index to collect
8376 * @first: pointer to the first element in document order
8377 * @last: pointer to the last element in document order
8378 *
8379 * This is the function implementing a step: based on the current list
8380 * of nodes, it builds up a new list, looking at all nodes under that
8381 * axis and selecting them it also do the predicate filtering
8382 *
8383 * Pushes the new NodeSet resulting from the search.
8384 * Returns the number of node traversed
8385 */
8386static int
8387xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8388 xmlXPathStepOpPtr op, int indx,
8389 xmlNodePtr * first, xmlNodePtr * last)
8390{
8391 xmlXPathAxisVal axis = op->value;
8392 xmlXPathTestVal test = op->value2;
8393 xmlXPathTypeVal type = op->value3;
8394 const xmlChar *prefix = op->value4;
8395 const xmlChar *name = op->value5;
8396 const xmlChar *URI = NULL;
8397 int n = 0, t = 0;
8398
8399 int i;
8400 xmlNodeSetPtr list;
8401 xmlXPathTraversalFunction next = NULL;
8402 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8403 xmlNodePtr cur = NULL;
8404 xmlXPathObjectPtr obj;
8405 xmlNodeSetPtr nodelist;
8406 xmlNodePtr tmp;
8407
8408 CHECK_TYPE0(XPATH_NODESET);
8409 obj = valuePop(ctxt);
8410 addNode = xmlXPathNodeSetAdd;
8411 if (prefix != NULL) {
8412 URI = xmlXPathNsLookup(ctxt->context, prefix);
8413 if (URI == NULL)
8414 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8415 }
8416#ifdef DEBUG_STEP_NTH
8417 xmlGenericError(xmlGenericErrorContext, "new step : ");
8418 if (first != NULL) {
8419 if (*first != NULL)
8420 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8421 (*first)->name);
8422 else
8423 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8424 }
8425 if (last != NULL) {
8426 if (*last != NULL)
8427 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8428 (*last)->name);
8429 else
8430 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8431 }
8432#endif
8433 switch (axis) {
8434 case AXIS_ANCESTOR:
8435#ifdef DEBUG_STEP_NTH
8436 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8437#endif
8438 first = NULL;
8439 next = xmlXPathNextAncestor;
8440 break;
8441 case AXIS_ANCESTOR_OR_SELF:
8442#ifdef DEBUG_STEP_NTH
8443 xmlGenericError(xmlGenericErrorContext,
8444 "axis 'ancestors-or-self' ");
8445#endif
8446 first = NULL;
8447 next = xmlXPathNextAncestorOrSelf;
8448 break;
8449 case AXIS_ATTRIBUTE:
8450#ifdef DEBUG_STEP_NTH
8451 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8452#endif
8453 first = NULL;
8454 last = NULL;
8455 next = xmlXPathNextAttribute;
8456 break;
8457 case AXIS_CHILD:
8458#ifdef DEBUG_STEP_NTH
8459 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8460#endif
8461 last = NULL;
8462 next = xmlXPathNextChild;
8463 break;
8464 case AXIS_DESCENDANT:
8465#ifdef DEBUG_STEP_NTH
8466 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8467#endif
8468 last = NULL;
8469 next = xmlXPathNextDescendant;
8470 break;
8471 case AXIS_DESCENDANT_OR_SELF:
8472#ifdef DEBUG_STEP_NTH
8473 xmlGenericError(xmlGenericErrorContext,
8474 "axis 'descendant-or-self' ");
8475#endif
8476 last = NULL;
8477 next = xmlXPathNextDescendantOrSelf;
8478 break;
8479 case AXIS_FOLLOWING:
8480#ifdef DEBUG_STEP_NTH
8481 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8482#endif
8483 last = NULL;
8484 next = xmlXPathNextFollowing;
8485 break;
8486 case AXIS_FOLLOWING_SIBLING:
8487#ifdef DEBUG_STEP_NTH
8488 xmlGenericError(xmlGenericErrorContext,
8489 "axis 'following-siblings' ");
8490#endif
8491 last = NULL;
8492 next = xmlXPathNextFollowingSibling;
8493 break;
8494 case AXIS_NAMESPACE:
8495#ifdef DEBUG_STEP_NTH
8496 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8497#endif
8498 last = NULL;
8499 first = NULL;
8500 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8501 break;
8502 case AXIS_PARENT:
8503#ifdef DEBUG_STEP_NTH
8504 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8505#endif
8506 first = NULL;
8507 next = xmlXPathNextParent;
8508 break;
8509 case AXIS_PRECEDING:
8510#ifdef DEBUG_STEP_NTH
8511 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8512#endif
8513 first = NULL;
8514 next = xmlXPathNextPrecedingInternal;
8515 break;
8516 case AXIS_PRECEDING_SIBLING:
8517#ifdef DEBUG_STEP_NTH
8518 xmlGenericError(xmlGenericErrorContext,
8519 "axis 'preceding-sibling' ");
8520#endif
8521 first = NULL;
8522 next = xmlXPathNextPrecedingSibling;
8523 break;
8524 case AXIS_SELF:
8525#ifdef DEBUG_STEP_NTH
8526 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8527#endif
8528 first = NULL;
8529 last = NULL;
8530 next = xmlXPathNextSelf;
8531 break;
8532 }
8533 if (next == NULL)
8534 return(0);
8535
8536 nodelist = obj->nodesetval;
8537 if (nodelist == NULL) {
8538 xmlXPathFreeObject(obj);
8539 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8540 return(0);
8541 }
8542 addNode = xmlXPathNodeSetAddUnique;
8543#ifdef DEBUG_STEP_NTH
8544 xmlGenericError(xmlGenericErrorContext,
8545 " context contains %d nodes\n", nodelist->nodeNr);
8546 switch (test) {
8547 case NODE_TEST_NONE:
8548 xmlGenericError(xmlGenericErrorContext,
8549 " searching for none !!!\n");
8550 break;
8551 case NODE_TEST_TYPE:
8552 xmlGenericError(xmlGenericErrorContext,
8553 " searching for type %d\n", type);
8554 break;
8555 case NODE_TEST_PI:
8556 xmlGenericError(xmlGenericErrorContext,
8557 " searching for PI !!!\n");
8558 break;
8559 case NODE_TEST_ALL:
8560 xmlGenericError(xmlGenericErrorContext,
8561 " searching for *\n");
8562 break;
8563 case NODE_TEST_NS:
8564 xmlGenericError(xmlGenericErrorContext,
8565 " searching for namespace %s\n",
8566 prefix);
8567 break;
8568 case NODE_TEST_NAME:
8569 xmlGenericError(xmlGenericErrorContext,
8570 " searching for name %s\n", name);
8571 if (prefix != NULL)
8572 xmlGenericError(xmlGenericErrorContext,
8573 " with namespace %s\n", prefix);
8574 break;
8575 }
8576 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8577#endif
8578 /*
8579 * 2.3 Node Tests
8580 * - For the attribute axis, the principal node type is attribute.
8581 * - For the namespace axis, the principal node type is namespace.
8582 * - For other axes, the principal node type is element.
8583 *
8584 * A node test * is true for any node of the
8585 * principal node type. For example, child::* willi
8586 * select all element children of the context node
8587 */
8588 tmp = ctxt->context->node;
8589 list = xmlXPathNodeSetCreate(NULL);
8590 for (i = 0; i < nodelist->nodeNr; i++) {
8591 ctxt->context->node = nodelist->nodeTab[i];
8592
8593 cur = NULL;
8594 n = 0;
8595 do {
8596 cur = next(ctxt, cur);
8597 if (cur == NULL)
8598 break;
8599 if ((first != NULL) && (*first == cur))
8600 break;
8601 if (((t % 256) == 0) &&
8602 (first != NULL) && (*first != NULL) &&
8603 (xmlXPathCmpNodes(*first, cur) >= 0))
8604 break;
8605 if ((last != NULL) && (*last == cur))
8606 break;
8607 if (((t % 256) == 0) &&
8608 (last != NULL) && (*last != NULL) &&
8609 (xmlXPathCmpNodes(cur, *last) >= 0))
8610 break;
8611 t++;
8612 switch (test) {
8613 case NODE_TEST_NONE:
8614 ctxt->context->node = tmp;
8615 STRANGE return(0);
8616 case NODE_TEST_TYPE:
8617 if ((cur->type == type) ||
8618 ((type == NODE_TYPE_NODE) &&
8619 ((cur->type == XML_DOCUMENT_NODE) ||
8620 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8621 (cur->type == XML_ELEMENT_NODE) ||
8622 (cur->type == XML_PI_NODE) ||
8623 (cur->type == XML_COMMENT_NODE) ||
8624 (cur->type == XML_CDATA_SECTION_NODE) ||
8625 (cur->type == XML_TEXT_NODE)))) {
8626 n++;
8627 if (n == indx)
8628 addNode(list, cur);
8629 }
8630 break;
8631 case NODE_TEST_PI:
8632 if (cur->type == XML_PI_NODE) {
8633 if ((name != NULL) &&
8634 (!xmlStrEqual(name, cur->name)))
8635 break;
8636 n++;
8637 if (n == indx)
8638 addNode(list, cur);
8639 }
8640 break;
8641 case NODE_TEST_ALL:
8642 if (axis == AXIS_ATTRIBUTE) {
8643 if (cur->type == XML_ATTRIBUTE_NODE) {
8644 n++;
8645 if (n == indx)
8646 addNode(list, cur);
8647 }
8648 } else if (axis == AXIS_NAMESPACE) {
8649 if (cur->type == XML_NAMESPACE_DECL) {
8650 n++;
8651 if (n == indx)
8652 addNode(list, cur);
8653 }
8654 } else {
8655 if (cur->type == XML_ELEMENT_NODE) {
8656 if (prefix == NULL) {
8657 n++;
8658 if (n == indx)
8659 addNode(list, cur);
8660 } else if ((cur->ns != NULL) &&
8661 (xmlStrEqual(URI, cur->ns->href))) {
8662 n++;
8663 if (n == indx)
8664 addNode(list, cur);
8665 }
8666 }
8667 }
8668 break;
8669 case NODE_TEST_NS:{
8670 TODO;
8671 break;
8672 }
8673 case NODE_TEST_NAME:
8674 switch (cur->type) {
8675 case XML_ELEMENT_NODE:
8676 if (xmlStrEqual(name, cur->name)) {
8677 if (prefix == NULL) {
8678 if (cur->ns == NULL) {
8679 n++;
8680 if (n == indx)
8681 addNode(list, cur);
8682 }
8683 } else {
8684 if ((cur->ns != NULL) &&
8685 (xmlStrEqual(URI,
8686 cur->ns->href))) {
8687 n++;
8688 if (n == indx)
8689 addNode(list, cur);
8690 }
8691 }
8692 }
8693 break;
8694 case XML_ATTRIBUTE_NODE:{
8695 xmlAttrPtr attr = (xmlAttrPtr) cur;
8696
8697 if (xmlStrEqual(name, attr->name)) {
8698 if (prefix == NULL) {
8699 if ((attr->ns == NULL) ||
8700 (attr->ns->prefix == NULL)) {
8701 n++;
8702 if (n == indx)
8703 addNode(list, cur);
8704 }
8705 } else {
8706 if ((attr->ns != NULL) &&
8707 (xmlStrEqual(URI,
8708 attr->ns->
8709 href))) {
8710 n++;
8711 if (n == indx)
8712 addNode(list, cur);
8713 }
8714 }
8715 }
8716 break;
8717 }
8718 case XML_NAMESPACE_DECL:
8719 if (cur->type == XML_NAMESPACE_DECL) {
8720 xmlNsPtr ns = (xmlNsPtr) cur;
8721
8722 if ((ns->prefix != NULL) && (name != NULL)
8723 && (xmlStrEqual(ns->prefix, name))) {
8724 n++;
8725 if (n == indx)
8726 addNode(list, cur);
8727 }
8728 }
8729 break;
8730 default:
8731 break;
8732 }
8733 break;
8734 break;
8735 }
8736 } while (n < indx);
8737 }
8738 ctxt->context->node = tmp;
8739#ifdef DEBUG_STEP_NTH
8740 xmlGenericError(xmlGenericErrorContext,
8741 "\nExamined %d nodes, found %d nodes at that step\n",
8742 t, list->nodeNr);
8743#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008744 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008745 if ((obj->boolval) && (obj->user != NULL)) {
8746 ctxt->value->boolval = 1;
8747 ctxt->value->user = obj->user;
8748 obj->user = NULL;
8749 obj->boolval = 0;
8750 }
8751 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008752 return(t);
8753}
8754
8755/**
8756 * xmlXPathCompOpEvalFirst:
8757 * @ctxt: the XPath parser context with the compiled expression
8758 * @op: an XPath compiled operation
8759 * @first: the first elem found so far
8760 *
8761 * Evaluate the Precompiled XPath operation searching only the first
8762 * element in document order
8763 *
8764 * Returns the number of examined objects.
8765 */
8766static int
8767xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8768 xmlXPathStepOpPtr op, xmlNodePtr * first)
8769{
8770 int total = 0, cur;
8771 xmlXPathCompExprPtr comp;
8772 xmlXPathObjectPtr arg1, arg2;
8773
Daniel Veillard556c6682001-10-06 09:59:51 +00008774 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008775 comp = ctxt->comp;
8776 switch (op->op) {
8777 case XPATH_OP_END:
8778 return (0);
8779 case XPATH_OP_UNION:
8780 total =
8781 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8782 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008783 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008784 if ((ctxt->value != NULL)
8785 && (ctxt->value->type == XPATH_NODESET)
8786 && (ctxt->value->nodesetval != NULL)
8787 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8788 /*
8789 * limit tree traversing to first node in the result
8790 */
8791 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8792 *first = ctxt->value->nodesetval->nodeTab[0];
8793 }
8794 cur =
8795 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8796 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008797 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008798 CHECK_TYPE0(XPATH_NODESET);
8799 arg2 = valuePop(ctxt);
8800
8801 CHECK_TYPE0(XPATH_NODESET);
8802 arg1 = valuePop(ctxt);
8803
8804 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8805 arg2->nodesetval);
8806 valuePush(ctxt, arg1);
8807 xmlXPathFreeObject(arg2);
8808 /* optimizer */
8809 if (total > cur)
8810 xmlXPathCompSwap(op);
8811 return (total + cur);
8812 case XPATH_OP_ROOT:
8813 xmlXPathRoot(ctxt);
8814 return (0);
8815 case XPATH_OP_NODE:
8816 if (op->ch1 != -1)
8817 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008818 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008819 if (op->ch2 != -1)
8820 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008821 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008822 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8823 return (total);
8824 case XPATH_OP_RESET:
8825 if (op->ch1 != -1)
8826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008827 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008828 if (op->ch2 != -1)
8829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008830 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008831 ctxt->context->node = NULL;
8832 return (total);
8833 case XPATH_OP_COLLECT:{
8834 if (op->ch1 == -1)
8835 return (total);
8836
8837 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008838 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008839
8840 /*
8841 * Optimization for [n] selection where n is a number
8842 */
8843 if ((op->ch2 != -1) &&
8844 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8845 (comp->steps[op->ch2].ch1 == -1) &&
8846 (comp->steps[op->ch2].ch2 != -1) &&
8847 (comp->steps[comp->steps[op->ch2].ch2].op ==
8848 XPATH_OP_VALUE)) {
8849 xmlXPathObjectPtr val;
8850
8851 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8852 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8853 int indx = (int) val->floatval;
8854
8855 if (val->floatval == (float) indx) {
8856 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8857 first, NULL);
8858 return (total);
8859 }
8860 }
8861 }
8862 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8863 return (total);
8864 }
8865 case XPATH_OP_VALUE:
8866 valuePush(ctxt,
8867 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8868 return (0);
8869 case XPATH_OP_SORT:
8870 if (op->ch1 != -1)
8871 total +=
8872 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8873 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008874 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 if ((ctxt->value != NULL)
8876 && (ctxt->value->type == XPATH_NODESET)
8877 && (ctxt->value->nodesetval != NULL))
8878 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8879 return (total);
8880 default:
8881 return (xmlXPathCompOpEval(ctxt, op));
8882 }
8883}
8884
8885/**
8886 * xmlXPathCompOpEvalLast:
8887 * @ctxt: the XPath parser context with the compiled expression
8888 * @op: an XPath compiled operation
8889 * @last: the last elem found so far
8890 *
8891 * Evaluate the Precompiled XPath operation searching only the last
8892 * element in document order
8893 *
8894 * Returns the number of node traversed
8895 */
8896static int
8897xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8898 xmlNodePtr * last)
8899{
8900 int total = 0, cur;
8901 xmlXPathCompExprPtr comp;
8902 xmlXPathObjectPtr arg1, arg2;
8903
Daniel Veillard556c6682001-10-06 09:59:51 +00008904 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008905 comp = ctxt->comp;
8906 switch (op->op) {
8907 case XPATH_OP_END:
8908 return (0);
8909 case XPATH_OP_UNION:
8910 total =
8911 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008912 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008913 if ((ctxt->value != NULL)
8914 && (ctxt->value->type == XPATH_NODESET)
8915 && (ctxt->value->nodesetval != NULL)
8916 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8917 /*
8918 * limit tree traversing to first node in the result
8919 */
8920 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8921 *last =
8922 ctxt->value->nodesetval->nodeTab[ctxt->value->
8923 nodesetval->nodeNr -
8924 1];
8925 }
8926 cur =
8927 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008928 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 if ((ctxt->value != NULL)
8930 && (ctxt->value->type == XPATH_NODESET)
8931 && (ctxt->value->nodesetval != NULL)
8932 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8933 }
8934 CHECK_TYPE0(XPATH_NODESET);
8935 arg2 = valuePop(ctxt);
8936
8937 CHECK_TYPE0(XPATH_NODESET);
8938 arg1 = valuePop(ctxt);
8939
8940 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8941 arg2->nodesetval);
8942 valuePush(ctxt, arg1);
8943 xmlXPathFreeObject(arg2);
8944 /* optimizer */
8945 if (total > cur)
8946 xmlXPathCompSwap(op);
8947 return (total + cur);
8948 case XPATH_OP_ROOT:
8949 xmlXPathRoot(ctxt);
8950 return (0);
8951 case XPATH_OP_NODE:
8952 if (op->ch1 != -1)
8953 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008954 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 if (op->ch2 != -1)
8956 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008957 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008958 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8959 return (total);
8960 case XPATH_OP_RESET:
8961 if (op->ch1 != -1)
8962 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008963 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008964 if (op->ch2 != -1)
8965 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008966 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008967 ctxt->context->node = NULL;
8968 return (total);
8969 case XPATH_OP_COLLECT:{
8970 if (op->ch1 == -1)
8971 return (0);
8972
8973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008974 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975
8976 /*
8977 * Optimization for [n] selection where n is a number
8978 */
8979 if ((op->ch2 != -1) &&
8980 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8981 (comp->steps[op->ch2].ch1 == -1) &&
8982 (comp->steps[op->ch2].ch2 != -1) &&
8983 (comp->steps[comp->steps[op->ch2].ch2].op ==
8984 XPATH_OP_VALUE)) {
8985 xmlXPathObjectPtr val;
8986
8987 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8988 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8989 int indx = (int) val->floatval;
8990
8991 if (val->floatval == (float) indx) {
8992 total +=
8993 xmlXPathNodeCollectAndTestNth(ctxt, op,
8994 indx, NULL,
8995 last);
8996 return (total);
8997 }
8998 }
8999 }
9000 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9001 return (total);
9002 }
9003 case XPATH_OP_VALUE:
9004 valuePush(ctxt,
9005 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9006 return (0);
9007 case XPATH_OP_SORT:
9008 if (op->ch1 != -1)
9009 total +=
9010 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9011 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009012 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009013 if ((ctxt->value != NULL)
9014 && (ctxt->value->type == XPATH_NODESET)
9015 && (ctxt->value->nodesetval != NULL))
9016 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9017 return (total);
9018 default:
9019 return (xmlXPathCompOpEval(ctxt, op));
9020 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009021}
9022
Owen Taylor3473f882001-02-23 17:55:21 +00009023/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009024 * xmlXPathCompOpEval:
9025 * @ctxt: the XPath parser context with the compiled expression
9026 * @op: an XPath compiled operation
9027 *
9028 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009029 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009030 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009031static int
9032xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9033{
9034 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009035 int equal, ret;
9036 xmlXPathCompExprPtr comp;
9037 xmlXPathObjectPtr arg1, arg2;
9038
Daniel Veillard556c6682001-10-06 09:59:51 +00009039 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009040 comp = ctxt->comp;
9041 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009042 case XPATH_OP_END:
9043 return (0);
9044 case XPATH_OP_AND:
9045 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009046 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009047 xmlXPathBooleanFunction(ctxt, 1);
9048 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9049 return (total);
9050 arg2 = valuePop(ctxt);
9051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009052 if (ctxt->error) {
9053 xmlXPathFreeObject(arg2);
9054 return(0);
9055 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009056 xmlXPathBooleanFunction(ctxt, 1);
9057 arg1 = valuePop(ctxt);
9058 arg1->boolval &= arg2->boolval;
9059 valuePush(ctxt, arg1);
9060 xmlXPathFreeObject(arg2);
9061 return (total);
9062 case XPATH_OP_OR:
9063 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009064 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009065 xmlXPathBooleanFunction(ctxt, 1);
9066 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9067 return (total);
9068 arg2 = valuePop(ctxt);
9069 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009070 if (ctxt->error) {
9071 xmlXPathFreeObject(arg2);
9072 return(0);
9073 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 xmlXPathBooleanFunction(ctxt, 1);
9075 arg1 = valuePop(ctxt);
9076 arg1->boolval |= arg2->boolval;
9077 valuePush(ctxt, arg1);
9078 xmlXPathFreeObject(arg2);
9079 return (total);
9080 case XPATH_OP_EQUAL:
9081 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009082 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009083 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009084 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009085 equal = xmlXPathEqualValues(ctxt);
9086 if (op->value)
9087 valuePush(ctxt, xmlXPathNewBoolean(equal));
9088 else
9089 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9090 return (total);
9091 case XPATH_OP_CMP:
9092 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009093 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009095 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009096 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9097 valuePush(ctxt, xmlXPathNewBoolean(ret));
9098 return (total);
9099 case XPATH_OP_PLUS:
9100 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009101 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009102 if (op->ch2 != -1)
9103 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009104 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 if (op->value == 0)
9106 xmlXPathSubValues(ctxt);
9107 else if (op->value == 1)
9108 xmlXPathAddValues(ctxt);
9109 else if (op->value == 2)
9110 xmlXPathValueFlipSign(ctxt);
9111 else if (op->value == 3) {
9112 CAST_TO_NUMBER;
9113 CHECK_TYPE0(XPATH_NUMBER);
9114 }
9115 return (total);
9116 case XPATH_OP_MULT:
9117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009118 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009119 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009120 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 if (op->value == 0)
9122 xmlXPathMultValues(ctxt);
9123 else if (op->value == 1)
9124 xmlXPathDivValues(ctxt);
9125 else if (op->value == 2)
9126 xmlXPathModValues(ctxt);
9127 return (total);
9128 case XPATH_OP_UNION:
9129 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009130 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009132 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009133 CHECK_TYPE0(XPATH_NODESET);
9134 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009135
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 CHECK_TYPE0(XPATH_NODESET);
9137 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009138
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9140 arg2->nodesetval);
9141 valuePush(ctxt, arg1);
9142 xmlXPathFreeObject(arg2);
9143 return (total);
9144 case XPATH_OP_ROOT:
9145 xmlXPathRoot(ctxt);
9146 return (total);
9147 case XPATH_OP_NODE:
9148 if (op->ch1 != -1)
9149 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009150 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 if (op->ch2 != -1)
9152 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009153 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009154 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9155 return (total);
9156 case XPATH_OP_RESET:
9157 if (op->ch1 != -1)
9158 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009159 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009160 if (op->ch2 != -1)
9161 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009162 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009163 ctxt->context->node = NULL;
9164 return (total);
9165 case XPATH_OP_COLLECT:{
9166 if (op->ch1 == -1)
9167 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009168
Daniel Veillardf06307e2001-07-03 10:35:50 +00009169 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009170 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009171
Daniel Veillardf06307e2001-07-03 10:35:50 +00009172 /*
9173 * Optimization for [n] selection where n is a number
9174 */
9175 if ((op->ch2 != -1) &&
9176 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9177 (comp->steps[op->ch2].ch1 == -1) &&
9178 (comp->steps[op->ch2].ch2 != -1) &&
9179 (comp->steps[comp->steps[op->ch2].ch2].op ==
9180 XPATH_OP_VALUE)) {
9181 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009182
Daniel Veillardf06307e2001-07-03 10:35:50 +00009183 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9184 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9185 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009186
Daniel Veillardf06307e2001-07-03 10:35:50 +00009187 if (val->floatval == (float) indx) {
9188 total +=
9189 xmlXPathNodeCollectAndTestNth(ctxt, op,
9190 indx, NULL,
9191 NULL);
9192 return (total);
9193 }
9194 }
9195 }
9196 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9197 return (total);
9198 }
9199 case XPATH_OP_VALUE:
9200 valuePush(ctxt,
9201 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9202 return (total);
9203 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009204 xmlXPathObjectPtr val;
9205
Daniel Veillardf06307e2001-07-03 10:35:50 +00009206 if (op->ch1 != -1)
9207 total +=
9208 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009209 if (op->value5 == NULL) {
9210 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9211 if (val == NULL) {
9212 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9213 return(0);
9214 }
9215 valuePush(ctxt, val);
9216 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009217 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009218
Daniel Veillardf06307e2001-07-03 10:35:50 +00009219 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9220 if (URI == NULL) {
9221 xmlGenericError(xmlGenericErrorContext,
9222 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
9223 op->value4, op->value5);
9224 return (total);
9225 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009226 val = xmlXPathVariableLookupNS(ctxt->context,
9227 op->value4, URI);
9228 if (val == NULL) {
9229 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9230 return(0);
9231 }
9232 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009233 }
9234 return (total);
9235 }
9236 case XPATH_OP_FUNCTION:{
9237 xmlXPathFunction func;
9238 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009239 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009240
9241 if (op->ch1 != -1)
9242 total +=
9243 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009244 if (ctxt->valueNr < op->value) {
9245 xmlGenericError(xmlGenericErrorContext,
9246 "xmlXPathRunEval: parameter error\n");
9247 ctxt->error = XPATH_INVALID_OPERAND;
9248 return (total);
9249 }
9250 for (i = 0; i < op->value; i++)
9251 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9252 xmlGenericError(xmlGenericErrorContext,
9253 "xmlXPathRunEval: parameter error\n");
9254 ctxt->error = XPATH_INVALID_OPERAND;
9255 return (total);
9256 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009257 if (op->cache != NULL)
9258 func = (xmlXPathFunction) op->cache;
9259 else {
9260 const xmlChar *URI = NULL;
9261
9262 if (op->value5 == NULL)
9263 func =
9264 xmlXPathFunctionLookup(ctxt->context,
9265 op->value4);
9266 else {
9267 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9268 if (URI == NULL) {
9269 xmlGenericError(xmlGenericErrorContext,
9270 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
9271 op->value4, op->value5);
9272 return (total);
9273 }
9274 func = xmlXPathFunctionLookupNS(ctxt->context,
9275 op->value4, URI);
9276 }
9277 if (func == NULL) {
9278 xmlGenericError(xmlGenericErrorContext,
9279 "xmlXPathRunEval: function %s not found\n",
9280 op->value4);
9281 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009282 }
9283 op->cache = (void *) func;
9284 op->cacheURI = (void *) URI;
9285 }
9286 oldFunc = ctxt->context->function;
9287 oldFuncURI = ctxt->context->functionURI;
9288 ctxt->context->function = op->value4;
9289 ctxt->context->functionURI = op->cacheURI;
9290 func(ctxt, op->value);
9291 ctxt->context->function = oldFunc;
9292 ctxt->context->functionURI = oldFuncURI;
9293 return (total);
9294 }
9295 case XPATH_OP_ARG:
9296 if (op->ch1 != -1)
9297 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009298 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009299 if (op->ch2 != -1)
9300 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009301 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009302 return (total);
9303 case XPATH_OP_PREDICATE:
9304 case XPATH_OP_FILTER:{
9305 xmlXPathObjectPtr res;
9306 xmlXPathObjectPtr obj, tmp;
9307 xmlNodeSetPtr newset = NULL;
9308 xmlNodeSetPtr oldset;
9309 xmlNodePtr oldnode;
9310 int i;
9311
9312 /*
9313 * Optimization for ()[1] selection i.e. the first elem
9314 */
9315 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9316 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9317 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9318 xmlXPathObjectPtr val;
9319
9320 val = comp->steps[op->ch2].value4;
9321 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9322 (val->floatval == 1.0)) {
9323 xmlNodePtr first = NULL;
9324
9325 total +=
9326 xmlXPathCompOpEvalFirst(ctxt,
9327 &comp->steps[op->ch1],
9328 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009329 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009330 /*
9331 * The nodeset should be in document order,
9332 * Keep only the first value
9333 */
9334 if ((ctxt->value != NULL) &&
9335 (ctxt->value->type == XPATH_NODESET) &&
9336 (ctxt->value->nodesetval != NULL) &&
9337 (ctxt->value->nodesetval->nodeNr > 1))
9338 ctxt->value->nodesetval->nodeNr = 1;
9339 return (total);
9340 }
9341 }
9342 /*
9343 * Optimization for ()[last()] selection i.e. the last elem
9344 */
9345 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9346 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9347 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9348 int f = comp->steps[op->ch2].ch1;
9349
9350 if ((f != -1) &&
9351 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9352 (comp->steps[f].value5 == NULL) &&
9353 (comp->steps[f].value == 0) &&
9354 (comp->steps[f].value4 != NULL) &&
9355 (xmlStrEqual
9356 (comp->steps[f].value4, BAD_CAST "last"))) {
9357 xmlNodePtr last = NULL;
9358
9359 total +=
9360 xmlXPathCompOpEvalLast(ctxt,
9361 &comp->steps[op->ch1],
9362 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009363 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009364 /*
9365 * The nodeset should be in document order,
9366 * Keep only the last value
9367 */
9368 if ((ctxt->value != NULL) &&
9369 (ctxt->value->type == XPATH_NODESET) &&
9370 (ctxt->value->nodesetval != NULL) &&
9371 (ctxt->value->nodesetval->nodeTab != NULL) &&
9372 (ctxt->value->nodesetval->nodeNr > 1)) {
9373 ctxt->value->nodesetval->nodeTab[0] =
9374 ctxt->value->nodesetval->nodeTab[ctxt->
9375 value->
9376 nodesetval->
9377 nodeNr -
9378 1];
9379 ctxt->value->nodesetval->nodeNr = 1;
9380 }
9381 return (total);
9382 }
9383 }
9384
9385 if (op->ch1 != -1)
9386 total +=
9387 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009388 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009389 if (op->ch2 == -1)
9390 return (total);
9391 if (ctxt->value == NULL)
9392 return (total);
9393
9394 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009395
9396#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009397 /*
9398 * Hum are we filtering the result of an XPointer expression
9399 */
9400 if (ctxt->value->type == XPATH_LOCATIONSET) {
9401 xmlLocationSetPtr newlocset = NULL;
9402 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009403
Daniel Veillardf06307e2001-07-03 10:35:50 +00009404 /*
9405 * Extract the old locset, and then evaluate the result of the
9406 * expression for all the element in the locset. use it to grow
9407 * up a new locset.
9408 */
9409 CHECK_TYPE0(XPATH_LOCATIONSET);
9410 obj = valuePop(ctxt);
9411 oldlocset = obj->user;
9412 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009413
Daniel Veillardf06307e2001-07-03 10:35:50 +00009414 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9415 ctxt->context->contextSize = 0;
9416 ctxt->context->proximityPosition = 0;
9417 if (op->ch2 != -1)
9418 total +=
9419 xmlXPathCompOpEval(ctxt,
9420 &comp->steps[op->ch2]);
9421 res = valuePop(ctxt);
9422 if (res != NULL)
9423 xmlXPathFreeObject(res);
9424 valuePush(ctxt, obj);
9425 CHECK_ERROR0;
9426 return (total);
9427 }
9428 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009429
Daniel Veillardf06307e2001-07-03 10:35:50 +00009430 for (i = 0; i < oldlocset->locNr; i++) {
9431 /*
9432 * Run the evaluation with a node list made of a
9433 * single item in the nodelocset.
9434 */
9435 ctxt->context->node = oldlocset->locTab[i]->user;
9436 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9437 valuePush(ctxt, tmp);
9438 ctxt->context->contextSize = oldlocset->locNr;
9439 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009440
Daniel Veillardf06307e2001-07-03 10:35:50 +00009441 if (op->ch2 != -1)
9442 total +=
9443 xmlXPathCompOpEval(ctxt,
9444 &comp->steps[op->ch2]);
9445 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009446
Daniel Veillardf06307e2001-07-03 10:35:50 +00009447 /*
9448 * The result of the evaluation need to be tested to
9449 * decided whether the filter succeeded or not
9450 */
9451 res = valuePop(ctxt);
9452 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9453 xmlXPtrLocationSetAdd(newlocset,
9454 xmlXPathObjectCopy
9455 (oldlocset->locTab[i]));
9456 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009457
Daniel Veillardf06307e2001-07-03 10:35:50 +00009458 /*
9459 * Cleanup
9460 */
9461 if (res != NULL)
9462 xmlXPathFreeObject(res);
9463 if (ctxt->value == tmp) {
9464 res = valuePop(ctxt);
9465 xmlXPathFreeObject(res);
9466 }
9467
9468 ctxt->context->node = NULL;
9469 }
9470
9471 /*
9472 * The result is used as the new evaluation locset.
9473 */
9474 xmlXPathFreeObject(obj);
9475 ctxt->context->node = NULL;
9476 ctxt->context->contextSize = -1;
9477 ctxt->context->proximityPosition = -1;
9478 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9479 ctxt->context->node = oldnode;
9480 return (total);
9481 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009482#endif /* LIBXML_XPTR_ENABLED */
9483
Daniel Veillardf06307e2001-07-03 10:35:50 +00009484 /*
9485 * Extract the old set, and then evaluate the result of the
9486 * expression for all the element in the set. use it to grow
9487 * up a new set.
9488 */
9489 CHECK_TYPE0(XPATH_NODESET);
9490 obj = valuePop(ctxt);
9491 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009492
Daniel Veillardf06307e2001-07-03 10:35:50 +00009493 oldnode = ctxt->context->node;
9494 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009495
Daniel Veillardf06307e2001-07-03 10:35:50 +00009496 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9497 ctxt->context->contextSize = 0;
9498 ctxt->context->proximityPosition = 0;
9499 if (op->ch2 != -1)
9500 total +=
9501 xmlXPathCompOpEval(ctxt,
9502 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009503 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009504 res = valuePop(ctxt);
9505 if (res != NULL)
9506 xmlXPathFreeObject(res);
9507 valuePush(ctxt, obj);
9508 ctxt->context->node = oldnode;
9509 CHECK_ERROR0;
9510 } else {
9511 /*
9512 * Initialize the new set.
9513 */
9514 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009515
Daniel Veillardf06307e2001-07-03 10:35:50 +00009516 for (i = 0; i < oldset->nodeNr; i++) {
9517 /*
9518 * Run the evaluation with a node list made of
9519 * a single item in the nodeset.
9520 */
9521 ctxt->context->node = oldset->nodeTab[i];
9522 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9523 valuePush(ctxt, tmp);
9524 ctxt->context->contextSize = oldset->nodeNr;
9525 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009526
Daniel Veillardf06307e2001-07-03 10:35:50 +00009527 if (op->ch2 != -1)
9528 total +=
9529 xmlXPathCompOpEval(ctxt,
9530 &comp->steps[op->ch2]);
9531 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009532
Daniel Veillardf06307e2001-07-03 10:35:50 +00009533 /*
9534 * The result of the evaluation need to be tested to
9535 * decided whether the filter succeeded or not
9536 */
9537 res = valuePop(ctxt);
9538 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9539 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9540 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009541
Daniel Veillardf06307e2001-07-03 10:35:50 +00009542 /*
9543 * Cleanup
9544 */
9545 if (res != NULL)
9546 xmlXPathFreeObject(res);
9547 if (ctxt->value == tmp) {
9548 res = valuePop(ctxt);
9549 xmlXPathFreeObject(res);
9550 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009551
Daniel Veillardf06307e2001-07-03 10:35:50 +00009552 ctxt->context->node = NULL;
9553 }
9554
9555 /*
9556 * The result is used as the new evaluation set.
9557 */
9558 xmlXPathFreeObject(obj);
9559 ctxt->context->node = NULL;
9560 ctxt->context->contextSize = -1;
9561 ctxt->context->proximityPosition = -1;
9562 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9563 }
9564 ctxt->context->node = oldnode;
9565 return (total);
9566 }
9567 case XPATH_OP_SORT:
9568 if (op->ch1 != -1)
9569 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009570 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009571 if ((ctxt->value != NULL) &&
9572 (ctxt->value->type == XPATH_NODESET) &&
9573 (ctxt->value->nodesetval != NULL))
9574 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9575 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009576#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009577 case XPATH_OP_RANGETO:{
9578 xmlXPathObjectPtr range;
9579 xmlXPathObjectPtr res, obj;
9580 xmlXPathObjectPtr tmp;
9581 xmlLocationSetPtr newset = NULL;
9582 xmlNodeSetPtr oldset;
9583 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009584
Daniel Veillardf06307e2001-07-03 10:35:50 +00009585 if (op->ch1 != -1)
9586 total +=
9587 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9588 if (op->ch2 == -1)
9589 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009590
Daniel Veillardf06307e2001-07-03 10:35:50 +00009591 CHECK_TYPE0(XPATH_NODESET);
9592 obj = valuePop(ctxt);
9593 oldset = obj->nodesetval;
9594 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009595
Daniel Veillardf06307e2001-07-03 10:35:50 +00009596 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009597
Daniel Veillardf06307e2001-07-03 10:35:50 +00009598 if (oldset != NULL) {
9599 for (i = 0; i < oldset->nodeNr; i++) {
9600 /*
9601 * Run the evaluation with a node list made of a single item
9602 * in the nodeset.
9603 */
9604 ctxt->context->node = oldset->nodeTab[i];
9605 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9606 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009607
Daniel Veillardf06307e2001-07-03 10:35:50 +00009608 if (op->ch2 != -1)
9609 total +=
9610 xmlXPathCompOpEval(ctxt,
9611 &comp->steps[op->ch2]);
9612 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009613
Daniel Veillardf06307e2001-07-03 10:35:50 +00009614 /*
9615 * The result of the evaluation need to be tested to
9616 * decided whether the filter succeeded or not
9617 */
9618 res = valuePop(ctxt);
9619 range =
9620 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9621 res);
9622 if (range != NULL) {
9623 xmlXPtrLocationSetAdd(newset, range);
9624 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009625
Daniel Veillardf06307e2001-07-03 10:35:50 +00009626 /*
9627 * Cleanup
9628 */
9629 if (res != NULL)
9630 xmlXPathFreeObject(res);
9631 if (ctxt->value == tmp) {
9632 res = valuePop(ctxt);
9633 xmlXPathFreeObject(res);
9634 }
9635
9636 ctxt->context->node = NULL;
9637 }
9638 }
9639
9640 /*
9641 * The result is used as the new evaluation set.
9642 */
9643 xmlXPathFreeObject(obj);
9644 ctxt->context->node = NULL;
9645 ctxt->context->contextSize = -1;
9646 ctxt->context->proximityPosition = -1;
9647 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9648 return (total);
9649 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009650#endif /* LIBXML_XPTR_ENABLED */
9651 }
9652 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009653 "XPath: unknown precompiled operation %d\n", op->op);
9654 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009655}
9656
9657/**
9658 * xmlXPathRunEval:
9659 * @ctxt: the XPath parser context with the compiled expression
9660 *
9661 * Evaluate the Precompiled XPath expression in the given context.
9662 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009663static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009664xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9665 xmlXPathCompExprPtr comp;
9666
9667 if ((ctxt == NULL) || (ctxt->comp == NULL))
9668 return;
9669
9670 if (ctxt->valueTab == NULL) {
9671 /* Allocate the value stack */
9672 ctxt->valueTab = (xmlXPathObjectPtr *)
9673 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9674 if (ctxt->valueTab == NULL) {
9675 xmlFree(ctxt);
9676 xmlGenericError(xmlGenericErrorContext,
9677 "xmlXPathRunEval: out of memory\n");
9678 return;
9679 }
9680 ctxt->valueNr = 0;
9681 ctxt->valueMax = 10;
9682 ctxt->value = NULL;
9683 }
9684 comp = ctxt->comp;
9685 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9686}
9687
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009688/************************************************************************
9689 * *
9690 * Public interfaces *
9691 * *
9692 ************************************************************************/
9693
9694/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009695 * xmlXPathEvalPredicate:
9696 * @ctxt: the XPath context
9697 * @res: the Predicate Expression evaluation result
9698 *
9699 * Evaluate a predicate result for the current node.
9700 * A PredicateExpr is evaluated by evaluating the Expr and converting
9701 * the result to a boolean. If the result is a number, the result will
9702 * be converted to true if the number is equal to the position of the
9703 * context node in the context node list (as returned by the position
9704 * function) and will be converted to false otherwise; if the result
9705 * is not a number, then the result will be converted as if by a call
9706 * to the boolean function.
9707 *
9708 * Return 1 if predicate is true, 0 otherwise
9709 */
9710int
9711xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9712 if (res == NULL) return(0);
9713 switch (res->type) {
9714 case XPATH_BOOLEAN:
9715 return(res->boolval);
9716 case XPATH_NUMBER:
9717 return(res->floatval == ctxt->proximityPosition);
9718 case XPATH_NODESET:
9719 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009720 if (res->nodesetval == NULL)
9721 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009722 return(res->nodesetval->nodeNr != 0);
9723 case XPATH_STRING:
9724 return((res->stringval != NULL) &&
9725 (xmlStrlen(res->stringval) != 0));
9726 default:
9727 STRANGE
9728 }
9729 return(0);
9730}
9731
9732/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009733 * xmlXPathEvaluatePredicateResult:
9734 * @ctxt: the XPath Parser context
9735 * @res: the Predicate Expression evaluation result
9736 *
9737 * Evaluate a predicate result for the current node.
9738 * A PredicateExpr is evaluated by evaluating the Expr and converting
9739 * the result to a boolean. If the result is a number, the result will
9740 * be converted to true if the number is equal to the position of the
9741 * context node in the context node list (as returned by the position
9742 * function) and will be converted to false otherwise; if the result
9743 * is not a number, then the result will be converted as if by a call
9744 * to the boolean function.
9745 *
9746 * Return 1 if predicate is true, 0 otherwise
9747 */
9748int
9749xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9750 xmlXPathObjectPtr res) {
9751 if (res == NULL) return(0);
9752 switch (res->type) {
9753 case XPATH_BOOLEAN:
9754 return(res->boolval);
9755 case XPATH_NUMBER:
9756 return(res->floatval == ctxt->context->proximityPosition);
9757 case XPATH_NODESET:
9758 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009759 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009760 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009761 return(res->nodesetval->nodeNr != 0);
9762 case XPATH_STRING:
9763 return((res->stringval != NULL) &&
9764 (xmlStrlen(res->stringval) != 0));
9765 default:
9766 STRANGE
9767 }
9768 return(0);
9769}
9770
9771/**
9772 * xmlXPathCompile:
9773 * @str: the XPath expression
9774 *
9775 * Compile an XPath expression
9776 *
9777 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9778 * the caller has to free the object.
9779 */
9780xmlXPathCompExprPtr
9781xmlXPathCompile(const xmlChar *str) {
9782 xmlXPathParserContextPtr ctxt;
9783 xmlXPathCompExprPtr comp;
9784
9785 xmlXPathInit();
9786
9787 ctxt = xmlXPathNewParserContext(str, NULL);
9788 xmlXPathCompileExpr(ctxt);
9789
Daniel Veillard40af6492001-04-22 08:50:55 +00009790 if (*ctxt->cur != 0) {
9791 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9792 comp = NULL;
9793 } else {
9794 comp = ctxt->comp;
9795 ctxt->comp = NULL;
9796 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009797 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009798#ifdef DEBUG_EVAL_COUNTS
9799 if (comp != NULL) {
9800 comp->string = xmlStrdup(str);
9801 comp->nb = 0;
9802 }
9803#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009804 return(comp);
9805}
9806
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009807/**
9808 * xmlXPathCompiledEval:
9809 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009810 * @ctx: the XPath context
9811 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009812 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009813 *
9814 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9815 * the caller has to free the object.
9816 */
9817xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009818xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009819 xmlXPathParserContextPtr ctxt;
9820 xmlXPathObjectPtr res, tmp, init = NULL;
9821 int stack = 0;
9822
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009823 if ((comp == NULL) || (ctx == NULL))
9824 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009825 xmlXPathInit();
9826
9827 CHECK_CONTEXT(ctx)
9828
Daniel Veillardf06307e2001-07-03 10:35:50 +00009829#ifdef DEBUG_EVAL_COUNTS
9830 comp->nb++;
9831 if ((comp->string != NULL) && (comp->nb > 100)) {
9832 fprintf(stderr, "100 x %s\n", comp->string);
9833 comp->nb = 0;
9834 }
9835#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009836 ctxt = xmlXPathCompParserContext(comp, ctx);
9837 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009838
9839 if (ctxt->value == NULL) {
9840 xmlGenericError(xmlGenericErrorContext,
9841 "xmlXPathEval: evaluation failed\n");
9842 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009843 } else {
9844 res = valuePop(ctxt);
9845 }
9846
Daniel Veillardf06307e2001-07-03 10:35:50 +00009847
Owen Taylor3473f882001-02-23 17:55:21 +00009848 do {
9849 tmp = valuePop(ctxt);
9850 if (tmp != NULL) {
9851 if (tmp != init)
9852 stack++;
9853 xmlXPathFreeObject(tmp);
9854 }
9855 } while (tmp != NULL);
9856 if ((stack != 0) && (res != NULL)) {
9857 xmlGenericError(xmlGenericErrorContext,
9858 "xmlXPathEval: %d object left on the stack\n",
9859 stack);
9860 }
9861 if (ctxt->error != XPATH_EXPRESSION_OK) {
9862 xmlXPathFreeObject(res);
9863 res = NULL;
9864 }
9865
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009866
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009867 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009868 xmlXPathFreeParserContext(ctxt);
9869 return(res);
9870}
9871
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009872/**
9873 * xmlXPathEvalExpr:
9874 * @ctxt: the XPath Parser context
9875 *
9876 * Parse and evaluate an XPath expression in the given context,
9877 * then push the result on the context stack
9878 */
9879void
9880xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9881 xmlXPathCompileExpr(ctxt);
9882 xmlXPathRunEval(ctxt);
9883}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009884
9885/**
9886 * xmlXPathEval:
9887 * @str: the XPath expression
9888 * @ctx: the XPath context
9889 *
9890 * Evaluate the XPath Location Path in the given context.
9891 *
9892 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9893 * the caller has to free the object.
9894 */
9895xmlXPathObjectPtr
9896xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9897 xmlXPathParserContextPtr ctxt;
9898 xmlXPathObjectPtr res, tmp, init = NULL;
9899 int stack = 0;
9900
9901 xmlXPathInit();
9902
9903 CHECK_CONTEXT(ctx)
9904
9905 ctxt = xmlXPathNewParserContext(str, ctx);
9906 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009907
9908 if (ctxt->value == NULL) {
9909 xmlGenericError(xmlGenericErrorContext,
9910 "xmlXPathEval: evaluation failed\n");
9911 res = NULL;
9912 } else if (*ctxt->cur != 0) {
9913 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9914 res = NULL;
9915 } else {
9916 res = valuePop(ctxt);
9917 }
9918
9919 do {
9920 tmp = valuePop(ctxt);
9921 if (tmp != NULL) {
9922 if (tmp != init)
9923 stack++;
9924 xmlXPathFreeObject(tmp);
9925 }
9926 } while (tmp != NULL);
9927 if ((stack != 0) && (res != NULL)) {
9928 xmlGenericError(xmlGenericErrorContext,
9929 "xmlXPathEval: %d object left on the stack\n",
9930 stack);
9931 }
9932 if (ctxt->error != XPATH_EXPRESSION_OK) {
9933 xmlXPathFreeObject(res);
9934 res = NULL;
9935 }
9936
Owen Taylor3473f882001-02-23 17:55:21 +00009937 xmlXPathFreeParserContext(ctxt);
9938 return(res);
9939}
9940
9941/**
9942 * xmlXPathEvalExpression:
9943 * @str: the XPath expression
9944 * @ctxt: the XPath context
9945 *
9946 * Evaluate the XPath expression in the given context.
9947 *
9948 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9949 * the caller has to free the object.
9950 */
9951xmlXPathObjectPtr
9952xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9953 xmlXPathParserContextPtr pctxt;
9954 xmlXPathObjectPtr res, tmp;
9955 int stack = 0;
9956
9957 xmlXPathInit();
9958
9959 CHECK_CONTEXT(ctxt)
9960
9961 pctxt = xmlXPathNewParserContext(str, ctxt);
9962 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009963
9964 if (*pctxt->cur != 0) {
9965 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9966 res = NULL;
9967 } else {
9968 res = valuePop(pctxt);
9969 }
9970 do {
9971 tmp = valuePop(pctxt);
9972 if (tmp != NULL) {
9973 xmlXPathFreeObject(tmp);
9974 stack++;
9975 }
9976 } while (tmp != NULL);
9977 if ((stack != 0) && (res != NULL)) {
9978 xmlGenericError(xmlGenericErrorContext,
9979 "xmlXPathEvalExpression: %d object left on the stack\n",
9980 stack);
9981 }
9982 xmlXPathFreeParserContext(pctxt);
9983 return(res);
9984}
9985
9986/**
9987 * xmlXPathRegisterAllFunctions:
9988 * @ctxt: the XPath context
9989 *
9990 * Registers all default XPath functions in this context
9991 */
9992void
9993xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9994{
9995 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9996 xmlXPathBooleanFunction);
9997 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9998 xmlXPathCeilingFunction);
9999 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10000 xmlXPathCountFunction);
10001 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10002 xmlXPathConcatFunction);
10003 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10004 xmlXPathContainsFunction);
10005 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10006 xmlXPathIdFunction);
10007 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10008 xmlXPathFalseFunction);
10009 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10010 xmlXPathFloorFunction);
10011 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10012 xmlXPathLastFunction);
10013 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10014 xmlXPathLangFunction);
10015 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10016 xmlXPathLocalNameFunction);
10017 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10018 xmlXPathNotFunction);
10019 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10020 xmlXPathNameFunction);
10021 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10022 xmlXPathNamespaceURIFunction);
10023 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10024 xmlXPathNormalizeFunction);
10025 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10026 xmlXPathNumberFunction);
10027 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10028 xmlXPathPositionFunction);
10029 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10030 xmlXPathRoundFunction);
10031 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10032 xmlXPathStringFunction);
10033 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10034 xmlXPathStringLengthFunction);
10035 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10036 xmlXPathStartsWithFunction);
10037 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10038 xmlXPathSubstringFunction);
10039 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10040 xmlXPathSubstringBeforeFunction);
10041 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10042 xmlXPathSubstringAfterFunction);
10043 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10044 xmlXPathSumFunction);
10045 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10046 xmlXPathTrueFunction);
10047 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10048 xmlXPathTranslateFunction);
10049}
10050
10051#endif /* LIBXML_XPATH_ENABLED */