blob: 95a516e2d9d3f183c7b4fd2f2c7946241be05418 [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
1179const char *xmlXPathErrorMessages[] = {
1180 "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
2779 case XPATH_UNDEFINED:
2780 case XPATH_USERS:
2781 xmlGenericError(xmlGenericErrorContext,
2782 "xmlXPathObjectCopy: unsupported type %d\n",
2783 val->type);
2784 break;
2785 }
2786 return(ret);
2787}
2788
2789/**
2790 * xmlXPathFreeObject:
2791 * @obj: the object to free
2792 *
2793 * Free up an xmlXPathObjectPtr object.
2794 */
2795void
2796xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2797 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002798 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00002799 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002800 if (obj->user != NULL) {
2801 xmlFreeNodeList((xmlNodePtr) obj->user);
2802 xmlXPathFreeNodeSet(obj->nodesetval);
2803 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00002804 xmlXPathFreeValueTree(obj->nodesetval);
2805 } else {
2806 if (obj->nodesetval != NULL)
2807 xmlXPathFreeNodeSet(obj->nodesetval);
2808 }
Owen Taylor3473f882001-02-23 17:55:21 +00002809#ifdef LIBXML_XPTR_ENABLED
2810 } else if (obj->type == XPATH_LOCATIONSET) {
2811 if (obj->user != NULL)
2812 xmlXPtrFreeLocationSet(obj->user);
2813#endif
2814 } else if (obj->type == XPATH_STRING) {
2815 if (obj->stringval != NULL)
2816 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00002817 }
2818
Owen Taylor3473f882001-02-23 17:55:21 +00002819 xmlFree(obj);
2820}
2821
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002822
2823/************************************************************************
2824 * *
2825 * Type Casting Routines *
2826 * *
2827 ************************************************************************/
2828
2829/**
2830 * xmlXPathCastBooleanToString:
2831 * @val: a boolean
2832 *
2833 * Converts a boolean to its string value.
2834 *
2835 * Returns a newly allocated string.
2836 */
2837xmlChar *
2838xmlXPathCastBooleanToString (int val) {
2839 xmlChar *ret;
2840 if (val)
2841 ret = xmlStrdup((const xmlChar *) "true");
2842 else
2843 ret = xmlStrdup((const xmlChar *) "false");
2844 return(ret);
2845}
2846
2847/**
2848 * xmlXPathCastNumberToString:
2849 * @val: a number
2850 *
2851 * Converts a number to its string value.
2852 *
2853 * Returns a newly allocated string.
2854 */
2855xmlChar *
2856xmlXPathCastNumberToString (double val) {
2857 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00002858 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002859 case 1:
2860 ret = xmlStrdup((const xmlChar *) "+Infinity");
2861 break;
2862 case -1:
2863 ret = xmlStrdup((const xmlChar *) "-Infinity");
2864 break;
2865 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002866 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002867 ret = xmlStrdup((const xmlChar *) "NaN");
2868 } else {
2869 /* could be improved */
2870 char buf[100];
2871 xmlXPathFormatNumber(val, buf, 100);
2872 ret = xmlStrdup((const xmlChar *) buf);
2873 }
2874 }
2875 return(ret);
2876}
2877
2878/**
2879 * xmlXPathCastNodeToString:
2880 * @node: a node
2881 *
2882 * Converts a node to its string value.
2883 *
2884 * Returns a newly allocated string.
2885 */
2886xmlChar *
2887xmlXPathCastNodeToString (xmlNodePtr node) {
2888 return(xmlNodeGetContent(node));
2889}
2890
2891/**
2892 * xmlXPathCastNodeSetToString:
2893 * @ns: a node-set
2894 *
2895 * Converts a node-set to its string value.
2896 *
2897 * Returns a newly allocated string.
2898 */
2899xmlChar *
2900xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2901 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2902 return(xmlStrdup((const xmlChar *) ""));
2903
2904 xmlXPathNodeSetSort(ns);
2905 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2906}
2907
2908/**
2909 * xmlXPathCastToString:
2910 * @val: an XPath object
2911 *
2912 * Converts an existing object to its string() equivalent
2913 *
2914 * Returns the string value of the object, NULL in case of error.
2915 * A new string is allocated only if needed (val isn't a
2916 * string object).
2917 */
2918xmlChar *
2919xmlXPathCastToString(xmlXPathObjectPtr val) {
2920 xmlChar *ret = NULL;
2921
2922 if (val == NULL)
2923 return(xmlStrdup((const xmlChar *) ""));
2924 switch (val->type) {
2925 case XPATH_UNDEFINED:
2926#ifdef DEBUG_EXPR
2927 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2928#endif
2929 ret = xmlStrdup((const xmlChar *) "");
2930 break;
2931 case XPATH_XSLT_TREE:
2932 case XPATH_NODESET:
2933 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2934 break;
2935 case XPATH_STRING:
2936 return(val->stringval);
2937 case XPATH_BOOLEAN:
2938 ret = xmlXPathCastBooleanToString(val->boolval);
2939 break;
2940 case XPATH_NUMBER: {
2941 ret = xmlXPathCastNumberToString(val->floatval);
2942 break;
2943 }
2944 case XPATH_USERS:
2945 case XPATH_POINT:
2946 case XPATH_RANGE:
2947 case XPATH_LOCATIONSET:
2948 TODO
2949 ret = xmlStrdup((const xmlChar *) "");
2950 break;
2951 }
2952 return(ret);
2953}
2954
2955/**
2956 * xmlXPathConvertString:
2957 * @val: an XPath object
2958 *
2959 * Converts an existing object to its string() equivalent
2960 *
2961 * Returns the new object, the old one is freed (or the operation
2962 * is done directly on @val)
2963 */
2964xmlXPathObjectPtr
2965xmlXPathConvertString(xmlXPathObjectPtr val) {
2966 xmlChar *res = NULL;
2967
2968 if (val == NULL)
2969 return(xmlXPathNewCString(""));
2970
2971 switch (val->type) {
2972 case XPATH_UNDEFINED:
2973#ifdef DEBUG_EXPR
2974 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2975#endif
2976 break;
2977 case XPATH_XSLT_TREE:
2978 case XPATH_NODESET:
2979 res = xmlXPathCastNodeSetToString(val->nodesetval);
2980 break;
2981 case XPATH_STRING:
2982 return(val);
2983 case XPATH_BOOLEAN:
2984 res = xmlXPathCastBooleanToString(val->boolval);
2985 break;
2986 case XPATH_NUMBER:
2987 res = xmlXPathCastNumberToString(val->floatval);
2988 break;
2989 case XPATH_USERS:
2990 case XPATH_POINT:
2991 case XPATH_RANGE:
2992 case XPATH_LOCATIONSET:
2993 TODO;
2994 break;
2995 }
2996 xmlXPathFreeObject(val);
2997 if (res == NULL)
2998 return(xmlXPathNewCString(""));
2999 return(xmlXPathWrapString(res));
3000}
3001
3002/**
3003 * xmlXPathCastBooleanToNumber:
3004 * @val: a boolean
3005 *
3006 * Converts a boolean to its number value
3007 *
3008 * Returns the number value
3009 */
3010double
3011xmlXPathCastBooleanToNumber(int val) {
3012 if (val)
3013 return(1.0);
3014 return(0.0);
3015}
3016
3017/**
3018 * xmlXPathCastStringToNumber:
3019 * @val: a string
3020 *
3021 * Converts a string to its number value
3022 *
3023 * Returns the number value
3024 */
3025double
3026xmlXPathCastStringToNumber(const xmlChar * val) {
3027 return(xmlXPathStringEvalNumber(val));
3028}
3029
3030/**
3031 * xmlXPathCastNodeToNumber:
3032 * @node: a node
3033 *
3034 * Converts a node to its number value
3035 *
3036 * Returns the number value
3037 */
3038double
3039xmlXPathCastNodeToNumber (xmlNodePtr node) {
3040 xmlChar *strval;
3041 double ret;
3042
3043 if (node == NULL)
3044 return(xmlXPathNAN);
3045 strval = xmlXPathCastNodeToString(node);
3046 if (strval == NULL)
3047 return(xmlXPathNAN);
3048 ret = xmlXPathCastStringToNumber(strval);
3049 xmlFree(strval);
3050
3051 return(ret);
3052}
3053
3054/**
3055 * xmlXPathCastNodeSetToNumber:
3056 * @ns: a node-set
3057 *
3058 * Converts a node-set to its number value
3059 *
3060 * Returns the number value
3061 */
3062double
3063xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3064 xmlChar *str;
3065 double ret;
3066
3067 if (ns == NULL)
3068 return(xmlXPathNAN);
3069 str = xmlXPathCastNodeSetToString(ns);
3070 ret = xmlXPathCastStringToNumber(str);
3071 xmlFree(str);
3072 return(ret);
3073}
3074
3075/**
3076 * xmlXPathCastToNumber:
3077 * @val: an XPath object
3078 *
3079 * Converts an XPath object to its number value
3080 *
3081 * Returns the number value
3082 */
3083double
3084xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3085 double ret = 0.0;
3086
3087 if (val == NULL)
3088 return(xmlXPathNAN);
3089 switch (val->type) {
3090 case XPATH_UNDEFINED:
3091#ifdef DEGUB_EXPR
3092 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3093#endif
3094 ret = xmlXPathNAN;
3095 break;
3096 case XPATH_XSLT_TREE:
3097 case XPATH_NODESET:
3098 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3099 break;
3100 case XPATH_STRING:
3101 ret = xmlXPathCastStringToNumber(val->stringval);
3102 break;
3103 case XPATH_NUMBER:
3104 ret = val->floatval;
3105 break;
3106 case XPATH_BOOLEAN:
3107 ret = xmlXPathCastBooleanToNumber(val->boolval);
3108 break;
3109 case XPATH_USERS:
3110 case XPATH_POINT:
3111 case XPATH_RANGE:
3112 case XPATH_LOCATIONSET:
3113 TODO;
3114 ret = xmlXPathNAN;
3115 break;
3116 }
3117 return(ret);
3118}
3119
3120/**
3121 * xmlXPathConvertNumber:
3122 * @val: an XPath object
3123 *
3124 * Converts an existing object to its number() equivalent
3125 *
3126 * Returns the new object, the old one is freed (or the operation
3127 * is done directly on @val)
3128 */
3129xmlXPathObjectPtr
3130xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3131 xmlXPathObjectPtr ret;
3132
3133 if (val == NULL)
3134 return(xmlXPathNewFloat(0.0));
3135 if (val->type == XPATH_NUMBER)
3136 return(val);
3137 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3138 xmlXPathFreeObject(val);
3139 return(ret);
3140}
3141
3142/**
3143 * xmlXPathCastNumberToBoolean:
3144 * @val: a number
3145 *
3146 * Converts a number to its boolean value
3147 *
3148 * Returns the boolean value
3149 */
3150int
3151xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003152 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003153 return(0);
3154 return(1);
3155}
3156
3157/**
3158 * xmlXPathCastStringToBoolean:
3159 * @val: a string
3160 *
3161 * Converts a string to its boolean value
3162 *
3163 * Returns the boolean value
3164 */
3165int
3166xmlXPathCastStringToBoolean (const xmlChar *val) {
3167 if ((val == NULL) || (xmlStrlen(val) == 0))
3168 return(0);
3169 return(1);
3170}
3171
3172/**
3173 * xmlXPathCastNodeSetToBoolean:
3174 * @ns: a node-set
3175 *
3176 * Converts a node-set to its boolean value
3177 *
3178 * Returns the boolean value
3179 */
3180int
3181xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3182 if ((ns == NULL) || (ns->nodeNr == 0))
3183 return(0);
3184 return(1);
3185}
3186
3187/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003188 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003189 * @val: an XPath object
3190 *
3191 * Converts an XPath object to its boolean value
3192 *
3193 * Returns the boolean value
3194 */
3195int
3196xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3197 int ret = 0;
3198
3199 if (val == NULL)
3200 return(0);
3201 switch (val->type) {
3202 case XPATH_UNDEFINED:
3203#ifdef DEBUG_EXPR
3204 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3205#endif
3206 ret = 0;
3207 break;
3208 case XPATH_XSLT_TREE:
3209 case XPATH_NODESET:
3210 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3211 break;
3212 case XPATH_STRING:
3213 ret = xmlXPathCastStringToBoolean(val->stringval);
3214 break;
3215 case XPATH_NUMBER:
3216 ret = xmlXPathCastNumberToBoolean(val->floatval);
3217 break;
3218 case XPATH_BOOLEAN:
3219 ret = val->boolval;
3220 break;
3221 case XPATH_USERS:
3222 case XPATH_POINT:
3223 case XPATH_RANGE:
3224 case XPATH_LOCATIONSET:
3225 TODO;
3226 ret = 0;
3227 break;
3228 }
3229 return(ret);
3230}
3231
3232
3233/**
3234 * xmlXPathConvertBoolean:
3235 * @val: an XPath object
3236 *
3237 * Converts an existing object to its boolean() equivalent
3238 *
3239 * Returns the new object, the old one is freed (or the operation
3240 * is done directly on @val)
3241 */
3242xmlXPathObjectPtr
3243xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3244 xmlXPathObjectPtr ret;
3245
3246 if (val == NULL)
3247 return(xmlXPathNewBoolean(0));
3248 if (val->type == XPATH_BOOLEAN)
3249 return(val);
3250 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3251 xmlXPathFreeObject(val);
3252 return(ret);
3253}
3254
Owen Taylor3473f882001-02-23 17:55:21 +00003255/************************************************************************
3256 * *
3257 * Routines to handle XPath contexts *
3258 * *
3259 ************************************************************************/
3260
3261/**
3262 * xmlXPathNewContext:
3263 * @doc: the XML document
3264 *
3265 * Create a new xmlXPathContext
3266 *
3267 * Returns the xmlXPathContext just allocated.
3268 */
3269xmlXPathContextPtr
3270xmlXPathNewContext(xmlDocPtr doc) {
3271 xmlXPathContextPtr ret;
3272
3273 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3274 if (ret == NULL) {
3275 xmlGenericError(xmlGenericErrorContext,
3276 "xmlXPathNewContext: out of memory\n");
3277 return(NULL);
3278 }
3279 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3280 ret->doc = doc;
3281 ret->node = NULL;
3282
3283 ret->varHash = NULL;
3284
3285 ret->nb_types = 0;
3286 ret->max_types = 0;
3287 ret->types = NULL;
3288
3289 ret->funcHash = xmlHashCreate(0);
3290
3291 ret->nb_axis = 0;
3292 ret->max_axis = 0;
3293 ret->axis = NULL;
3294
3295 ret->nsHash = NULL;
3296 ret->user = NULL;
3297
3298 ret->contextSize = -1;
3299 ret->proximityPosition = -1;
3300
3301 xmlXPathRegisterAllFunctions(ret);
3302
3303 return(ret);
3304}
3305
3306/**
3307 * xmlXPathFreeContext:
3308 * @ctxt: the context to free
3309 *
3310 * Free up an xmlXPathContext
3311 */
3312void
3313xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3314 xmlXPathRegisteredNsCleanup(ctxt);
3315 xmlXPathRegisteredFuncsCleanup(ctxt);
3316 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003317 xmlFree(ctxt);
3318}
3319
3320/************************************************************************
3321 * *
3322 * Routines to handle XPath parser contexts *
3323 * *
3324 ************************************************************************/
3325
3326#define CHECK_CTXT(ctxt) \
3327 if (ctxt == NULL) { \
3328 xmlGenericError(xmlGenericErrorContext, \
3329 "%s:%d Internal error: ctxt == NULL\n", \
3330 __FILE__, __LINE__); \
3331 } \
3332
3333
3334#define CHECK_CONTEXT(ctxt) \
3335 if (ctxt == NULL) { \
3336 xmlGenericError(xmlGenericErrorContext, \
3337 "%s:%d Internal error: no context\n", \
3338 __FILE__, __LINE__); \
3339 } \
3340 else if (ctxt->doc == NULL) { \
3341 xmlGenericError(xmlGenericErrorContext, \
3342 "%s:%d Internal error: no document\n", \
3343 __FILE__, __LINE__); \
3344 } \
3345 else if (ctxt->doc->children == NULL) { \
3346 xmlGenericError(xmlGenericErrorContext, \
3347 "%s:%d Internal error: document without root\n", \
3348 __FILE__, __LINE__); \
3349 } \
3350
3351
3352/**
3353 * xmlXPathNewParserContext:
3354 * @str: the XPath expression
3355 * @ctxt: the XPath context
3356 *
3357 * Create a new xmlXPathParserContext
3358 *
3359 * Returns the xmlXPathParserContext just allocated.
3360 */
3361xmlXPathParserContextPtr
3362xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3363 xmlXPathParserContextPtr ret;
3364
3365 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3366 if (ret == NULL) {
3367 xmlGenericError(xmlGenericErrorContext,
3368 "xmlXPathNewParserContext: out of memory\n");
3369 return(NULL);
3370 }
3371 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3372 ret->cur = ret->base = str;
3373 ret->context = ctxt;
3374
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003375 ret->comp = xmlXPathNewCompExpr();
3376 if (ret->comp == NULL) {
3377 xmlFree(ret->valueTab);
3378 xmlFree(ret);
3379 return(NULL);
3380 }
3381
3382 return(ret);
3383}
3384
3385/**
3386 * xmlXPathCompParserContext:
3387 * @comp: the XPath compiled expression
3388 * @ctxt: the XPath context
3389 *
3390 * Create a new xmlXPathParserContext when processing a compiled expression
3391 *
3392 * Returns the xmlXPathParserContext just allocated.
3393 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003394static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003395xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3396 xmlXPathParserContextPtr ret;
3397
3398 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3399 if (ret == NULL) {
3400 xmlGenericError(xmlGenericErrorContext,
3401 "xmlXPathNewParserContext: out of memory\n");
3402 return(NULL);
3403 }
3404 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3405
Owen Taylor3473f882001-02-23 17:55:21 +00003406 /* Allocate the value stack */
3407 ret->valueTab = (xmlXPathObjectPtr *)
3408 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003409 if (ret->valueTab == NULL) {
3410 xmlFree(ret);
3411 xmlGenericError(xmlGenericErrorContext,
3412 "xmlXPathNewParserContext: out of memory\n");
3413 return(NULL);
3414 }
Owen Taylor3473f882001-02-23 17:55:21 +00003415 ret->valueNr = 0;
3416 ret->valueMax = 10;
3417 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003418
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003419 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003420 ret->comp = comp;
3421
Owen Taylor3473f882001-02-23 17:55:21 +00003422 return(ret);
3423}
3424
3425/**
3426 * xmlXPathFreeParserContext:
3427 * @ctxt: the context to free
3428 *
3429 * Free up an xmlXPathParserContext
3430 */
3431void
3432xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3433 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003434 xmlFree(ctxt->valueTab);
3435 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003436 if (ctxt->comp)
3437 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003438 xmlFree(ctxt);
3439}
3440
3441/************************************************************************
3442 * *
3443 * The implicit core function library *
3444 * *
3445 ************************************************************************/
3446
Owen Taylor3473f882001-02-23 17:55:21 +00003447/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003448 * xmlXPathNodeStringHash:
3449 * @node: a node pointer
3450 *
3451 * Function computing the beginning of the string value of the node,
3452 * used to speed up comparisons
3453 *
3454 * Returns an int usable as a hash
3455 */
3456static unsigned int
3457xmlXPathNodeValHash(xmlNodePtr node) {
3458 int len = 2;
3459 const xmlChar * string = NULL;
3460 xmlNodePtr tmp = NULL;
3461 unsigned int ret = 0;
3462
3463 if (node == NULL)
3464 return(0);
3465
3466
3467 switch (node->type) {
3468 case XML_COMMENT_NODE:
3469 case XML_PI_NODE:
3470 case XML_CDATA_SECTION_NODE:
3471 case XML_TEXT_NODE:
3472 string = node->content;
3473 if (string == NULL)
3474 return(0);
3475 if (string[0] == 0)
3476 return(0);
3477 return(((unsigned int) string[0]) +
3478 (((unsigned int) string[1]) << 8));
3479 case XML_NAMESPACE_DECL:
3480 string = ((xmlNsPtr)node)->href;
3481 if (string == NULL)
3482 return(0);
3483 if (string[0] == 0)
3484 return(0);
3485 return(((unsigned int) string[0]) +
3486 (((unsigned int) string[1]) << 8));
3487 case XML_ATTRIBUTE_NODE:
3488 tmp = ((xmlAttrPtr) node)->children;
3489 break;
3490 case XML_ELEMENT_NODE:
3491 tmp = node->children;
3492 break;
3493 default:
3494 return(0);
3495 }
3496 while (tmp != NULL) {
3497 switch (tmp->type) {
3498 case XML_COMMENT_NODE:
3499 case XML_PI_NODE:
3500 case XML_CDATA_SECTION_NODE:
3501 case XML_TEXT_NODE:
3502 string = tmp->content;
3503 break;
3504 case XML_NAMESPACE_DECL:
3505 string = ((xmlNsPtr)tmp)->href;
3506 break;
3507 default:
3508 break;
3509 }
3510 if ((string != NULL) && (string[0] != 0)) {
3511 if (string[0] == 0)
3512 return(0);
3513 if (len == 1) {
3514 return(ret + (((unsigned int) string[0]) << 8));
3515 }
3516 if (string[1] == 0) {
3517 len = 1;
3518 ret = (unsigned int) string[0];
3519 } else {
3520 return(((unsigned int) string[0]) +
3521 (((unsigned int) string[1]) << 8));
3522 }
3523 }
3524 /*
3525 * Skip to next node
3526 */
3527 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3528 if (tmp->children->type != XML_ENTITY_DECL) {
3529 tmp = tmp->children;
3530 continue;
3531 }
3532 }
3533 if (tmp == node)
3534 break;
3535
3536 if (tmp->next != NULL) {
3537 tmp = tmp->next;
3538 continue;
3539 }
3540
3541 do {
3542 tmp = tmp->parent;
3543 if (tmp == NULL)
3544 break;
3545 if (tmp == node) {
3546 tmp = NULL;
3547 break;
3548 }
3549 if (tmp->next != NULL) {
3550 tmp = tmp->next;
3551 break;
3552 }
3553 } while (tmp != NULL);
3554 }
3555 return(ret);
3556}
3557
3558/**
3559 * xmlXPathStringHash:
3560 * @string: a string
3561 *
3562 * Function computing the beginning of the string value of the node,
3563 * used to speed up comparisons
3564 *
3565 * Returns an int usable as a hash
3566 */
3567static unsigned int
3568xmlXPathStringHash(const xmlChar * string) {
3569 if (string == NULL)
3570 return((unsigned int) 0);
3571 if (string[0] == 0)
3572 return(0);
3573 return(((unsigned int) string[0]) +
3574 (((unsigned int) string[1]) << 8));
3575}
3576
3577/**
Owen Taylor3473f882001-02-23 17:55:21 +00003578 * xmlXPathCompareNodeSetFloat:
3579 * @ctxt: the XPath Parser context
3580 * @inf: less than (1) or greater than (0)
3581 * @strict: is the comparison strict
3582 * @arg: the node set
3583 * @f: the value
3584 *
3585 * Implement the compare operation between a nodeset and a number
3586 * @ns < @val (1, 1, ...
3587 * @ns <= @val (1, 0, ...
3588 * @ns > @val (0, 1, ...
3589 * @ns >= @val (0, 0, ...
3590 *
3591 * If one object to be compared is a node-set and the other is a number,
3592 * then the comparison will be true if and only if there is a node in the
3593 * node-set such that the result of performing the comparison on the number
3594 * to be compared and on the result of converting the string-value of that
3595 * node to a number using the number function is true.
3596 *
3597 * Returns 0 or 1 depending on the results of the test.
3598 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003599static int
Owen Taylor3473f882001-02-23 17:55:21 +00003600xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3601 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3602 int i, ret = 0;
3603 xmlNodeSetPtr ns;
3604 xmlChar *str2;
3605
3606 if ((f == NULL) || (arg == NULL) ||
3607 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3608 xmlXPathFreeObject(arg);
3609 xmlXPathFreeObject(f);
3610 return(0);
3611 }
3612 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003613 if (ns != NULL) {
3614 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003615 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003616 if (str2 != NULL) {
3617 valuePush(ctxt,
3618 xmlXPathNewString(str2));
3619 xmlFree(str2);
3620 xmlXPathNumberFunction(ctxt, 1);
3621 valuePush(ctxt, xmlXPathObjectCopy(f));
3622 ret = xmlXPathCompareValues(ctxt, inf, strict);
3623 if (ret)
3624 break;
3625 }
3626 }
Owen Taylor3473f882001-02-23 17:55:21 +00003627 }
3628 xmlXPathFreeObject(arg);
3629 xmlXPathFreeObject(f);
3630 return(ret);
3631}
3632
3633/**
3634 * xmlXPathCompareNodeSetString:
3635 * @ctxt: the XPath Parser context
3636 * @inf: less than (1) or greater than (0)
3637 * @strict: is the comparison strict
3638 * @arg: the node set
3639 * @s: the value
3640 *
3641 * Implement the compare operation between a nodeset and a string
3642 * @ns < @val (1, 1, ...
3643 * @ns <= @val (1, 0, ...
3644 * @ns > @val (0, 1, ...
3645 * @ns >= @val (0, 0, ...
3646 *
3647 * If one object to be compared is a node-set and the other is a string,
3648 * then the comparison will be true if and only if there is a node in
3649 * the node-set such that the result of performing the comparison on the
3650 * string-value of the node and the other string is true.
3651 *
3652 * Returns 0 or 1 depending on the results of the test.
3653 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003654static int
Owen Taylor3473f882001-02-23 17:55:21 +00003655xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3656 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3657 int i, ret = 0;
3658 xmlNodeSetPtr ns;
3659 xmlChar *str2;
3660
3661 if ((s == NULL) || (arg == NULL) ||
3662 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3663 xmlXPathFreeObject(arg);
3664 xmlXPathFreeObject(s);
3665 return(0);
3666 }
3667 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003668 if (ns != NULL) {
3669 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003670 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003671 if (str2 != NULL) {
3672 valuePush(ctxt,
3673 xmlXPathNewString(str2));
3674 xmlFree(str2);
3675 valuePush(ctxt, xmlXPathObjectCopy(s));
3676 ret = xmlXPathCompareValues(ctxt, inf, strict);
3677 if (ret)
3678 break;
3679 }
3680 }
Owen Taylor3473f882001-02-23 17:55:21 +00003681 }
3682 xmlXPathFreeObject(arg);
3683 xmlXPathFreeObject(s);
3684 return(ret);
3685}
3686
3687/**
3688 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003689 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003690 * @strict: is the comparison strict
3691 * @arg1: the fist node set object
3692 * @arg2: the second node set object
3693 *
3694 * Implement the compare operation on nodesets:
3695 *
3696 * If both objects to be compared are node-sets, then the comparison
3697 * will be true if and only if there is a node in the first node-set
3698 * and a node in the second node-set such that the result of performing
3699 * the comparison on the string-values of the two nodes is true.
3700 * ....
3701 * When neither object to be compared is a node-set and the operator
3702 * is <=, <, >= or >, then the objects are compared by converting both
3703 * objects to numbers and comparing the numbers according to IEEE 754.
3704 * ....
3705 * The number function converts its argument to a number as follows:
3706 * - a string that consists of optional whitespace followed by an
3707 * optional minus sign followed by a Number followed by whitespace
3708 * is converted to the IEEE 754 number that is nearest (according
3709 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3710 * represented by the string; any other string is converted to NaN
3711 *
3712 * Conclusion all nodes need to be converted first to their string value
3713 * and then the comparison must be done when possible
3714 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003715static int
3716xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003717 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3718 int i, j, init = 0;
3719 double val1;
3720 double *values2;
3721 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003722 xmlNodeSetPtr ns1;
3723 xmlNodeSetPtr ns2;
3724
3725 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003726 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3727 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003728 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003729 }
Owen Taylor3473f882001-02-23 17:55:21 +00003730 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003731 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3732 xmlXPathFreeObject(arg1);
3733 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003734 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003735 }
Owen Taylor3473f882001-02-23 17:55:21 +00003736
3737 ns1 = arg1->nodesetval;
3738 ns2 = arg2->nodesetval;
3739
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003740 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003741 xmlXPathFreeObject(arg1);
3742 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003743 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003744 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003745 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003746 xmlXPathFreeObject(arg1);
3747 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003748 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003749 }
Owen Taylor3473f882001-02-23 17:55:21 +00003750
3751 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3752 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003753 xmlXPathFreeObject(arg1);
3754 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003755 return(0);
3756 }
3757 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003758 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00003759 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00003760 continue;
3761 for (j = 0;j < ns2->nodeNr;j++) {
3762 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003763 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003764 }
Daniel Veillardcda96922001-08-21 10:56:31 +00003765 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00003766 continue;
3767 if (inf && strict)
3768 ret = (val1 < values2[j]);
3769 else 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 if (ret)
3776 break;
3777 }
3778 if (ret)
3779 break;
3780 init = 1;
3781 }
3782 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003783 xmlXPathFreeObject(arg1);
3784 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003785 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003786}
3787
3788/**
3789 * xmlXPathCompareNodeSetValue:
3790 * @ctxt: the XPath Parser context
3791 * @inf: less than (1) or greater than (0)
3792 * @strict: is the comparison strict
3793 * @arg: the node set
3794 * @val: the value
3795 *
3796 * Implement the compare operation between a nodeset and a value
3797 * @ns < @val (1, 1, ...
3798 * @ns <= @val (1, 0, ...
3799 * @ns > @val (0, 1, ...
3800 * @ns >= @val (0, 0, ...
3801 *
3802 * If one object to be compared is a node-set and the other is a boolean,
3803 * then the comparison will be true if and only if the result of performing
3804 * the comparison on the boolean and on the result of converting
3805 * the node-set to a boolean using the boolean function is true.
3806 *
3807 * Returns 0 or 1 depending on the results of the test.
3808 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003809static int
Owen Taylor3473f882001-02-23 17:55:21 +00003810xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3811 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3812 if ((val == NULL) || (arg == NULL) ||
3813 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3814 return(0);
3815
3816 switch(val->type) {
3817 case XPATH_NUMBER:
3818 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3819 case XPATH_NODESET:
3820 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003821 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003822 case XPATH_STRING:
3823 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3824 case XPATH_BOOLEAN:
3825 valuePush(ctxt, arg);
3826 xmlXPathBooleanFunction(ctxt, 1);
3827 valuePush(ctxt, val);
3828 return(xmlXPathCompareValues(ctxt, inf, strict));
3829 default:
3830 TODO
3831 return(0);
3832 }
3833 return(0);
3834}
3835
3836/**
3837 * xmlXPathEqualNodeSetString
3838 * @arg: the nodeset object argument
3839 * @str: the string to compare to.
3840 *
3841 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3842 * If one object to be compared is a node-set and the other is a string,
3843 * then the comparison will be true if and only if there is a node in
3844 * the node-set such that the result of performing the comparison on the
3845 * string-value of the node and the other string is true.
3846 *
3847 * Returns 0 or 1 depending on the results of the test.
3848 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003849static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003850xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3851{
Owen Taylor3473f882001-02-23 17:55:21 +00003852 int i;
3853 xmlNodeSetPtr ns;
3854 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003855 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003856
3857 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003858 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3859 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003860 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003861 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003862 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003863 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003864 if (ns->nodeNr <= 0) {
3865 if (hash == 0)
3866 return(1);
3867 return(0);
3868 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003869 for (i = 0; i < ns->nodeNr; i++) {
3870 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3871 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3872 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3873 xmlFree(str2);
3874 return (1);
3875 }
3876 if (str2 != NULL)
3877 xmlFree(str2);
3878 }
Owen Taylor3473f882001-02-23 17:55:21 +00003879 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003880 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003881}
3882
3883/**
3884 * xmlXPathEqualNodeSetFloat
3885 * @arg: the nodeset object argument
3886 * @f: the float to compare to
3887 *
3888 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3889 * If one object to be compared is a node-set and the other is a number,
3890 * then the comparison will be true if and only if there is a node in
3891 * the node-set such that the result of performing the comparison on the
3892 * number to be compared and on the result of converting the string-value
3893 * of that node to a number using the number function is true.
3894 *
3895 * Returns 0 or 1 depending on the results of the test.
3896 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003897static int
Owen Taylor3473f882001-02-23 17:55:21 +00003898xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3899 char buf[100] = "";
3900
3901 if ((arg == NULL) ||
3902 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3903 return(0);
3904
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003905 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003906 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3907}
3908
3909
3910/**
3911 * xmlXPathEqualNodeSets
3912 * @arg1: first nodeset object argument
3913 * @arg2: second nodeset object argument
3914 *
3915 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3916 * If both objects to be compared are node-sets, then the comparison
3917 * will be true if and only if there is a node in the first node-set and
3918 * a node in the second node-set such that the result of performing the
3919 * comparison on the string-values of the two nodes is true.
3920 *
3921 * (needless to say, this is a costly operation)
3922 *
3923 * Returns 0 or 1 depending on the results of the test.
3924 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003925static int
Owen Taylor3473f882001-02-23 17:55:21 +00003926xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3927 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003928 unsigned int *hashs1;
3929 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003930 xmlChar **values1;
3931 xmlChar **values2;
3932 int ret = 0;
3933 xmlNodeSetPtr ns1;
3934 xmlNodeSetPtr ns2;
3935
3936 if ((arg1 == NULL) ||
3937 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3938 return(0);
3939 if ((arg2 == NULL) ||
3940 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3941 return(0);
3942
3943 ns1 = arg1->nodesetval;
3944 ns2 = arg2->nodesetval;
3945
Daniel Veillard911f49a2001-04-07 15:39:35 +00003946 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003947 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003948 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003949 return(0);
3950
3951 /*
3952 * check if there is a node pertaining to both sets
3953 */
3954 for (i = 0;i < ns1->nodeNr;i++)
3955 for (j = 0;j < ns2->nodeNr;j++)
3956 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3957 return(1);
3958
3959 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3960 if (values1 == NULL)
3961 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003962 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3963 if (hashs1 == NULL) {
3964 xmlFree(values1);
3965 return(0);
3966 }
Owen Taylor3473f882001-02-23 17:55:21 +00003967 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3968 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3969 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003970 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003971 xmlFree(values1);
3972 return(0);
3973 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003974 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3975 if (hashs2 == NULL) {
3976 xmlFree(hashs1);
3977 xmlFree(values1);
3978 xmlFree(values2);
3979 return(0);
3980 }
Owen Taylor3473f882001-02-23 17:55:21 +00003981 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3982 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003983 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003984 for (j = 0;j < ns2->nodeNr;j++) {
3985 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003986 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
3987 if (hashs1[i] == hashs2[j]) {
3988 if (values1[i] == NULL)
3989 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3990 if (values2[j] == NULL)
3991 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3992 ret = xmlStrEqual(values1[i], values2[j]);
3993 if (ret)
3994 break;
3995 }
Owen Taylor3473f882001-02-23 17:55:21 +00003996 }
3997 if (ret)
3998 break;
3999 }
4000 for (i = 0;i < ns1->nodeNr;i++)
4001 if (values1[i] != NULL)
4002 xmlFree(values1[i]);
4003 for (j = 0;j < ns2->nodeNr;j++)
4004 if (values2[j] != NULL)
4005 xmlFree(values2[j]);
4006 xmlFree(values1);
4007 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004008 xmlFree(hashs1);
4009 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004010 return(ret);
4011}
4012
4013/**
4014 * xmlXPathEqualValues:
4015 * @ctxt: the XPath Parser context
4016 *
4017 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4018 *
4019 * Returns 0 or 1 depending on the results of the test.
4020 */
4021int
4022xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4023 xmlXPathObjectPtr arg1, arg2;
4024 int ret = 0;
4025
4026 arg1 = valuePop(ctxt);
4027 if (arg1 == NULL)
4028 XP_ERROR0(XPATH_INVALID_OPERAND);
4029
4030 arg2 = valuePop(ctxt);
4031 if (arg2 == NULL) {
4032 xmlXPathFreeObject(arg1);
4033 XP_ERROR0(XPATH_INVALID_OPERAND);
4034 }
4035
4036 if (arg1 == arg2) {
4037#ifdef DEBUG_EXPR
4038 xmlGenericError(xmlGenericErrorContext,
4039 "Equal: by pointer\n");
4040#endif
4041 return(1);
4042 }
4043
4044 switch (arg1->type) {
4045 case XPATH_UNDEFINED:
4046#ifdef DEBUG_EXPR
4047 xmlGenericError(xmlGenericErrorContext,
4048 "Equal: undefined\n");
4049#endif
4050 break;
4051 case XPATH_XSLT_TREE:
4052 case XPATH_NODESET:
4053 switch (arg2->type) {
4054 case XPATH_UNDEFINED:
4055#ifdef DEBUG_EXPR
4056 xmlGenericError(xmlGenericErrorContext,
4057 "Equal: undefined\n");
4058#endif
4059 break;
4060 case XPATH_XSLT_TREE:
4061 case XPATH_NODESET:
4062 ret = xmlXPathEqualNodeSets(arg1, arg2);
4063 break;
4064 case XPATH_BOOLEAN:
4065 if ((arg1->nodesetval == NULL) ||
4066 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4067 else
4068 ret = 1;
4069 ret = (ret == arg2->boolval);
4070 break;
4071 case XPATH_NUMBER:
4072 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4073 break;
4074 case XPATH_STRING:
4075 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4076 break;
4077 case XPATH_USERS:
4078 case XPATH_POINT:
4079 case XPATH_RANGE:
4080 case XPATH_LOCATIONSET:
4081 TODO
4082 break;
4083 }
4084 break;
4085 case XPATH_BOOLEAN:
4086 switch (arg2->type) {
4087 case XPATH_UNDEFINED:
4088#ifdef DEBUG_EXPR
4089 xmlGenericError(xmlGenericErrorContext,
4090 "Equal: undefined\n");
4091#endif
4092 break;
4093 case XPATH_NODESET:
4094 case XPATH_XSLT_TREE:
4095 if ((arg2->nodesetval == NULL) ||
4096 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4097 else
4098 ret = 1;
4099 break;
4100 case XPATH_BOOLEAN:
4101#ifdef DEBUG_EXPR
4102 xmlGenericError(xmlGenericErrorContext,
4103 "Equal: %d boolean %d \n",
4104 arg1->boolval, arg2->boolval);
4105#endif
4106 ret = (arg1->boolval == arg2->boolval);
4107 break;
4108 case XPATH_NUMBER:
4109 if (arg2->floatval) ret = 1;
4110 else ret = 0;
4111 ret = (arg1->boolval == ret);
4112 break;
4113 case XPATH_STRING:
4114 if ((arg2->stringval == NULL) ||
4115 (arg2->stringval[0] == 0)) ret = 0;
4116 else
4117 ret = 1;
4118 ret = (arg1->boolval == ret);
4119 break;
4120 case XPATH_USERS:
4121 case XPATH_POINT:
4122 case XPATH_RANGE:
4123 case XPATH_LOCATIONSET:
4124 TODO
4125 break;
4126 }
4127 break;
4128 case XPATH_NUMBER:
4129 switch (arg2->type) {
4130 case XPATH_UNDEFINED:
4131#ifdef DEBUG_EXPR
4132 xmlGenericError(xmlGenericErrorContext,
4133 "Equal: undefined\n");
4134#endif
4135 break;
4136 case XPATH_NODESET:
4137 case XPATH_XSLT_TREE:
4138 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4139 break;
4140 case XPATH_BOOLEAN:
4141 if (arg1->floatval) ret = 1;
4142 else ret = 0;
4143 ret = (arg2->boolval == ret);
4144 break;
4145 case XPATH_STRING:
4146 valuePush(ctxt, arg2);
4147 xmlXPathNumberFunction(ctxt, 1);
4148 arg2 = valuePop(ctxt);
4149 /* no break on purpose */
4150 case XPATH_NUMBER:
4151 ret = (arg1->floatval == arg2->floatval);
4152 break;
4153 case XPATH_USERS:
4154 case XPATH_POINT:
4155 case XPATH_RANGE:
4156 case XPATH_LOCATIONSET:
4157 TODO
4158 break;
4159 }
4160 break;
4161 case XPATH_STRING:
4162 switch (arg2->type) {
4163 case XPATH_UNDEFINED:
4164#ifdef DEBUG_EXPR
4165 xmlGenericError(xmlGenericErrorContext,
4166 "Equal: undefined\n");
4167#endif
4168 break;
4169 case XPATH_NODESET:
4170 case XPATH_XSLT_TREE:
4171 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4172 break;
4173 case XPATH_BOOLEAN:
4174 if ((arg1->stringval == NULL) ||
4175 (arg1->stringval[0] == 0)) ret = 0;
4176 else
4177 ret = 1;
4178 ret = (arg2->boolval == ret);
4179 break;
4180 case XPATH_STRING:
4181 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4182 break;
4183 case XPATH_NUMBER:
4184 valuePush(ctxt, arg1);
4185 xmlXPathNumberFunction(ctxt, 1);
4186 arg1 = valuePop(ctxt);
4187 ret = (arg1->floatval == arg2->floatval);
4188 break;
4189 case XPATH_USERS:
4190 case XPATH_POINT:
4191 case XPATH_RANGE:
4192 case XPATH_LOCATIONSET:
4193 TODO
4194 break;
4195 }
4196 break;
4197 case XPATH_USERS:
4198 case XPATH_POINT:
4199 case XPATH_RANGE:
4200 case XPATH_LOCATIONSET:
4201 TODO
4202 break;
4203 }
4204 xmlXPathFreeObject(arg1);
4205 xmlXPathFreeObject(arg2);
4206 return(ret);
4207}
4208
4209
4210/**
4211 * xmlXPathCompareValues:
4212 * @ctxt: the XPath Parser context
4213 * @inf: less than (1) or greater than (0)
4214 * @strict: is the comparison strict
4215 *
4216 * Implement the compare operation on XPath objects:
4217 * @arg1 < @arg2 (1, 1, ...
4218 * @arg1 <= @arg2 (1, 0, ...
4219 * @arg1 > @arg2 (0, 1, ...
4220 * @arg1 >= @arg2 (0, 0, ...
4221 *
4222 * When neither object to be compared is a node-set and the operator is
4223 * <=, <, >=, >, then the objects are compared by converted both objects
4224 * to numbers and comparing the numbers according to IEEE 754. The <
4225 * comparison will be true if and only if the first number is less than the
4226 * second number. The <= comparison will be true if and only if the first
4227 * number is less than or equal to the second number. The > comparison
4228 * will be true if and only if the first number is greater than the second
4229 * number. The >= comparison will be true if and only if the first number
4230 * is greater than or equal to the second number.
4231 *
4232 * Returns 1 if the comparaison succeeded, 0 if it failed
4233 */
4234int
4235xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4236 int ret = 0;
4237 xmlXPathObjectPtr arg1, arg2;
4238
4239 arg2 = valuePop(ctxt);
4240 if (arg2 == NULL) {
4241 XP_ERROR0(XPATH_INVALID_OPERAND);
4242 }
4243
4244 arg1 = valuePop(ctxt);
4245 if (arg1 == NULL) {
4246 xmlXPathFreeObject(arg2);
4247 XP_ERROR0(XPATH_INVALID_OPERAND);
4248 }
4249
4250 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4251 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004252 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004253 } else {
4254 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004255 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4256 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004257 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004258 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4259 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004260 }
4261 }
4262 return(ret);
4263 }
4264
4265 if (arg1->type != XPATH_NUMBER) {
4266 valuePush(ctxt, arg1);
4267 xmlXPathNumberFunction(ctxt, 1);
4268 arg1 = valuePop(ctxt);
4269 }
4270 if (arg1->type != XPATH_NUMBER) {
4271 xmlXPathFreeObject(arg1);
4272 xmlXPathFreeObject(arg2);
4273 XP_ERROR0(XPATH_INVALID_OPERAND);
4274 }
4275 if (arg2->type != XPATH_NUMBER) {
4276 valuePush(ctxt, arg2);
4277 xmlXPathNumberFunction(ctxt, 1);
4278 arg2 = valuePop(ctxt);
4279 }
4280 if (arg2->type != XPATH_NUMBER) {
4281 xmlXPathFreeObject(arg1);
4282 xmlXPathFreeObject(arg2);
4283 XP_ERROR0(XPATH_INVALID_OPERAND);
4284 }
4285 /*
4286 * Add tests for infinity and nan
4287 * => feedback on 3.4 for Inf and NaN
4288 */
4289 if (inf && strict)
4290 ret = (arg1->floatval < arg2->floatval);
4291 else if (inf && !strict)
4292 ret = (arg1->floatval <= arg2->floatval);
4293 else if (!inf && strict)
4294 ret = (arg1->floatval > arg2->floatval);
4295 else if (!inf && !strict)
4296 ret = (arg1->floatval >= arg2->floatval);
4297 xmlXPathFreeObject(arg1);
4298 xmlXPathFreeObject(arg2);
4299 return(ret);
4300}
4301
4302/**
4303 * xmlXPathValueFlipSign:
4304 * @ctxt: the XPath Parser context
4305 *
4306 * Implement the unary - operation on an XPath object
4307 * The numeric operators convert their operands to numbers as if
4308 * by calling the number function.
4309 */
4310void
4311xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004312 CAST_TO_NUMBER;
4313 CHECK_TYPE(XPATH_NUMBER);
4314 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004315}
4316
4317/**
4318 * xmlXPathAddValues:
4319 * @ctxt: the XPath Parser context
4320 *
4321 * Implement the add operation on XPath objects:
4322 * The numeric operators convert their operands to numbers as if
4323 * by calling the number function.
4324 */
4325void
4326xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4327 xmlXPathObjectPtr arg;
4328 double val;
4329
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004330 arg = valuePop(ctxt);
4331 if (arg == NULL)
4332 XP_ERROR(XPATH_INVALID_OPERAND);
4333 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004334 xmlXPathFreeObject(arg);
4335
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004336 CAST_TO_NUMBER;
4337 CHECK_TYPE(XPATH_NUMBER);
4338 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004339}
4340
4341/**
4342 * xmlXPathSubValues:
4343 * @ctxt: the XPath Parser context
4344 *
4345 * Implement the substraction operation on XPath objects:
4346 * The numeric operators convert their operands to numbers as if
4347 * by calling the number function.
4348 */
4349void
4350xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4351 xmlXPathObjectPtr arg;
4352 double val;
4353
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004354 arg = valuePop(ctxt);
4355 if (arg == NULL)
4356 XP_ERROR(XPATH_INVALID_OPERAND);
4357 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004358 xmlXPathFreeObject(arg);
4359
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004360 CAST_TO_NUMBER;
4361 CHECK_TYPE(XPATH_NUMBER);
4362 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004363}
4364
4365/**
4366 * xmlXPathMultValues:
4367 * @ctxt: the XPath Parser context
4368 *
4369 * Implement the multiply operation on XPath objects:
4370 * The numeric operators convert their operands to numbers as if
4371 * by calling the number function.
4372 */
4373void
4374xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4375 xmlXPathObjectPtr arg;
4376 double val;
4377
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004378 arg = valuePop(ctxt);
4379 if (arg == NULL)
4380 XP_ERROR(XPATH_INVALID_OPERAND);
4381 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004382 xmlXPathFreeObject(arg);
4383
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004384 CAST_TO_NUMBER;
4385 CHECK_TYPE(XPATH_NUMBER);
4386 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004387}
4388
4389/**
4390 * xmlXPathDivValues:
4391 * @ctxt: the XPath Parser context
4392 *
4393 * Implement the div operation on XPath objects @arg1 / @arg2:
4394 * The numeric operators convert their operands to numbers as if
4395 * by calling the number function.
4396 */
4397void
4398xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4399 xmlXPathObjectPtr arg;
4400 double val;
4401
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004402 arg = valuePop(ctxt);
4403 if (arg == NULL)
4404 XP_ERROR(XPATH_INVALID_OPERAND);
4405 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004406 xmlXPathFreeObject(arg);
4407
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004408 CAST_TO_NUMBER;
4409 CHECK_TYPE(XPATH_NUMBER);
4410 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004411}
4412
4413/**
4414 * xmlXPathModValues:
4415 * @ctxt: the XPath Parser context
4416 *
4417 * Implement the mod operation on XPath objects: @arg1 / @arg2
4418 * The numeric operators convert their operands to numbers as if
4419 * by calling the number function.
4420 */
4421void
4422xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4423 xmlXPathObjectPtr arg;
4424 int arg1, arg2;
4425
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004426 arg = valuePop(ctxt);
4427 if (arg == NULL)
4428 XP_ERROR(XPATH_INVALID_OPERAND);
4429 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004430 xmlXPathFreeObject(arg);
4431
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004432 CAST_TO_NUMBER;
4433 CHECK_TYPE(XPATH_NUMBER);
4434 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004435 if (arg2 == 0)
4436 ctxt->value->floatval = xmlXPathNAN;
4437 else
4438 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004439}
4440
4441/************************************************************************
4442 * *
4443 * The traversal functions *
4444 * *
4445 ************************************************************************/
4446
Owen Taylor3473f882001-02-23 17:55:21 +00004447/*
4448 * A traversal function enumerates nodes along an axis.
4449 * Initially it must be called with NULL, and it indicates
4450 * termination on the axis by returning NULL.
4451 */
4452typedef xmlNodePtr (*xmlXPathTraversalFunction)
4453 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4454
4455/**
4456 * xmlXPathNextSelf:
4457 * @ctxt: the XPath Parser context
4458 * @cur: the current node in the traversal
4459 *
4460 * Traversal function for the "self" direction
4461 * The self axis contains just the context node itself
4462 *
4463 * Returns the next element following that axis
4464 */
4465xmlNodePtr
4466xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4467 if (cur == NULL)
4468 return(ctxt->context->node);
4469 return(NULL);
4470}
4471
4472/**
4473 * xmlXPathNextChild:
4474 * @ctxt: the XPath Parser context
4475 * @cur: the current node in the traversal
4476 *
4477 * Traversal function for the "child" direction
4478 * The child axis contains the children of the context node in document order.
4479 *
4480 * Returns the next element following that axis
4481 */
4482xmlNodePtr
4483xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4484 if (cur == NULL) {
4485 if (ctxt->context->node == NULL) return(NULL);
4486 switch (ctxt->context->node->type) {
4487 case XML_ELEMENT_NODE:
4488 case XML_TEXT_NODE:
4489 case XML_CDATA_SECTION_NODE:
4490 case XML_ENTITY_REF_NODE:
4491 case XML_ENTITY_NODE:
4492 case XML_PI_NODE:
4493 case XML_COMMENT_NODE:
4494 case XML_NOTATION_NODE:
4495 case XML_DTD_NODE:
4496 return(ctxt->context->node->children);
4497 case XML_DOCUMENT_NODE:
4498 case XML_DOCUMENT_TYPE_NODE:
4499 case XML_DOCUMENT_FRAG_NODE:
4500 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004501#ifdef LIBXML_DOCB_ENABLED
4502 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004503#endif
4504 return(((xmlDocPtr) ctxt->context->node)->children);
4505 case XML_ELEMENT_DECL:
4506 case XML_ATTRIBUTE_DECL:
4507 case XML_ENTITY_DECL:
4508 case XML_ATTRIBUTE_NODE:
4509 case XML_NAMESPACE_DECL:
4510 case XML_XINCLUDE_START:
4511 case XML_XINCLUDE_END:
4512 return(NULL);
4513 }
4514 return(NULL);
4515 }
4516 if ((cur->type == XML_DOCUMENT_NODE) ||
4517 (cur->type == XML_HTML_DOCUMENT_NODE))
4518 return(NULL);
4519 return(cur->next);
4520}
4521
4522/**
4523 * xmlXPathNextDescendant:
4524 * @ctxt: the XPath Parser context
4525 * @cur: the current node in the traversal
4526 *
4527 * Traversal function for the "descendant" direction
4528 * the descendant axis contains the descendants of the context node in document
4529 * order; a descendant is a child or a child of a child and so on.
4530 *
4531 * Returns the next element following that axis
4532 */
4533xmlNodePtr
4534xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4535 if (cur == NULL) {
4536 if (ctxt->context->node == NULL)
4537 return(NULL);
4538 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4539 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4540 return(NULL);
4541
4542 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4543 return(ctxt->context->doc->children);
4544 return(ctxt->context->node->children);
4545 }
4546
Daniel Veillard567e1b42001-08-01 15:53:47 +00004547 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004548 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004549 return(cur->children);
4550 }
4551
4552 if (cur == ctxt->context->node) return(NULL);
4553
Owen Taylor3473f882001-02-23 17:55:21 +00004554 if (cur->next != NULL) return(cur->next);
4555
4556 do {
4557 cur = cur->parent;
4558 if (cur == NULL) return(NULL);
4559 if (cur == ctxt->context->node) return(NULL);
4560 if (cur->next != NULL) {
4561 cur = cur->next;
4562 return(cur);
4563 }
4564 } while (cur != NULL);
4565 return(cur);
4566}
4567
4568/**
4569 * xmlXPathNextDescendantOrSelf:
4570 * @ctxt: the XPath Parser context
4571 * @cur: the current node in the traversal
4572 *
4573 * Traversal function for the "descendant-or-self" direction
4574 * the descendant-or-self axis contains the context node and the descendants
4575 * of the context node in document order; thus the context node is the first
4576 * node on the axis, and the first child of the context node is the second node
4577 * on the axis
4578 *
4579 * Returns the next element following that axis
4580 */
4581xmlNodePtr
4582xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4583 if (cur == NULL) {
4584 if (ctxt->context->node == NULL)
4585 return(NULL);
4586 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4587 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4588 return(NULL);
4589 return(ctxt->context->node);
4590 }
4591
4592 return(xmlXPathNextDescendant(ctxt, cur));
4593}
4594
4595/**
4596 * xmlXPathNextParent:
4597 * @ctxt: the XPath Parser context
4598 * @cur: the current node in the traversal
4599 *
4600 * Traversal function for the "parent" direction
4601 * The parent axis contains the parent of the context node, if there is one.
4602 *
4603 * Returns the next element following that axis
4604 */
4605xmlNodePtr
4606xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4607 /*
4608 * the parent of an attribute or namespace node is the element
4609 * to which the attribute or namespace node is attached
4610 * Namespace handling !!!
4611 */
4612 if (cur == NULL) {
4613 if (ctxt->context->node == NULL) return(NULL);
4614 switch (ctxt->context->node->type) {
4615 case XML_ELEMENT_NODE:
4616 case XML_TEXT_NODE:
4617 case XML_CDATA_SECTION_NODE:
4618 case XML_ENTITY_REF_NODE:
4619 case XML_ENTITY_NODE:
4620 case XML_PI_NODE:
4621 case XML_COMMENT_NODE:
4622 case XML_NOTATION_NODE:
4623 case XML_DTD_NODE:
4624 case XML_ELEMENT_DECL:
4625 case XML_ATTRIBUTE_DECL:
4626 case XML_XINCLUDE_START:
4627 case XML_XINCLUDE_END:
4628 case XML_ENTITY_DECL:
4629 if (ctxt->context->node->parent == NULL)
4630 return((xmlNodePtr) ctxt->context->doc);
4631 return(ctxt->context->node->parent);
4632 case XML_ATTRIBUTE_NODE: {
4633 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4634
4635 return(att->parent);
4636 }
4637 case XML_DOCUMENT_NODE:
4638 case XML_DOCUMENT_TYPE_NODE:
4639 case XML_DOCUMENT_FRAG_NODE:
4640 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004641#ifdef LIBXML_DOCB_ENABLED
4642 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004643#endif
4644 return(NULL);
4645 case XML_NAMESPACE_DECL:
4646 /*
4647 * TODO !!! may require extending struct _xmlNs with
4648 * parent field
4649 * C.f. Infoset case...
4650 */
4651 return(NULL);
4652 }
4653 }
4654 return(NULL);
4655}
4656
4657/**
4658 * xmlXPathNextAncestor:
4659 * @ctxt: the XPath Parser context
4660 * @cur: the current node in the traversal
4661 *
4662 * Traversal function for the "ancestor" direction
4663 * the ancestor axis contains the ancestors of the context node; the ancestors
4664 * of the context node consist of the parent of context node and the parent's
4665 * parent and so on; the nodes are ordered in reverse document order; thus the
4666 * parent is the first node on the axis, and the parent's parent is the second
4667 * node on the axis
4668 *
4669 * Returns the next element following that axis
4670 */
4671xmlNodePtr
4672xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4673 /*
4674 * the parent of an attribute or namespace node is the element
4675 * to which the attribute or namespace node is attached
4676 * !!!!!!!!!!!!!
4677 */
4678 if (cur == NULL) {
4679 if (ctxt->context->node == NULL) return(NULL);
4680 switch (ctxt->context->node->type) {
4681 case XML_ELEMENT_NODE:
4682 case XML_TEXT_NODE:
4683 case XML_CDATA_SECTION_NODE:
4684 case XML_ENTITY_REF_NODE:
4685 case XML_ENTITY_NODE:
4686 case XML_PI_NODE:
4687 case XML_COMMENT_NODE:
4688 case XML_DTD_NODE:
4689 case XML_ELEMENT_DECL:
4690 case XML_ATTRIBUTE_DECL:
4691 case XML_ENTITY_DECL:
4692 case XML_NOTATION_NODE:
4693 case XML_XINCLUDE_START:
4694 case XML_XINCLUDE_END:
4695 if (ctxt->context->node->parent == NULL)
4696 return((xmlNodePtr) ctxt->context->doc);
4697 return(ctxt->context->node->parent);
4698 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004699 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004700
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004701 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004702 }
4703 case XML_DOCUMENT_NODE:
4704 case XML_DOCUMENT_TYPE_NODE:
4705 case XML_DOCUMENT_FRAG_NODE:
4706 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004707#ifdef LIBXML_DOCB_ENABLED
4708 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004709#endif
4710 return(NULL);
4711 case XML_NAMESPACE_DECL:
4712 /*
4713 * TODO !!! may require extending struct _xmlNs with
4714 * parent field
4715 * C.f. Infoset case...
4716 */
4717 return(NULL);
4718 }
4719 return(NULL);
4720 }
4721 if (cur == ctxt->context->doc->children)
4722 return((xmlNodePtr) ctxt->context->doc);
4723 if (cur == (xmlNodePtr) ctxt->context->doc)
4724 return(NULL);
4725 switch (cur->type) {
4726 case XML_ELEMENT_NODE:
4727 case XML_TEXT_NODE:
4728 case XML_CDATA_SECTION_NODE:
4729 case XML_ENTITY_REF_NODE:
4730 case XML_ENTITY_NODE:
4731 case XML_PI_NODE:
4732 case XML_COMMENT_NODE:
4733 case XML_NOTATION_NODE:
4734 case XML_DTD_NODE:
4735 case XML_ELEMENT_DECL:
4736 case XML_ATTRIBUTE_DECL:
4737 case XML_ENTITY_DECL:
4738 case XML_XINCLUDE_START:
4739 case XML_XINCLUDE_END:
4740 return(cur->parent);
4741 case XML_ATTRIBUTE_NODE: {
4742 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4743
4744 return(att->parent);
4745 }
4746 case XML_DOCUMENT_NODE:
4747 case XML_DOCUMENT_TYPE_NODE:
4748 case XML_DOCUMENT_FRAG_NODE:
4749 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004750#ifdef LIBXML_DOCB_ENABLED
4751 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004752#endif
4753 return(NULL);
4754 case XML_NAMESPACE_DECL:
4755 /*
4756 * TODO !!! may require extending struct _xmlNs with
4757 * parent field
4758 * C.f. Infoset case...
4759 */
4760 return(NULL);
4761 }
4762 return(NULL);
4763}
4764
4765/**
4766 * xmlXPathNextAncestorOrSelf:
4767 * @ctxt: the XPath Parser context
4768 * @cur: the current node in the traversal
4769 *
4770 * Traversal function for the "ancestor-or-self" direction
4771 * he ancestor-or-self axis contains the context node and ancestors of
4772 * the context node in reverse document order; thus the context node is
4773 * the first node on the axis, and the context node's parent the second;
4774 * parent here is defined the same as with the parent axis.
4775 *
4776 * Returns the next element following that axis
4777 */
4778xmlNodePtr
4779xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4780 if (cur == NULL)
4781 return(ctxt->context->node);
4782 return(xmlXPathNextAncestor(ctxt, cur));
4783}
4784
4785/**
4786 * xmlXPathNextFollowingSibling:
4787 * @ctxt: the XPath Parser context
4788 * @cur: the current node in the traversal
4789 *
4790 * Traversal function for the "following-sibling" direction
4791 * The following-sibling axis contains the following siblings of the context
4792 * node in document order.
4793 *
4794 * Returns the next element following that axis
4795 */
4796xmlNodePtr
4797xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4798 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4799 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4800 return(NULL);
4801 if (cur == (xmlNodePtr) ctxt->context->doc)
4802 return(NULL);
4803 if (cur == NULL)
4804 return(ctxt->context->node->next);
4805 return(cur->next);
4806}
4807
4808/**
4809 * xmlXPathNextPrecedingSibling:
4810 * @ctxt: the XPath Parser context
4811 * @cur: the current node in the traversal
4812 *
4813 * Traversal function for the "preceding-sibling" direction
4814 * The preceding-sibling axis contains the preceding siblings of the context
4815 * node in reverse document order; the first preceding sibling is first on the
4816 * axis; the sibling preceding that node is the second on the axis and so on.
4817 *
4818 * Returns the next element following that axis
4819 */
4820xmlNodePtr
4821xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4822 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4823 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4824 return(NULL);
4825 if (cur == (xmlNodePtr) ctxt->context->doc)
4826 return(NULL);
4827 if (cur == NULL)
4828 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004829 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4830 cur = cur->prev;
4831 if (cur == NULL)
4832 return(ctxt->context->node->prev);
4833 }
Owen Taylor3473f882001-02-23 17:55:21 +00004834 return(cur->prev);
4835}
4836
4837/**
4838 * xmlXPathNextFollowing:
4839 * @ctxt: the XPath Parser context
4840 * @cur: the current node in the traversal
4841 *
4842 * Traversal function for the "following" direction
4843 * The following axis contains all nodes in the same document as the context
4844 * node that are after the context node in document order, excluding any
4845 * descendants and excluding attribute nodes and namespace nodes; the nodes
4846 * are ordered in document order
4847 *
4848 * Returns the next element following that axis
4849 */
4850xmlNodePtr
4851xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4852 if (cur != NULL && cur->children != NULL)
4853 return cur->children ;
4854 if (cur == NULL) cur = ctxt->context->node;
4855 if (cur == NULL) return(NULL) ; /* ERROR */
4856 if (cur->next != NULL) return(cur->next) ;
4857 do {
4858 cur = cur->parent;
4859 if (cur == NULL) return(NULL);
4860 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4861 if (cur->next != NULL) return(cur->next);
4862 } while (cur != NULL);
4863 return(cur);
4864}
4865
4866/*
4867 * xmlXPathIsAncestor:
4868 * @ancestor: the ancestor node
4869 * @node: the current node
4870 *
4871 * Check that @ancestor is a @node's ancestor
4872 *
4873 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4874 */
4875static int
4876xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4877 if ((ancestor == NULL) || (node == NULL)) return(0);
4878 /* nodes need to be in the same document */
4879 if (ancestor->doc != node->doc) return(0);
4880 /* avoid searching if ancestor or node is the root node */
4881 if (ancestor == (xmlNodePtr) node->doc) return(1);
4882 if (node == (xmlNodePtr) ancestor->doc) return(0);
4883 while (node->parent != NULL) {
4884 if (node->parent == ancestor)
4885 return(1);
4886 node = node->parent;
4887 }
4888 return(0);
4889}
4890
4891/**
4892 * xmlXPathNextPreceding:
4893 * @ctxt: the XPath Parser context
4894 * @cur: the current node in the traversal
4895 *
4896 * Traversal function for the "preceding" direction
4897 * the preceding axis contains all nodes in the same document as the context
4898 * node that are before the context node in document order, excluding any
4899 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4900 * ordered in reverse document order
4901 *
4902 * Returns the next element following that axis
4903 */
4904xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004905xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4906{
Owen Taylor3473f882001-02-23 17:55:21 +00004907 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004908 cur = ctxt->context->node;
4909 if (cur == NULL)
4910 return (NULL);
4911 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4912 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004913 do {
4914 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004915 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4916 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004917 }
4918
4919 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004920 if (cur == NULL)
4921 return (NULL);
4922 if (cur == ctxt->context->doc->children)
4923 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004924 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004925 return (cur);
4926}
4927
4928/**
4929 * xmlXPathNextPrecedingInternal:
4930 * @ctxt: the XPath Parser context
4931 * @cur: the current node in the traversal
4932 *
4933 * Traversal function for the "preceding" direction
4934 * the preceding axis contains all nodes in the same document as the context
4935 * node that are before the context node in document order, excluding any
4936 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4937 * ordered in reverse document order
4938 * This is a faster implementation but internal only since it requires a
4939 * state kept in the parser context: ctxt->ancestor.
4940 *
4941 * Returns the next element following that axis
4942 */
4943static xmlNodePtr
4944xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4945 xmlNodePtr cur)
4946{
4947 if (cur == NULL) {
4948 cur = ctxt->context->node;
4949 if (cur == NULL)
4950 return (NULL);
4951 ctxt->ancestor = cur->parent;
4952 }
4953 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4954 cur = cur->prev;
4955 while (cur->prev == NULL) {
4956 cur = cur->parent;
4957 if (cur == NULL)
4958 return (NULL);
4959 if (cur == ctxt->context->doc->children)
4960 return (NULL);
4961 if (cur != ctxt->ancestor)
4962 return (cur);
4963 ctxt->ancestor = cur->parent;
4964 }
4965 cur = cur->prev;
4966 while (cur->last != NULL)
4967 cur = cur->last;
4968 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004969}
4970
4971/**
4972 * xmlXPathNextNamespace:
4973 * @ctxt: the XPath Parser context
4974 * @cur: the current attribute in the traversal
4975 *
4976 * Traversal function for the "namespace" direction
4977 * the namespace axis contains the namespace nodes of the context node;
4978 * the order of nodes on this axis is implementation-defined; the axis will
4979 * be empty unless the context node is an element
4980 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00004981 * We keep the XML namespace node at the end of the list.
4982 *
Owen Taylor3473f882001-02-23 17:55:21 +00004983 * Returns the next element following that axis
4984 */
4985xmlNodePtr
4986xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004987 xmlNodePtr ret;
4988
Owen Taylor3473f882001-02-23 17:55:21 +00004989 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00004990 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
4991 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004992 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
4993 if (ctxt->context->tmpNsList != NULL)
4994 xmlFree(ctxt->context->tmpNsList);
4995 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00004996 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004997 if (ctxt->context->tmpNsList == NULL) return(NULL);
4998 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004999 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005000 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5001 if (ret == NULL) {
5002 xmlFree(ctxt->context->tmpNsList);
5003 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005004 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005005 }
5006 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005007}
5008
5009/**
5010 * xmlXPathNextAttribute:
5011 * @ctxt: the XPath Parser context
5012 * @cur: the current attribute in the traversal
5013 *
5014 * Traversal function for the "attribute" direction
5015 * TODO: support DTD inherited default attributes
5016 *
5017 * Returns the next element following that axis
5018 */
5019xmlNodePtr
5020xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005021 if (ctxt->context->node == NULL)
5022 return(NULL);
5023 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5024 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005025 if (cur == NULL) {
5026 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5027 return(NULL);
5028 return((xmlNodePtr)ctxt->context->node->properties);
5029 }
5030 return((xmlNodePtr)cur->next);
5031}
5032
5033/************************************************************************
5034 * *
5035 * NodeTest Functions *
5036 * *
5037 ************************************************************************/
5038
Owen Taylor3473f882001-02-23 17:55:21 +00005039#define IS_FUNCTION 200
5040
Owen Taylor3473f882001-02-23 17:55:21 +00005041
5042/************************************************************************
5043 * *
5044 * Implicit tree core function library *
5045 * *
5046 ************************************************************************/
5047
5048/**
5049 * xmlXPathRoot:
5050 * @ctxt: the XPath Parser context
5051 *
5052 * Initialize the context to the root of the document
5053 */
5054void
5055xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5056 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5057 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5058}
5059
5060/************************************************************************
5061 * *
5062 * The explicit core function library *
5063 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5064 * *
5065 ************************************************************************/
5066
5067
5068/**
5069 * xmlXPathLastFunction:
5070 * @ctxt: the XPath Parser context
5071 * @nargs: the number of arguments
5072 *
5073 * Implement the last() XPath function
5074 * number last()
5075 * The last function returns the number of nodes in the context node list.
5076 */
5077void
5078xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5079 CHECK_ARITY(0);
5080 if (ctxt->context->contextSize >= 0) {
5081 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5082#ifdef DEBUG_EXPR
5083 xmlGenericError(xmlGenericErrorContext,
5084 "last() : %d\n", ctxt->context->contextSize);
5085#endif
5086 } else {
5087 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5088 }
5089}
5090
5091/**
5092 * xmlXPathPositionFunction:
5093 * @ctxt: the XPath Parser context
5094 * @nargs: the number of arguments
5095 *
5096 * Implement the position() XPath function
5097 * number position()
5098 * The position function returns the position of the context node in the
5099 * context node list. The first position is 1, and so the last positionr
5100 * will be equal to last().
5101 */
5102void
5103xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5104 CHECK_ARITY(0);
5105 if (ctxt->context->proximityPosition >= 0) {
5106 valuePush(ctxt,
5107 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5108#ifdef DEBUG_EXPR
5109 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5110 ctxt->context->proximityPosition);
5111#endif
5112 } else {
5113 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5114 }
5115}
5116
5117/**
5118 * xmlXPathCountFunction:
5119 * @ctxt: the XPath Parser context
5120 * @nargs: the number of arguments
5121 *
5122 * Implement the count() XPath function
5123 * number count(node-set)
5124 */
5125void
5126xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5127 xmlXPathObjectPtr cur;
5128
5129 CHECK_ARITY(1);
5130 if ((ctxt->value == NULL) ||
5131 ((ctxt->value->type != XPATH_NODESET) &&
5132 (ctxt->value->type != XPATH_XSLT_TREE)))
5133 XP_ERROR(XPATH_INVALID_TYPE);
5134 cur = valuePop(ctxt);
5135
Daniel Veillard911f49a2001-04-07 15:39:35 +00005136 if ((cur == NULL) || (cur->nodesetval == NULL))
5137 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005138 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005139 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005140 } else {
5141 if ((cur->nodesetval->nodeNr != 1) ||
5142 (cur->nodesetval->nodeTab == NULL)) {
5143 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5144 } else {
5145 xmlNodePtr tmp;
5146 int i = 0;
5147
5148 tmp = cur->nodesetval->nodeTab[0];
5149 if (tmp != NULL) {
5150 tmp = tmp->children;
5151 while (tmp != NULL) {
5152 tmp = tmp->next;
5153 i++;
5154 }
5155 }
5156 valuePush(ctxt, xmlXPathNewFloat((double) i));
5157 }
5158 }
Owen Taylor3473f882001-02-23 17:55:21 +00005159 xmlXPathFreeObject(cur);
5160}
5161
5162/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005163 * xmlXPathGetElementsByIds:
5164 * @doc: the document
5165 * @ids: a whitespace separated list of IDs
5166 *
5167 * Selects elements by their unique ID.
5168 *
5169 * Returns a node-set of selected elements.
5170 */
5171static xmlNodeSetPtr
5172xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5173 xmlNodeSetPtr ret;
5174 const xmlChar *cur = ids;
5175 xmlChar *ID;
5176 xmlAttrPtr attr;
5177 xmlNodePtr elem = NULL;
5178
5179 ret = xmlXPathNodeSetCreate(NULL);
5180
5181 while (IS_BLANK(*cur)) cur++;
5182 while (*cur != 0) {
5183 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5184 (*cur == '.') || (*cur == '-') ||
5185 (*cur == '_') || (*cur == ':') ||
5186 (IS_COMBINING(*cur)) ||
5187 (IS_EXTENDER(*cur)))
5188 cur++;
5189
5190 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5191
5192 ID = xmlStrndup(ids, cur - ids);
5193 attr = xmlGetID(doc, ID);
5194 if (attr != NULL) {
5195 elem = attr->parent;
5196 xmlXPathNodeSetAdd(ret, elem);
5197 }
5198 if (ID != NULL)
5199 xmlFree(ID);
5200
5201 while (IS_BLANK(*cur)) cur++;
5202 ids = cur;
5203 }
5204 return(ret);
5205}
5206
5207/**
Owen Taylor3473f882001-02-23 17:55:21 +00005208 * xmlXPathIdFunction:
5209 * @ctxt: the XPath Parser context
5210 * @nargs: the number of arguments
5211 *
5212 * Implement the id() XPath function
5213 * node-set id(object)
5214 * The id function selects elements by their unique ID
5215 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5216 * then the result is the union of the result of applying id to the
5217 * string value of each of the nodes in the argument node-set. When the
5218 * argument to id is of any other type, the argument is converted to a
5219 * string as if by a call to the string function; the string is split
5220 * into a whitespace-separated list of tokens (whitespace is any sequence
5221 * of characters matching the production S); the result is a node-set
5222 * containing the elements in the same document as the context node that
5223 * have a unique ID equal to any of the tokens in the list.
5224 */
5225void
5226xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005227 xmlChar *tokens;
5228 xmlNodeSetPtr ret;
5229 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005230
5231 CHECK_ARITY(1);
5232 obj = valuePop(ctxt);
5233 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5234 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005235 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005236 int i;
5237
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005238 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005239
Daniel Veillard911f49a2001-04-07 15:39:35 +00005240 if (obj->nodesetval != NULL) {
5241 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005242 tokens =
5243 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5244 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5245 ret = xmlXPathNodeSetMerge(ret, ns);
5246 xmlXPathFreeNodeSet(ns);
5247 if (tokens != NULL)
5248 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005249 }
Owen Taylor3473f882001-02-23 17:55:21 +00005250 }
5251
5252 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005253 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005254 return;
5255 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005256 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005257
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005258 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5259 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005260
Owen Taylor3473f882001-02-23 17:55:21 +00005261 xmlXPathFreeObject(obj);
5262 return;
5263}
5264
5265/**
5266 * xmlXPathLocalNameFunction:
5267 * @ctxt: the XPath Parser context
5268 * @nargs: the number of arguments
5269 *
5270 * Implement the local-name() XPath function
5271 * string local-name(node-set?)
5272 * The local-name function returns a string containing the local part
5273 * of the name of the node in the argument node-set that is first in
5274 * document order. If the node-set is empty or the first node has no
5275 * name, an empty string is returned. If the argument is omitted it
5276 * defaults to the context node.
5277 */
5278void
5279xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5280 xmlXPathObjectPtr cur;
5281
5282 if (nargs == 0) {
5283 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5284 nargs = 1;
5285 }
5286
5287 CHECK_ARITY(1);
5288 if ((ctxt->value == NULL) ||
5289 ((ctxt->value->type != XPATH_NODESET) &&
5290 (ctxt->value->type != XPATH_XSLT_TREE)))
5291 XP_ERROR(XPATH_INVALID_TYPE);
5292 cur = valuePop(ctxt);
5293
Daniel Veillard911f49a2001-04-07 15:39:35 +00005294 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005295 valuePush(ctxt, xmlXPathNewCString(""));
5296 } else {
5297 int i = 0; /* Should be first in document order !!!!! */
5298 switch (cur->nodesetval->nodeTab[i]->type) {
5299 case XML_ELEMENT_NODE:
5300 case XML_ATTRIBUTE_NODE:
5301 case XML_PI_NODE:
5302 valuePush(ctxt,
5303 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5304 break;
5305 case XML_NAMESPACE_DECL:
5306 valuePush(ctxt, xmlXPathNewString(
5307 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5308 break;
5309 default:
5310 valuePush(ctxt, xmlXPathNewCString(""));
5311 }
5312 }
5313 xmlXPathFreeObject(cur);
5314}
5315
5316/**
5317 * xmlXPathNamespaceURIFunction:
5318 * @ctxt: the XPath Parser context
5319 * @nargs: the number of arguments
5320 *
5321 * Implement the namespace-uri() XPath function
5322 * string namespace-uri(node-set?)
5323 * The namespace-uri function returns a string containing the
5324 * namespace URI of the expanded name of the node in the argument
5325 * node-set that is first in document order. If the node-set is empty,
5326 * the first node has no name, or the expanded name has no namespace
5327 * URI, an empty string is returned. If the argument is omitted it
5328 * defaults to the context node.
5329 */
5330void
5331xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5332 xmlXPathObjectPtr cur;
5333
5334 if (nargs == 0) {
5335 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5336 nargs = 1;
5337 }
5338 CHECK_ARITY(1);
5339 if ((ctxt->value == NULL) ||
5340 ((ctxt->value->type != XPATH_NODESET) &&
5341 (ctxt->value->type != XPATH_XSLT_TREE)))
5342 XP_ERROR(XPATH_INVALID_TYPE);
5343 cur = valuePop(ctxt);
5344
Daniel Veillard911f49a2001-04-07 15:39:35 +00005345 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005346 valuePush(ctxt, xmlXPathNewCString(""));
5347 } else {
5348 int i = 0; /* Should be first in document order !!!!! */
5349 switch (cur->nodesetval->nodeTab[i]->type) {
5350 case XML_ELEMENT_NODE:
5351 case XML_ATTRIBUTE_NODE:
5352 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5353 valuePush(ctxt, xmlXPathNewCString(""));
5354 else
5355 valuePush(ctxt, xmlXPathNewString(
5356 cur->nodesetval->nodeTab[i]->ns->href));
5357 break;
5358 default:
5359 valuePush(ctxt, xmlXPathNewCString(""));
5360 }
5361 }
5362 xmlXPathFreeObject(cur);
5363}
5364
5365/**
5366 * xmlXPathNameFunction:
5367 * @ctxt: the XPath Parser context
5368 * @nargs: the number of arguments
5369 *
5370 * Implement the name() XPath function
5371 * string name(node-set?)
5372 * The name function returns a string containing a QName representing
5373 * the name of the node in the argument node-set that is first in documenti
5374 * order. The QName must represent the name with respect to the namespace
5375 * declarations in effect on the node whose name is being represented.
5376 * Typically, this will be the form in which the name occurred in the XML
5377 * source. This need not be the case if there are namespace declarations
5378 * in effect on the node that associate multiple prefixes with the same
5379 * namespace. However, an implementation may include information about
5380 * the original prefix in its representation of nodes; in this case, an
5381 * implementation can ensure that the returned string is always the same
5382 * as the QName used in the XML source. If the argument it omitted it
5383 * defaults to the context node.
5384 * Libxml keep the original prefix so the "real qualified name" used is
5385 * returned.
5386 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005387static void
Daniel Veillard04383752001-07-08 14:27:15 +00005388xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5389{
Owen Taylor3473f882001-02-23 17:55:21 +00005390 xmlXPathObjectPtr cur;
5391
5392 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005393 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5394 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005395 }
5396
5397 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005398 if ((ctxt->value == NULL) ||
5399 ((ctxt->value->type != XPATH_NODESET) &&
5400 (ctxt->value->type != XPATH_XSLT_TREE)))
5401 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005402 cur = valuePop(ctxt);
5403
Daniel Veillard911f49a2001-04-07 15:39:35 +00005404 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005405 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005406 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005407 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005408
Daniel Veillard04383752001-07-08 14:27:15 +00005409 switch (cur->nodesetval->nodeTab[i]->type) {
5410 case XML_ELEMENT_NODE:
5411 case XML_ATTRIBUTE_NODE:
5412 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5413 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5414 valuePush(ctxt,
5415 xmlXPathNewString(cur->nodesetval->
5416 nodeTab[i]->name));
5417
5418 else {
5419 char name[2000];
5420
5421 snprintf(name, sizeof(name), "%s:%s",
5422 (char *) cur->nodesetval->nodeTab[i]->ns->
5423 prefix,
5424 (char *) cur->nodesetval->nodeTab[i]->name);
5425 name[sizeof(name) - 1] = 0;
5426 valuePush(ctxt, xmlXPathNewCString(name));
5427 }
5428 break;
5429 default:
5430 valuePush(ctxt,
5431 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5432 xmlXPathLocalNameFunction(ctxt, 1);
5433 }
Owen Taylor3473f882001-02-23 17:55:21 +00005434 }
5435 xmlXPathFreeObject(cur);
5436}
5437
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005438
5439/**
Owen Taylor3473f882001-02-23 17:55:21 +00005440 * xmlXPathStringFunction:
5441 * @ctxt: the XPath Parser context
5442 * @nargs: the number of arguments
5443 *
5444 * Implement the string() XPath function
5445 * string string(object?)
5446 * he string function converts an object to a string as follows:
5447 * - A node-set is converted to a string by returning the value of
5448 * the node in the node-set that is first in document order.
5449 * If the node-set is empty, an empty string is returned.
5450 * - A number is converted to a string as follows
5451 * + NaN is converted to the string NaN
5452 * + positive zero is converted to the string 0
5453 * + negative zero is converted to the string 0
5454 * + positive infinity is converted to the string Infinity
5455 * + negative infinity is converted to the string -Infinity
5456 * + if the number is an integer, the number is represented in
5457 * decimal form as a Number with no decimal point and no leading
5458 * zeros, preceded by a minus sign (-) if the number is negative
5459 * + otherwise, the number is represented in decimal form as a
5460 * Number including a decimal point with at least one digit
5461 * before the decimal point and at least one digit after the
5462 * decimal point, preceded by a minus sign (-) if the number
5463 * is negative; there must be no leading zeros before the decimal
5464 * point apart possibly from the one required digit immediatelyi
5465 * before the decimal point; beyond the one required digit
5466 * after the decimal point there must be as many, but only as
5467 * many, more digits as are needed to uniquely distinguish the
5468 * number from all other IEEE 754 numeric values.
5469 * - The boolean false value is converted to the string false.
5470 * The boolean true value is converted to the string true.
5471 *
5472 * If the argument is omitted, it defaults to a node-set with the
5473 * context node as its only member.
5474 */
5475void
5476xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5477 xmlXPathObjectPtr cur;
5478
5479 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005480 valuePush(ctxt,
5481 xmlXPathWrapString(
5482 xmlXPathCastNodeToString(ctxt->context->node)));
5483 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005484 }
5485
5486 CHECK_ARITY(1);
5487 cur = valuePop(ctxt);
5488 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005489 cur = xmlXPathConvertString(cur);
5490 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005491}
5492
5493/**
5494 * xmlXPathStringLengthFunction:
5495 * @ctxt: the XPath Parser context
5496 * @nargs: the number of arguments
5497 *
5498 * Implement the string-length() XPath function
5499 * number string-length(string?)
5500 * The string-length returns the number of characters in the string
5501 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5502 * the context node converted to a string, in other words the value
5503 * of the context node.
5504 */
5505void
5506xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5507 xmlXPathObjectPtr cur;
5508
5509 if (nargs == 0) {
5510 if (ctxt->context->node == NULL) {
5511 valuePush(ctxt, xmlXPathNewFloat(0));
5512 } else {
5513 xmlChar *content;
5514
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005515 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005516 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005517 xmlFree(content);
5518 }
5519 return;
5520 }
5521 CHECK_ARITY(1);
5522 CAST_TO_STRING;
5523 CHECK_TYPE(XPATH_STRING);
5524 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005525 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005526 xmlXPathFreeObject(cur);
5527}
5528
5529/**
5530 * xmlXPathConcatFunction:
5531 * @ctxt: the XPath Parser context
5532 * @nargs: the number of arguments
5533 *
5534 * Implement the concat() XPath function
5535 * string concat(string, string, string*)
5536 * The concat function returns the concatenation of its arguments.
5537 */
5538void
5539xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5540 xmlXPathObjectPtr cur, newobj;
5541 xmlChar *tmp;
5542
5543 if (nargs < 2) {
5544 CHECK_ARITY(2);
5545 }
5546
5547 CAST_TO_STRING;
5548 cur = valuePop(ctxt);
5549 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5550 xmlXPathFreeObject(cur);
5551 return;
5552 }
5553 nargs--;
5554
5555 while (nargs > 0) {
5556 CAST_TO_STRING;
5557 newobj = valuePop(ctxt);
5558 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5559 xmlXPathFreeObject(newobj);
5560 xmlXPathFreeObject(cur);
5561 XP_ERROR(XPATH_INVALID_TYPE);
5562 }
5563 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5564 newobj->stringval = cur->stringval;
5565 cur->stringval = tmp;
5566
5567 xmlXPathFreeObject(newobj);
5568 nargs--;
5569 }
5570 valuePush(ctxt, cur);
5571}
5572
5573/**
5574 * xmlXPathContainsFunction:
5575 * @ctxt: the XPath Parser context
5576 * @nargs: the number of arguments
5577 *
5578 * Implement the contains() XPath function
5579 * boolean contains(string, string)
5580 * The contains function returns true if the first argument string
5581 * contains the second argument string, and otherwise returns false.
5582 */
5583void
5584xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5585 xmlXPathObjectPtr hay, needle;
5586
5587 CHECK_ARITY(2);
5588 CAST_TO_STRING;
5589 CHECK_TYPE(XPATH_STRING);
5590 needle = valuePop(ctxt);
5591 CAST_TO_STRING;
5592 hay = valuePop(ctxt);
5593 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5594 xmlXPathFreeObject(hay);
5595 xmlXPathFreeObject(needle);
5596 XP_ERROR(XPATH_INVALID_TYPE);
5597 }
5598 if (xmlStrstr(hay->stringval, needle->stringval))
5599 valuePush(ctxt, xmlXPathNewBoolean(1));
5600 else
5601 valuePush(ctxt, xmlXPathNewBoolean(0));
5602 xmlXPathFreeObject(hay);
5603 xmlXPathFreeObject(needle);
5604}
5605
5606/**
5607 * xmlXPathStartsWithFunction:
5608 * @ctxt: the XPath Parser context
5609 * @nargs: the number of arguments
5610 *
5611 * Implement the starts-with() XPath function
5612 * boolean starts-with(string, string)
5613 * The starts-with function returns true if the first argument string
5614 * starts with the second argument string, and otherwise returns false.
5615 */
5616void
5617xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5618 xmlXPathObjectPtr hay, needle;
5619 int n;
5620
5621 CHECK_ARITY(2);
5622 CAST_TO_STRING;
5623 CHECK_TYPE(XPATH_STRING);
5624 needle = valuePop(ctxt);
5625 CAST_TO_STRING;
5626 hay = valuePop(ctxt);
5627 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5628 xmlXPathFreeObject(hay);
5629 xmlXPathFreeObject(needle);
5630 XP_ERROR(XPATH_INVALID_TYPE);
5631 }
5632 n = xmlStrlen(needle->stringval);
5633 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5634 valuePush(ctxt, xmlXPathNewBoolean(0));
5635 else
5636 valuePush(ctxt, xmlXPathNewBoolean(1));
5637 xmlXPathFreeObject(hay);
5638 xmlXPathFreeObject(needle);
5639}
5640
5641/**
5642 * xmlXPathSubstringFunction:
5643 * @ctxt: the XPath Parser context
5644 * @nargs: the number of arguments
5645 *
5646 * Implement the substring() XPath function
5647 * string substring(string, number, number?)
5648 * The substring function returns the substring of the first argument
5649 * starting at the position specified in the second argument with
5650 * length specified in the third argument. For example,
5651 * substring("12345",2,3) returns "234". If the third argument is not
5652 * specified, it returns the substring starting at the position specified
5653 * in the second argument and continuing to the end of the string. For
5654 * example, substring("12345",2) returns "2345". More precisely, each
5655 * character in the string (see [3.6 Strings]) is considered to have a
5656 * numeric position: the position of the first character is 1, the position
5657 * of the second character is 2 and so on. The returned substring contains
5658 * those characters for which the position of the character is greater than
5659 * or equal to the second argument and, if the third argument is specified,
5660 * less than the sum of the second and third arguments; the comparisons
5661 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5662 * - substring("12345", 1.5, 2.6) returns "234"
5663 * - substring("12345", 0, 3) returns "12"
5664 * - substring("12345", 0 div 0, 3) returns ""
5665 * - substring("12345", 1, 0 div 0) returns ""
5666 * - substring("12345", -42, 1 div 0) returns "12345"
5667 * - substring("12345", -1 div 0, 1 div 0) returns ""
5668 */
5669void
5670xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5671 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005672 double le=0, in;
5673 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005674 xmlChar *ret;
5675
Owen Taylor3473f882001-02-23 17:55:21 +00005676 if (nargs < 2) {
5677 CHECK_ARITY(2);
5678 }
5679 if (nargs > 3) {
5680 CHECK_ARITY(3);
5681 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005682 /*
5683 * take care of possible last (position) argument
5684 */
Owen Taylor3473f882001-02-23 17:55:21 +00005685 if (nargs == 3) {
5686 CAST_TO_NUMBER;
5687 CHECK_TYPE(XPATH_NUMBER);
5688 len = valuePop(ctxt);
5689 le = len->floatval;
5690 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005691 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005692
Owen Taylor3473f882001-02-23 17:55:21 +00005693 CAST_TO_NUMBER;
5694 CHECK_TYPE(XPATH_NUMBER);
5695 start = valuePop(ctxt);
5696 in = start->floatval;
5697 xmlXPathFreeObject(start);
5698 CAST_TO_STRING;
5699 CHECK_TYPE(XPATH_STRING);
5700 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005701 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005702
Daniel Veillard97ac1312001-05-30 19:14:17 +00005703 /*
5704 * If last pos not present, calculate last position
5705 */
5706 if (nargs != 3)
5707 le = m;
5708
5709 /*
5710 * To meet our requirements, initial index calculations
5711 * must be done before we convert to integer format
5712 *
5713 * First we normalize indices
5714 */
5715 in -= 1.0;
5716 le += in;
5717 if (in < 0.0)
5718 in = 0.0;
5719 if (le > (double)m)
5720 le = (double)m;
5721
5722 /*
5723 * Now we go to integer form, rounding up
5724 */
Owen Taylor3473f882001-02-23 17:55:21 +00005725 i = (int) in;
5726 if (((double)i) != in) i++;
5727
Owen Taylor3473f882001-02-23 17:55:21 +00005728 l = (int) le;
5729 if (((double)l) != le) l++;
5730
Daniel Veillard97ac1312001-05-30 19:14:17 +00005731 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005732
5733 /* number of chars to copy */
5734 l -= i;
5735
Daniel Veillard97ac1312001-05-30 19:14:17 +00005736 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005737 if (ret == NULL)
5738 valuePush(ctxt, xmlXPathNewCString(""));
5739 else {
5740 valuePush(ctxt, xmlXPathNewString(ret));
5741 xmlFree(ret);
5742 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005743
Owen Taylor3473f882001-02-23 17:55:21 +00005744 xmlXPathFreeObject(str);
5745}
5746
5747/**
5748 * xmlXPathSubstringBeforeFunction:
5749 * @ctxt: the XPath Parser context
5750 * @nargs: the number of arguments
5751 *
5752 * Implement the substring-before() XPath function
5753 * string substring-before(string, string)
5754 * The substring-before function returns the substring of the first
5755 * argument string that precedes the first occurrence of the second
5756 * argument string in the first argument string, or the empty string
5757 * if the first argument string does not contain the second argument
5758 * string. For example, substring-before("1999/04/01","/") returns 1999.
5759 */
5760void
5761xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5762 xmlXPathObjectPtr str;
5763 xmlXPathObjectPtr find;
5764 xmlBufferPtr target;
5765 const xmlChar *point;
5766 int offset;
5767
5768 CHECK_ARITY(2);
5769 CAST_TO_STRING;
5770 find = valuePop(ctxt);
5771 CAST_TO_STRING;
5772 str = valuePop(ctxt);
5773
5774 target = xmlBufferCreate();
5775 if (target) {
5776 point = xmlStrstr(str->stringval, find->stringval);
5777 if (point) {
5778 offset = (int)(point - str->stringval);
5779 xmlBufferAdd(target, str->stringval, offset);
5780 }
5781 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5782 xmlBufferFree(target);
5783 }
5784
5785 xmlXPathFreeObject(str);
5786 xmlXPathFreeObject(find);
5787}
5788
5789/**
5790 * xmlXPathSubstringAfterFunction:
5791 * @ctxt: the XPath Parser context
5792 * @nargs: the number of arguments
5793 *
5794 * Implement the substring-after() XPath function
5795 * string substring-after(string, string)
5796 * The substring-after function returns the substring of the first
5797 * argument string that follows the first occurrence of the second
5798 * argument string in the first argument string, or the empty stringi
5799 * if the first argument string does not contain the second argument
5800 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5801 * and substring-after("1999/04/01","19") returns 99/04/01.
5802 */
5803void
5804xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5805 xmlXPathObjectPtr str;
5806 xmlXPathObjectPtr find;
5807 xmlBufferPtr target;
5808 const xmlChar *point;
5809 int offset;
5810
5811 CHECK_ARITY(2);
5812 CAST_TO_STRING;
5813 find = valuePop(ctxt);
5814 CAST_TO_STRING;
5815 str = valuePop(ctxt);
5816
5817 target = xmlBufferCreate();
5818 if (target) {
5819 point = xmlStrstr(str->stringval, find->stringval);
5820 if (point) {
5821 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5822 xmlBufferAdd(target, &str->stringval[offset],
5823 xmlStrlen(str->stringval) - offset);
5824 }
5825 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5826 xmlBufferFree(target);
5827 }
5828
5829 xmlXPathFreeObject(str);
5830 xmlXPathFreeObject(find);
5831}
5832
5833/**
5834 * xmlXPathNormalizeFunction:
5835 * @ctxt: the XPath Parser context
5836 * @nargs: the number of arguments
5837 *
5838 * Implement the normalize-space() XPath function
5839 * string normalize-space(string?)
5840 * The normalize-space function returns the argument string with white
5841 * space normalized by stripping leading and trailing whitespace
5842 * and replacing sequences of whitespace characters by a single
5843 * space. Whitespace characters are the same allowed by the S production
5844 * in XML. If the argument is omitted, it defaults to the context
5845 * node converted to a string, in other words the value of the context node.
5846 */
5847void
5848xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5849 xmlXPathObjectPtr obj = NULL;
5850 xmlChar *source = NULL;
5851 xmlBufferPtr target;
5852 xmlChar blank;
5853
5854 if (nargs == 0) {
5855 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005856 valuePush(ctxt,
5857 xmlXPathWrapString(
5858 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005859 nargs = 1;
5860 }
5861
5862 CHECK_ARITY(1);
5863 CAST_TO_STRING;
5864 CHECK_TYPE(XPATH_STRING);
5865 obj = valuePop(ctxt);
5866 source = obj->stringval;
5867
5868 target = xmlBufferCreate();
5869 if (target && source) {
5870
5871 /* Skip leading whitespaces */
5872 while (IS_BLANK(*source))
5873 source++;
5874
5875 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5876 blank = 0;
5877 while (*source) {
5878 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005879 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005880 } else {
5881 if (blank) {
5882 xmlBufferAdd(target, &blank, 1);
5883 blank = 0;
5884 }
5885 xmlBufferAdd(target, source, 1);
5886 }
5887 source++;
5888 }
5889
5890 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5891 xmlBufferFree(target);
5892 }
5893 xmlXPathFreeObject(obj);
5894}
5895
5896/**
5897 * xmlXPathTranslateFunction:
5898 * @ctxt: the XPath Parser context
5899 * @nargs: the number of arguments
5900 *
5901 * Implement the translate() XPath function
5902 * string translate(string, string, string)
5903 * The translate function returns the first argument string with
5904 * occurrences of characters in the second argument string replaced
5905 * by the character at the corresponding position in the third argument
5906 * string. For example, translate("bar","abc","ABC") returns the string
5907 * BAr. If there is a character in the second argument string with no
5908 * character at a corresponding position in the third argument string
5909 * (because the second argument string is longer than the third argument
5910 * string), then occurrences of that character in the first argument
5911 * string are removed. For example, translate("--aaa--","abc-","ABC")
5912 * returns "AAA". If a character occurs more than once in second
5913 * argument string, then the first occurrence determines the replacement
5914 * character. If the third argument string is longer than the second
5915 * argument string, then excess characters are ignored.
5916 */
5917void
5918xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005919 xmlXPathObjectPtr str;
5920 xmlXPathObjectPtr from;
5921 xmlXPathObjectPtr to;
5922 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005923 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005924 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005925 xmlChar *point;
5926 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005927
Daniel Veillarde043ee12001-04-16 14:08:07 +00005928 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005929
Daniel Veillarde043ee12001-04-16 14:08:07 +00005930 CAST_TO_STRING;
5931 to = valuePop(ctxt);
5932 CAST_TO_STRING;
5933 from = valuePop(ctxt);
5934 CAST_TO_STRING;
5935 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005936
Daniel Veillarde043ee12001-04-16 14:08:07 +00005937 target = xmlBufferCreate();
5938 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005939 max = xmlUTF8Strlen(to->stringval);
5940 for (cptr = str->stringval; (ch=*cptr); ) {
5941 offset = xmlUTF8Strloc(from->stringval, cptr);
5942 if (offset >= 0) {
5943 if (offset < max) {
5944 point = xmlUTF8Strpos(to->stringval, offset);
5945 if (point)
5946 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5947 }
5948 } else
5949 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5950
5951 /* Step to next character in input */
5952 cptr++;
5953 if ( ch & 0x80 ) {
5954 /* if not simple ascii, verify proper format */
5955 if ( (ch & 0xc0) != 0xc0 ) {
5956 xmlGenericError(xmlGenericErrorContext,
5957 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5958 break;
5959 }
5960 /* then skip over remaining bytes for this char */
5961 while ( (ch <<= 1) & 0x80 )
5962 if ( (*cptr++ & 0xc0) != 0x80 ) {
5963 xmlGenericError(xmlGenericErrorContext,
5964 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5965 break;
5966 }
5967 if (ch & 0x80) /* must have had error encountered */
5968 break;
5969 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005970 }
Owen Taylor3473f882001-02-23 17:55:21 +00005971 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005972 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5973 xmlBufferFree(target);
5974 xmlXPathFreeObject(str);
5975 xmlXPathFreeObject(from);
5976 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005977}
5978
5979/**
5980 * xmlXPathBooleanFunction:
5981 * @ctxt: the XPath Parser context
5982 * @nargs: the number of arguments
5983 *
5984 * Implement the boolean() XPath function
5985 * boolean boolean(object)
5986 * he boolean function converts its argument to a boolean as follows:
5987 * - a number is true if and only if it is neither positive or
5988 * negative zero nor NaN
5989 * - a node-set is true if and only if it is non-empty
5990 * - a string is true if and only if its length is non-zero
5991 */
5992void
5993xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5994 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005995
5996 CHECK_ARITY(1);
5997 cur = valuePop(ctxt);
5998 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005999 cur = xmlXPathConvertBoolean(cur);
6000 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006001}
6002
6003/**
6004 * xmlXPathNotFunction:
6005 * @ctxt: the XPath Parser context
6006 * @nargs: the number of arguments
6007 *
6008 * Implement the not() XPath function
6009 * boolean not(boolean)
6010 * The not function returns true if its argument is false,
6011 * and false otherwise.
6012 */
6013void
6014xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6015 CHECK_ARITY(1);
6016 CAST_TO_BOOLEAN;
6017 CHECK_TYPE(XPATH_BOOLEAN);
6018 ctxt->value->boolval = ! ctxt->value->boolval;
6019}
6020
6021/**
6022 * xmlXPathTrueFunction:
6023 * @ctxt: the XPath Parser context
6024 * @nargs: the number of arguments
6025 *
6026 * Implement the true() XPath function
6027 * boolean true()
6028 */
6029void
6030xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6031 CHECK_ARITY(0);
6032 valuePush(ctxt, xmlXPathNewBoolean(1));
6033}
6034
6035/**
6036 * xmlXPathFalseFunction:
6037 * @ctxt: the XPath Parser context
6038 * @nargs: the number of arguments
6039 *
6040 * Implement the false() XPath function
6041 * boolean false()
6042 */
6043void
6044xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6045 CHECK_ARITY(0);
6046 valuePush(ctxt, xmlXPathNewBoolean(0));
6047}
6048
6049/**
6050 * xmlXPathLangFunction:
6051 * @ctxt: the XPath Parser context
6052 * @nargs: the number of arguments
6053 *
6054 * Implement the lang() XPath function
6055 * boolean lang(string)
6056 * The lang function returns true or false depending on whether the
6057 * language of the context node as specified by xml:lang attributes
6058 * is the same as or is a sublanguage of the language specified by
6059 * the argument string. The language of the context node is determined
6060 * by the value of the xml:lang attribute on the context node, or, if
6061 * the context node has no xml:lang attribute, by the value of the
6062 * xml:lang attribute on the nearest ancestor of the context node that
6063 * has an xml:lang attribute. If there is no such attribute, then lang
6064 * returns false. If there is such an attribute, then lang returns
6065 * true if the attribute value is equal to the argument ignoring case,
6066 * or if there is some suffix starting with - such that the attribute
6067 * value is equal to the argument ignoring that suffix of the attribute
6068 * value and ignoring case.
6069 */
6070void
6071xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6072 xmlXPathObjectPtr val;
6073 const xmlChar *theLang;
6074 const xmlChar *lang;
6075 int ret = 0;
6076 int i;
6077
6078 CHECK_ARITY(1);
6079 CAST_TO_STRING;
6080 CHECK_TYPE(XPATH_STRING);
6081 val = valuePop(ctxt);
6082 lang = val->stringval;
6083 theLang = xmlNodeGetLang(ctxt->context->node);
6084 if ((theLang != NULL) && (lang != NULL)) {
6085 for (i = 0;lang[i] != 0;i++)
6086 if (toupper(lang[i]) != toupper(theLang[i]))
6087 goto not_equal;
6088 ret = 1;
6089 }
6090not_equal:
6091 xmlXPathFreeObject(val);
6092 valuePush(ctxt, xmlXPathNewBoolean(ret));
6093}
6094
6095/**
6096 * xmlXPathNumberFunction:
6097 * @ctxt: the XPath Parser context
6098 * @nargs: the number of arguments
6099 *
6100 * Implement the number() XPath function
6101 * number number(object?)
6102 */
6103void
6104xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6105 xmlXPathObjectPtr cur;
6106 double res;
6107
6108 if (nargs == 0) {
6109 if (ctxt->context->node == NULL) {
6110 valuePush(ctxt, xmlXPathNewFloat(0.0));
6111 } else {
6112 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6113
6114 res = xmlXPathStringEvalNumber(content);
6115 valuePush(ctxt, xmlXPathNewFloat(res));
6116 xmlFree(content);
6117 }
6118 return;
6119 }
6120
6121 CHECK_ARITY(1);
6122 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006123 cur = xmlXPathConvertNumber(cur);
6124 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006125}
6126
6127/**
6128 * xmlXPathSumFunction:
6129 * @ctxt: the XPath Parser context
6130 * @nargs: the number of arguments
6131 *
6132 * Implement the sum() XPath function
6133 * number sum(node-set)
6134 * The sum function returns the sum of the values of the nodes in
6135 * the argument node-set.
6136 */
6137void
6138xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6139 xmlXPathObjectPtr cur;
6140 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006141 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006142
6143 CHECK_ARITY(1);
6144 if ((ctxt->value == NULL) ||
6145 ((ctxt->value->type != XPATH_NODESET) &&
6146 (ctxt->value->type != XPATH_XSLT_TREE)))
6147 XP_ERROR(XPATH_INVALID_TYPE);
6148 cur = valuePop(ctxt);
6149
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006150 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006151 valuePush(ctxt, xmlXPathNewFloat(0.0));
6152 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006153 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6154 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006155 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006156 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006157 }
6158 xmlXPathFreeObject(cur);
6159}
6160
6161/**
6162 * xmlXPathFloorFunction:
6163 * @ctxt: the XPath Parser context
6164 * @nargs: the number of arguments
6165 *
6166 * Implement the floor() XPath function
6167 * number floor(number)
6168 * The floor function returns the largest (closest to positive infinity)
6169 * number that is not greater than the argument and that is an integer.
6170 */
6171void
6172xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6173 CHECK_ARITY(1);
6174 CAST_TO_NUMBER;
6175 CHECK_TYPE(XPATH_NUMBER);
6176#if 0
6177 ctxt->value->floatval = floor(ctxt->value->floatval);
6178#else
6179 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6180 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6181#endif
6182}
6183
6184/**
6185 * xmlXPathCeilingFunction:
6186 * @ctxt: the XPath Parser context
6187 * @nargs: the number of arguments
6188 *
6189 * Implement the ceiling() XPath function
6190 * number ceiling(number)
6191 * The ceiling function returns the smallest (closest to negative infinity)
6192 * number that is not less than the argument and that is an integer.
6193 */
6194void
6195xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6196 double f;
6197
6198 CHECK_ARITY(1);
6199 CAST_TO_NUMBER;
6200 CHECK_TYPE(XPATH_NUMBER);
6201
6202#if 0
6203 ctxt->value->floatval = ceil(ctxt->value->floatval);
6204#else
6205 f = (double)((int) ctxt->value->floatval);
6206 if (f != ctxt->value->floatval)
6207 ctxt->value->floatval = f + 1;
6208#endif
6209}
6210
6211/**
6212 * xmlXPathRoundFunction:
6213 * @ctxt: the XPath Parser context
6214 * @nargs: the number of arguments
6215 *
6216 * Implement the round() XPath function
6217 * number round(number)
6218 * The round function returns the number that is closest to the
6219 * argument and that is an integer. If there are two such numbers,
6220 * then the one that is even is returned.
6221 */
6222void
6223xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6224 double f;
6225
6226 CHECK_ARITY(1);
6227 CAST_TO_NUMBER;
6228 CHECK_TYPE(XPATH_NUMBER);
6229
Daniel Veillardcda96922001-08-21 10:56:31 +00006230 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6231 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6232 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006233 (ctxt->value->floatval == 0.0))
6234 return;
6235
6236#if 0
6237 f = floor(ctxt->value->floatval);
6238#else
6239 f = (double)((int) ctxt->value->floatval);
6240#endif
6241 if (ctxt->value->floatval < f + 0.5)
6242 ctxt->value->floatval = f;
6243 else
6244 ctxt->value->floatval = f + 1;
6245}
6246
6247/************************************************************************
6248 * *
6249 * The Parser *
6250 * *
6251 ************************************************************************/
6252
6253/*
6254 * a couple of forward declarations since we use a recursive call based
6255 * implementation.
6256 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006257static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006258static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006259static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006260#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006261static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6262#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006263#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006264static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006265#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006266static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6267 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006268
6269/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006270 * xmlXPathCurrentChar:
6271 * @ctxt: the XPath parser context
6272 * @cur: pointer to the beginning of the char
6273 * @len: pointer to the length of the char read
6274 *
6275 * The current char value, if using UTF-8 this may actaully span multiple
6276 * bytes in the input buffer.
6277 *
6278 * Returns the current char value and its lenght
6279 */
6280
6281static int
6282xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6283 unsigned char c;
6284 unsigned int val;
6285 const xmlChar *cur;
6286
6287 if (ctxt == NULL)
6288 return(0);
6289 cur = ctxt->cur;
6290
6291 /*
6292 * We are supposed to handle UTF8, check it's valid
6293 * From rfc2044: encoding of the Unicode values on UTF-8:
6294 *
6295 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6296 * 0000 0000-0000 007F 0xxxxxxx
6297 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6298 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6299 *
6300 * Check for the 0x110000 limit too
6301 */
6302 c = *cur;
6303 if (c & 0x80) {
6304 if ((cur[1] & 0xc0) != 0x80)
6305 goto encoding_error;
6306 if ((c & 0xe0) == 0xe0) {
6307
6308 if ((cur[2] & 0xc0) != 0x80)
6309 goto encoding_error;
6310 if ((c & 0xf0) == 0xf0) {
6311 if (((c & 0xf8) != 0xf0) ||
6312 ((cur[3] & 0xc0) != 0x80))
6313 goto encoding_error;
6314 /* 4-byte code */
6315 *len = 4;
6316 val = (cur[0] & 0x7) << 18;
6317 val |= (cur[1] & 0x3f) << 12;
6318 val |= (cur[2] & 0x3f) << 6;
6319 val |= cur[3] & 0x3f;
6320 } else {
6321 /* 3-byte code */
6322 *len = 3;
6323 val = (cur[0] & 0xf) << 12;
6324 val |= (cur[1] & 0x3f) << 6;
6325 val |= cur[2] & 0x3f;
6326 }
6327 } else {
6328 /* 2-byte code */
6329 *len = 2;
6330 val = (cur[0] & 0x1f) << 6;
6331 val |= cur[1] & 0x3f;
6332 }
6333 if (!IS_CHAR(val)) {
6334 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6335 }
6336 return(val);
6337 } else {
6338 /* 1-byte code */
6339 *len = 1;
6340 return((int) *cur);
6341 }
6342encoding_error:
6343 /*
6344 * If we detect an UTF8 error that probably mean that the
6345 * input encoding didn't get properly advertized in the
6346 * declaration header. Report the error and switch the encoding
6347 * to ISO-Latin-1 (if you don't like this policy, just declare the
6348 * encoding !)
6349 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006350 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006351 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006352}
6353
6354/**
Owen Taylor3473f882001-02-23 17:55:21 +00006355 * xmlXPathParseNCName:
6356 * @ctxt: the XPath Parser context
6357 *
6358 * parse an XML namespace non qualified name.
6359 *
6360 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6361 *
6362 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6363 * CombiningChar | Extender
6364 *
6365 * Returns the namespace name or NULL
6366 */
6367
6368xmlChar *
6369xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006370 const xmlChar *in;
6371 xmlChar *ret;
6372 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006373
Daniel Veillard2156a562001-04-28 12:24:34 +00006374 /*
6375 * Accelerator for simple ASCII names
6376 */
6377 in = ctxt->cur;
6378 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6379 ((*in >= 0x41) && (*in <= 0x5A)) ||
6380 (*in == '_')) {
6381 in++;
6382 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6383 ((*in >= 0x41) && (*in <= 0x5A)) ||
6384 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006385 (*in == '_') || (*in == '.') ||
6386 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006387 in++;
6388 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6389 (*in == '[') || (*in == ']') || (*in == ':') ||
6390 (*in == '@') || (*in == '*')) {
6391 count = in - ctxt->cur;
6392 if (count == 0)
6393 return(NULL);
6394 ret = xmlStrndup(ctxt->cur, count);
6395 ctxt->cur = in;
6396 return(ret);
6397 }
6398 }
6399 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006400}
6401
Daniel Veillard2156a562001-04-28 12:24:34 +00006402
Owen Taylor3473f882001-02-23 17:55:21 +00006403/**
6404 * xmlXPathParseQName:
6405 * @ctxt: the XPath Parser context
6406 * @prefix: a xmlChar **
6407 *
6408 * parse an XML qualified name
6409 *
6410 * [NS 5] QName ::= (Prefix ':')? LocalPart
6411 *
6412 * [NS 6] Prefix ::= NCName
6413 *
6414 * [NS 7] LocalPart ::= NCName
6415 *
6416 * Returns the function returns the local part, and prefix is updated
6417 * to get the Prefix if any.
6418 */
6419
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006420static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006421xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6422 xmlChar *ret = NULL;
6423
6424 *prefix = NULL;
6425 ret = xmlXPathParseNCName(ctxt);
6426 if (CUR == ':') {
6427 *prefix = ret;
6428 NEXT;
6429 ret = xmlXPathParseNCName(ctxt);
6430 }
6431 return(ret);
6432}
6433
6434/**
6435 * xmlXPathParseName:
6436 * @ctxt: the XPath Parser context
6437 *
6438 * parse an XML name
6439 *
6440 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6441 * CombiningChar | Extender
6442 *
6443 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6444 *
6445 * Returns the namespace name or NULL
6446 */
6447
6448xmlChar *
6449xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006450 const xmlChar *in;
6451 xmlChar *ret;
6452 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006453
Daniel Veillard61d80a22001-04-27 17:13:01 +00006454 /*
6455 * Accelerator for simple ASCII names
6456 */
6457 in = ctxt->cur;
6458 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6459 ((*in >= 0x41) && (*in <= 0x5A)) ||
6460 (*in == '_') || (*in == ':')) {
6461 in++;
6462 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6463 ((*in >= 0x41) && (*in <= 0x5A)) ||
6464 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006465 (*in == '_') || (*in == '-') ||
6466 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006467 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006468 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006469 count = in - ctxt->cur;
6470 ret = xmlStrndup(ctxt->cur, count);
6471 ctxt->cur = in;
6472 return(ret);
6473 }
6474 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006475 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006476}
6477
Daniel Veillard61d80a22001-04-27 17:13:01 +00006478static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006479xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006480 xmlChar buf[XML_MAX_NAMELEN + 5];
6481 int len = 0, l;
6482 int c;
6483
6484 /*
6485 * Handler for more complex cases
6486 */
6487 c = CUR_CHAR(l);
6488 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006489 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6490 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006491 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006492 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006493 return(NULL);
6494 }
6495
6496 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6497 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6498 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006499 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006500 (IS_COMBINING(c)) ||
6501 (IS_EXTENDER(c)))) {
6502 COPY_BUF(l,buf,len,c);
6503 NEXTL(l);
6504 c = CUR_CHAR(l);
6505 if (len >= XML_MAX_NAMELEN) {
6506 /*
6507 * Okay someone managed to make a huge name, so he's ready to pay
6508 * for the processing speed.
6509 */
6510 xmlChar *buffer;
6511 int max = len * 2;
6512
6513 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6514 if (buffer == NULL) {
6515 XP_ERROR0(XPATH_MEMORY_ERROR);
6516 }
6517 memcpy(buffer, buf, len);
6518 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6519 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006520 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006521 (IS_COMBINING(c)) ||
6522 (IS_EXTENDER(c))) {
6523 if (len + 10 > max) {
6524 max *= 2;
6525 buffer = (xmlChar *) xmlRealloc(buffer,
6526 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006527 if (buffer == NULL) {
6528 XP_ERROR0(XPATH_MEMORY_ERROR);
6529 }
6530 }
6531 COPY_BUF(l,buffer,len,c);
6532 NEXTL(l);
6533 c = CUR_CHAR(l);
6534 }
6535 buffer[len] = 0;
6536 return(buffer);
6537 }
6538 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006539 if (len == 0)
6540 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006541 return(xmlStrndup(buf, len));
6542}
Owen Taylor3473f882001-02-23 17:55:21 +00006543/**
6544 * xmlXPathStringEvalNumber:
6545 * @str: A string to scan
6546 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006547 * [30a] Float ::= Number ('e' Digits?)?
6548 *
Owen Taylor3473f882001-02-23 17:55:21 +00006549 * [30] Number ::= Digits ('.' Digits?)?
6550 * | '.' Digits
6551 * [31] Digits ::= [0-9]+
6552 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006553 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006554 * In complement of the Number expression, this function also handles
6555 * negative values : '-' Number.
6556 *
6557 * Returns the double value.
6558 */
6559double
6560xmlXPathStringEvalNumber(const xmlChar *str) {
6561 const xmlChar *cur = str;
6562 double ret = 0.0;
6563 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006564 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006565 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006566 int exponent = 0;
6567 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006568#ifdef __GNUC__
6569 unsigned long tmp = 0;
6570#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006571
Owen Taylor3473f882001-02-23 17:55:21 +00006572 while (IS_BLANK(*cur)) cur++;
6573 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6574 return(xmlXPathNAN);
6575 }
6576 if (*cur == '-') {
6577 isneg = 1;
6578 cur++;
6579 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006580
6581#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006582 /*
Daniel Veillardb06c6142001-08-27 14:26:30 +00006583 * tmp is a workaround against a gcc compiler bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006584 */
Owen Taylor3473f882001-02-23 17:55:21 +00006585 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006586 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006587 ok = 1;
6588 cur++;
6589 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006590 ret = (double) tmp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006591#else
6592 while ((*cur >= '0') && (*cur <= '9')) {
6593 ret = ret * 10 + (*cur - '0');
6594 ok = 1;
6595 cur++;
6596 }
6597#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006598
Owen Taylor3473f882001-02-23 17:55:21 +00006599 if (*cur == '.') {
6600 cur++;
6601 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6602 return(xmlXPathNAN);
6603 }
6604 while ((*cur >= '0') && (*cur <= '9')) {
6605 mult /= 10;
6606 ret = ret + (*cur - '0') * mult;
6607 cur++;
6608 }
6609 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006610 if ((*cur == 'e') || (*cur == 'E')) {
6611 cur++;
6612 if (*cur == '-') {
6613 is_exponent_negative = 1;
6614 cur++;
6615 }
6616 while ((*cur >= '0') && (*cur <= '9')) {
6617 exponent = exponent * 10 + (*cur - '0');
6618 cur++;
6619 }
6620 }
Owen Taylor3473f882001-02-23 17:55:21 +00006621 while (IS_BLANK(*cur)) cur++;
6622 if (*cur != 0) return(xmlXPathNAN);
6623 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006624 if (is_exponent_negative) exponent = -exponent;
6625 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006626 return(ret);
6627}
6628
6629/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006630 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006631 * @ctxt: the XPath Parser context
6632 *
6633 * [30] Number ::= Digits ('.' Digits?)?
6634 * | '.' Digits
6635 * [31] Digits ::= [0-9]+
6636 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006637 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006638 *
6639 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006640static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006641xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6642{
Owen Taylor3473f882001-02-23 17:55:21 +00006643 double ret = 0.0;
6644 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006645 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006646 int exponent = 0;
6647 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006648
6649 CHECK_ERROR;
6650 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6651 XP_ERROR(XPATH_NUMBER_ERROR);
6652 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006653 /*
6654 * Try to work around a gcc optimizer bug
6655 */
Owen Taylor3473f882001-02-23 17:55:21 +00006656 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006657 tmp = tmp * 10 + (CUR - '0');
6658 ok = 1;
6659 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006660 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006661 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006662 if (CUR == '.') {
6663 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006664 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6665 XP_ERROR(XPATH_NUMBER_ERROR);
6666 }
6667 while ((CUR >= '0') && (CUR <= '9')) {
6668 mult /= 10;
6669 ret = ret + (CUR - '0') * mult;
6670 NEXT;
6671 }
Owen Taylor3473f882001-02-23 17:55:21 +00006672 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006673 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006674 NEXT;
6675 if (CUR == '-') {
6676 is_exponent_negative = 1;
6677 NEXT;
6678 }
6679 while ((CUR >= '0') && (CUR <= '9')) {
6680 exponent = exponent * 10 + (CUR - '0');
6681 NEXT;
6682 }
6683 if (is_exponent_negative)
6684 exponent = -exponent;
6685 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006686 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006687 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006688 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006689}
6690
6691/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006692 * xmlXPathParseLiteral:
6693 * @ctxt: the XPath Parser context
6694 *
6695 * Parse a Literal
6696 *
6697 * [29] Literal ::= '"' [^"]* '"'
6698 * | "'" [^']* "'"
6699 *
6700 * Returns the value found or NULL in case of error
6701 */
6702static xmlChar *
6703xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6704 const xmlChar *q;
6705 xmlChar *ret = NULL;
6706
6707 if (CUR == '"') {
6708 NEXT;
6709 q = CUR_PTR;
6710 while ((IS_CHAR(CUR)) && (CUR != '"'))
6711 NEXT;
6712 if (!IS_CHAR(CUR)) {
6713 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6714 } else {
6715 ret = xmlStrndup(q, CUR_PTR - q);
6716 NEXT;
6717 }
6718 } else if (CUR == '\'') {
6719 NEXT;
6720 q = CUR_PTR;
6721 while ((IS_CHAR(CUR)) && (CUR != '\''))
6722 NEXT;
6723 if (!IS_CHAR(CUR)) {
6724 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6725 } else {
6726 ret = xmlStrndup(q, CUR_PTR - q);
6727 NEXT;
6728 }
6729 } else {
6730 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6731 }
6732 return(ret);
6733}
6734
6735/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006736 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006737 * @ctxt: the XPath Parser context
6738 *
6739 * Parse a Literal and push it on the stack.
6740 *
6741 * [29] Literal ::= '"' [^"]* '"'
6742 * | "'" [^']* "'"
6743 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006744 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006745 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006746static void
6747xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006748 const xmlChar *q;
6749 xmlChar *ret = NULL;
6750
6751 if (CUR == '"') {
6752 NEXT;
6753 q = CUR_PTR;
6754 while ((IS_CHAR(CUR)) && (CUR != '"'))
6755 NEXT;
6756 if (!IS_CHAR(CUR)) {
6757 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6758 } else {
6759 ret = xmlStrndup(q, CUR_PTR - q);
6760 NEXT;
6761 }
6762 } else if (CUR == '\'') {
6763 NEXT;
6764 q = CUR_PTR;
6765 while ((IS_CHAR(CUR)) && (CUR != '\''))
6766 NEXT;
6767 if (!IS_CHAR(CUR)) {
6768 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6769 } else {
6770 ret = xmlStrndup(q, CUR_PTR - q);
6771 NEXT;
6772 }
6773 } else {
6774 XP_ERROR(XPATH_START_LITERAL_ERROR);
6775 }
6776 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006777 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6778 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006779 xmlFree(ret);
6780}
6781
6782/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006783 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006784 * @ctxt: the XPath Parser context
6785 *
6786 * Parse a VariableReference, evaluate it and push it on the stack.
6787 *
6788 * The variable bindings consist of a mapping from variable names
6789 * to variable values. The value of a variable is an object, which
6790 * of any of the types that are possible for the value of an expression,
6791 * and may also be of additional types not specified here.
6792 *
6793 * Early evaluation is possible since:
6794 * The variable bindings [...] used to evaluate a subexpression are
6795 * always the same as those used to evaluate the containing expression.
6796 *
6797 * [36] VariableReference ::= '$' QName
6798 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006799static void
6800xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006801 xmlChar *name;
6802 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006803
6804 SKIP_BLANKS;
6805 if (CUR != '$') {
6806 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6807 }
6808 NEXT;
6809 name = xmlXPathParseQName(ctxt, &prefix);
6810 if (name == NULL) {
6811 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6812 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006813 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006814 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6815 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006816 SKIP_BLANKS;
6817}
6818
6819/**
6820 * xmlXPathIsNodeType:
6821 * @ctxt: the XPath Parser context
6822 * @name: a name string
6823 *
6824 * Is the name given a NodeType one.
6825 *
6826 * [38] NodeType ::= 'comment'
6827 * | 'text'
6828 * | 'processing-instruction'
6829 * | 'node'
6830 *
6831 * Returns 1 if true 0 otherwise
6832 */
6833int
6834xmlXPathIsNodeType(const xmlChar *name) {
6835 if (name == NULL)
6836 return(0);
6837
6838 if (xmlStrEqual(name, BAD_CAST "comment"))
6839 return(1);
6840 if (xmlStrEqual(name, BAD_CAST "text"))
6841 return(1);
6842 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6843 return(1);
6844 if (xmlStrEqual(name, BAD_CAST "node"))
6845 return(1);
6846 return(0);
6847}
6848
6849/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006850 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006851 * @ctxt: the XPath Parser context
6852 *
6853 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6854 * [17] Argument ::= Expr
6855 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006856 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006857 * pushed on the stack
6858 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006859static void
6860xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006861 xmlChar *name;
6862 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006863 int nbargs = 0;
6864
6865 name = xmlXPathParseQName(ctxt, &prefix);
6866 if (name == NULL) {
6867 XP_ERROR(XPATH_EXPR_ERROR);
6868 }
6869 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006870#ifdef DEBUG_EXPR
6871 if (prefix == NULL)
6872 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6873 name);
6874 else
6875 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6876 prefix, name);
6877#endif
6878
Owen Taylor3473f882001-02-23 17:55:21 +00006879 if (CUR != '(') {
6880 XP_ERROR(XPATH_EXPR_ERROR);
6881 }
6882 NEXT;
6883 SKIP_BLANKS;
6884
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006885 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006886 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006887 int op1 = ctxt->comp->last;
6888 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006889 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006890 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006891 nbargs++;
6892 if (CUR == ')') break;
6893 if (CUR != ',') {
6894 XP_ERROR(XPATH_EXPR_ERROR);
6895 }
6896 NEXT;
6897 SKIP_BLANKS;
6898 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006899 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6900 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006901 NEXT;
6902 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006903}
6904
6905/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006906 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006907 * @ctxt: the XPath Parser context
6908 *
6909 * [15] PrimaryExpr ::= VariableReference
6910 * | '(' Expr ')'
6911 * | Literal
6912 * | Number
6913 * | FunctionCall
6914 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006915 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006916 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006917static void
6918xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006919 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006920 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006921 else if (CUR == '(') {
6922 NEXT;
6923 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006924 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006925 if (CUR != ')') {
6926 XP_ERROR(XPATH_EXPR_ERROR);
6927 }
6928 NEXT;
6929 SKIP_BLANKS;
6930 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006931 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006932 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006933 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006934 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006935 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006936 }
6937 SKIP_BLANKS;
6938}
6939
6940/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006941 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006942 * @ctxt: the XPath Parser context
6943 *
6944 * [20] FilterExpr ::= PrimaryExpr
6945 * | FilterExpr Predicate
6946 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006947 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006948 * Square brackets are used to filter expressions in the same way that
6949 * they are used in location paths. It is an error if the expression to
6950 * be filtered does not evaluate to a node-set. The context node list
6951 * used for evaluating the expression in square brackets is the node-set
6952 * to be filtered listed in document order.
6953 */
6954
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006955static void
6956xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6957 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006958 CHECK_ERROR;
6959 SKIP_BLANKS;
6960
6961 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006962 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006963 SKIP_BLANKS;
6964 }
6965
6966
6967}
6968
6969/**
6970 * xmlXPathScanName:
6971 * @ctxt: the XPath Parser context
6972 *
6973 * Trickery: parse an XML name but without consuming the input flow
6974 * Needed to avoid insanity in the parser state.
6975 *
6976 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6977 * CombiningChar | Extender
6978 *
6979 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6980 *
6981 * [6] Names ::= Name (S Name)*
6982 *
6983 * Returns the Name parsed or NULL
6984 */
6985
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006986static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006987xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6988 xmlChar buf[XML_MAX_NAMELEN];
6989 int len = 0;
6990
6991 SKIP_BLANKS;
6992 if (!IS_LETTER(CUR) && (CUR != '_') &&
6993 (CUR != ':')) {
6994 return(NULL);
6995 }
6996
6997 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6998 (NXT(len) == '.') || (NXT(len) == '-') ||
6999 (NXT(len) == '_') || (NXT(len) == ':') ||
7000 (IS_COMBINING(NXT(len))) ||
7001 (IS_EXTENDER(NXT(len)))) {
7002 buf[len] = NXT(len);
7003 len++;
7004 if (len >= XML_MAX_NAMELEN) {
7005 xmlGenericError(xmlGenericErrorContext,
7006 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7007 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7008 (NXT(len) == '.') || (NXT(len) == '-') ||
7009 (NXT(len) == '_') || (NXT(len) == ':') ||
7010 (IS_COMBINING(NXT(len))) ||
7011 (IS_EXTENDER(NXT(len))))
7012 len++;
7013 break;
7014 }
7015 }
7016 return(xmlStrndup(buf, len));
7017}
7018
7019/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007020 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007021 * @ctxt: the XPath Parser context
7022 *
7023 * [19] PathExpr ::= LocationPath
7024 * | FilterExpr
7025 * | FilterExpr '/' RelativeLocationPath
7026 * | FilterExpr '//' RelativeLocationPath
7027 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007028 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007029 * The / operator and // operators combine an arbitrary expression
7030 * and a relative location path. It is an error if the expression
7031 * does not evaluate to a node-set.
7032 * The / operator does composition in the same way as when / is
7033 * used in a location path. As in location paths, // is short for
7034 * /descendant-or-self::node()/.
7035 */
7036
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007037static void
7038xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007039 int lc = 1; /* Should we branch to LocationPath ? */
7040 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7041
7042 SKIP_BLANKS;
7043 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7044 (CUR == '\'') || (CUR == '"')) {
7045 lc = 0;
7046 } else if (CUR == '*') {
7047 /* relative or absolute location path */
7048 lc = 1;
7049 } else if (CUR == '/') {
7050 /* relative or absolute location path */
7051 lc = 1;
7052 } else if (CUR == '@') {
7053 /* relative abbreviated attribute location path */
7054 lc = 1;
7055 } else if (CUR == '.') {
7056 /* relative abbreviated attribute location path */
7057 lc = 1;
7058 } else {
7059 /*
7060 * Problem is finding if we have a name here whether it's:
7061 * - a nodetype
7062 * - a function call in which case it's followed by '('
7063 * - an axis in which case it's followed by ':'
7064 * - a element name
7065 * We do an a priori analysis here rather than having to
7066 * maintain parsed token content through the recursive function
7067 * calls. This looks uglier but makes the code quite easier to
7068 * read/write/debug.
7069 */
7070 SKIP_BLANKS;
7071 name = xmlXPathScanName(ctxt);
7072 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7073#ifdef DEBUG_STEP
7074 xmlGenericError(xmlGenericErrorContext,
7075 "PathExpr: Axis\n");
7076#endif
7077 lc = 1;
7078 xmlFree(name);
7079 } else if (name != NULL) {
7080 int len =xmlStrlen(name);
7081 int blank = 0;
7082
7083
7084 while (NXT(len) != 0) {
7085 if (NXT(len) == '/') {
7086 /* element name */
7087#ifdef DEBUG_STEP
7088 xmlGenericError(xmlGenericErrorContext,
7089 "PathExpr: AbbrRelLocation\n");
7090#endif
7091 lc = 1;
7092 break;
7093 } else if (IS_BLANK(NXT(len))) {
7094 /* skip to next */
7095 blank = 1;
7096 } else if (NXT(len) == ':') {
7097#ifdef DEBUG_STEP
7098 xmlGenericError(xmlGenericErrorContext,
7099 "PathExpr: AbbrRelLocation\n");
7100#endif
7101 lc = 1;
7102 break;
7103 } else if ((NXT(len) == '(')) {
7104 /* Note Type or Function */
7105 if (xmlXPathIsNodeType(name)) {
7106#ifdef DEBUG_STEP
7107 xmlGenericError(xmlGenericErrorContext,
7108 "PathExpr: Type search\n");
7109#endif
7110 lc = 1;
7111 } else {
7112#ifdef DEBUG_STEP
7113 xmlGenericError(xmlGenericErrorContext,
7114 "PathExpr: function call\n");
7115#endif
7116 lc = 0;
7117 }
7118 break;
7119 } else if ((NXT(len) == '[')) {
7120 /* element name */
7121#ifdef DEBUG_STEP
7122 xmlGenericError(xmlGenericErrorContext,
7123 "PathExpr: AbbrRelLocation\n");
7124#endif
7125 lc = 1;
7126 break;
7127 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7128 (NXT(len) == '=')) {
7129 lc = 1;
7130 break;
7131 } else {
7132 lc = 1;
7133 break;
7134 }
7135 len++;
7136 }
7137 if (NXT(len) == 0) {
7138#ifdef DEBUG_STEP
7139 xmlGenericError(xmlGenericErrorContext,
7140 "PathExpr: AbbrRelLocation\n");
7141#endif
7142 /* element name */
7143 lc = 1;
7144 }
7145 xmlFree(name);
7146 } else {
7147 /* make sure all cases are covered explicitely */
7148 XP_ERROR(XPATH_EXPR_ERROR);
7149 }
7150 }
7151
7152 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007153 if (CUR == '/') {
7154 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7155 } else {
7156 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007157 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007158 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007159 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007160 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007161 CHECK_ERROR;
7162 if ((CUR == '/') && (NXT(1) == '/')) {
7163 SKIP(2);
7164 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007165
7166 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7167 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7168 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7169
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007170 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007171 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007172 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007173 }
7174 }
7175 SKIP_BLANKS;
7176}
7177
7178/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007179 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007180 * @ctxt: the XPath Parser context
7181 *
7182 * [18] UnionExpr ::= PathExpr
7183 * | UnionExpr '|' PathExpr
7184 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007185 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007186 */
7187
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007188static void
7189xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7190 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007191 CHECK_ERROR;
7192 SKIP_BLANKS;
7193 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007194 int op1 = ctxt->comp->last;
7195 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007196
7197 NEXT;
7198 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007199 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007200
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007201 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7202
Owen Taylor3473f882001-02-23 17:55:21 +00007203 SKIP_BLANKS;
7204 }
Owen Taylor3473f882001-02-23 17:55:21 +00007205}
7206
7207/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007208 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007209 * @ctxt: the XPath Parser context
7210 *
7211 * [27] UnaryExpr ::= UnionExpr
7212 * | '-' UnaryExpr
7213 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007214 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007215 */
7216
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007217static void
7218xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007219 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007220 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007221
7222 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007223 while (CUR == '-') {
7224 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007225 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007226 NEXT;
7227 SKIP_BLANKS;
7228 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007229
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007230 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007231 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007232 if (found) {
7233 if (minus)
7234 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7235 else
7236 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007237 }
7238}
7239
7240/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007241 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007242 * @ctxt: the XPath Parser context
7243 *
7244 * [26] MultiplicativeExpr ::= UnaryExpr
7245 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7246 * | MultiplicativeExpr 'div' UnaryExpr
7247 * | MultiplicativeExpr 'mod' UnaryExpr
7248 * [34] MultiplyOperator ::= '*'
7249 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007250 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007251 */
7252
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007253static void
7254xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7255 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007256 CHECK_ERROR;
7257 SKIP_BLANKS;
7258 while ((CUR == '*') ||
7259 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7260 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7261 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007262 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007263
7264 if (CUR == '*') {
7265 op = 0;
7266 NEXT;
7267 } else if (CUR == 'd') {
7268 op = 1;
7269 SKIP(3);
7270 } else if (CUR == 'm') {
7271 op = 2;
7272 SKIP(3);
7273 }
7274 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007275 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007276 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007277 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007278 SKIP_BLANKS;
7279 }
7280}
7281
7282/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007283 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007284 * @ctxt: the XPath Parser context
7285 *
7286 * [25] AdditiveExpr ::= MultiplicativeExpr
7287 * | AdditiveExpr '+' MultiplicativeExpr
7288 * | AdditiveExpr '-' MultiplicativeExpr
7289 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007290 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007291 */
7292
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007293static void
7294xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007295
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007296 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007297 CHECK_ERROR;
7298 SKIP_BLANKS;
7299 while ((CUR == '+') || (CUR == '-')) {
7300 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007301 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007302
7303 if (CUR == '+') plus = 1;
7304 else plus = 0;
7305 NEXT;
7306 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007307 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007308 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007309 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007310 SKIP_BLANKS;
7311 }
7312}
7313
7314/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007315 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007316 * @ctxt: the XPath Parser context
7317 *
7318 * [24] RelationalExpr ::= AdditiveExpr
7319 * | RelationalExpr '<' AdditiveExpr
7320 * | RelationalExpr '>' AdditiveExpr
7321 * | RelationalExpr '<=' AdditiveExpr
7322 * | RelationalExpr '>=' AdditiveExpr
7323 *
7324 * A <= B > C is allowed ? Answer from James, yes with
7325 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7326 * which is basically what got implemented.
7327 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007328 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007329 * on the stack
7330 */
7331
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007332static void
7333xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7334 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007335 CHECK_ERROR;
7336 SKIP_BLANKS;
7337 while ((CUR == '<') ||
7338 (CUR == '>') ||
7339 ((CUR == '<') && (NXT(1) == '=')) ||
7340 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007341 int inf, strict;
7342 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007343
7344 if (CUR == '<') inf = 1;
7345 else inf = 0;
7346 if (NXT(1) == '=') strict = 0;
7347 else strict = 1;
7348 NEXT;
7349 if (!strict) NEXT;
7350 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007351 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007352 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007353 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007354 SKIP_BLANKS;
7355 }
7356}
7357
7358/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007359 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007360 * @ctxt: the XPath Parser context
7361 *
7362 * [23] EqualityExpr ::= RelationalExpr
7363 * | EqualityExpr '=' RelationalExpr
7364 * | EqualityExpr '!=' RelationalExpr
7365 *
7366 * A != B != C is allowed ? Answer from James, yes with
7367 * (RelationalExpr = RelationalExpr) = RelationalExpr
7368 * (RelationalExpr != RelationalExpr) != RelationalExpr
7369 * which is basically what got implemented.
7370 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007371 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007372 *
7373 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007374static void
7375xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7376 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007377 CHECK_ERROR;
7378 SKIP_BLANKS;
7379 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007380 int eq;
7381 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007382
7383 if (CUR == '=') eq = 1;
7384 else eq = 0;
7385 NEXT;
7386 if (!eq) NEXT;
7387 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007388 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007389 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007390 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007391 SKIP_BLANKS;
7392 }
7393}
7394
7395/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007396 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007397 * @ctxt: the XPath Parser context
7398 *
7399 * [22] AndExpr ::= EqualityExpr
7400 * | AndExpr 'and' EqualityExpr
7401 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007402 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007403 *
7404 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007405static void
7406xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7407 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007408 CHECK_ERROR;
7409 SKIP_BLANKS;
7410 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007411 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007412 SKIP(3);
7413 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007414 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007415 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007416 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007417 SKIP_BLANKS;
7418 }
7419}
7420
7421/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007422 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007423 * @ctxt: the XPath Parser context
7424 *
7425 * [14] Expr ::= OrExpr
7426 * [21] OrExpr ::= AndExpr
7427 * | OrExpr 'or' AndExpr
7428 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007429 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007430 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007431static void
7432xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7433 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007434 CHECK_ERROR;
7435 SKIP_BLANKS;
7436 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007437 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007438 SKIP(2);
7439 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007440 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007441 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007442 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7443 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007444 SKIP_BLANKS;
7445 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007446 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7447 /* more ops could be optimized too */
7448 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7449 }
Owen Taylor3473f882001-02-23 17:55:21 +00007450}
7451
7452/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007453 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007454 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007455 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007456 *
7457 * [8] Predicate ::= '[' PredicateExpr ']'
7458 * [9] PredicateExpr ::= Expr
7459 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007460 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007461 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007462static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007463xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007464 int op1 = ctxt->comp->last;
7465
7466 SKIP_BLANKS;
7467 if (CUR != '[') {
7468 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7469 }
7470 NEXT;
7471 SKIP_BLANKS;
7472
7473 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007474 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007475 CHECK_ERROR;
7476
7477 if (CUR != ']') {
7478 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7479 }
7480
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007481 if (filter)
7482 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7483 else
7484 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007485
7486 NEXT;
7487 SKIP_BLANKS;
7488}
7489
7490/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007491 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007492 * @ctxt: the XPath Parser context
7493 * @test: pointer to a xmlXPathTestVal
7494 * @type: pointer to a xmlXPathTypeVal
7495 * @prefix: placeholder for a possible name prefix
7496 *
7497 * [7] NodeTest ::= NameTest
7498 * | NodeType '(' ')'
7499 * | 'processing-instruction' '(' Literal ')'
7500 *
7501 * [37] NameTest ::= '*'
7502 * | NCName ':' '*'
7503 * | QName
7504 * [38] NodeType ::= 'comment'
7505 * | 'text'
7506 * | 'processing-instruction'
7507 * | 'node'
7508 *
7509 * Returns the name found and update @test, @type and @prefix appropriately
7510 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007511static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007512xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7513 xmlXPathTypeVal *type, const xmlChar **prefix,
7514 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007515 int blanks;
7516
7517 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7518 STRANGE;
7519 return(NULL);
7520 }
7521 *type = 0;
7522 *test = 0;
7523 *prefix = NULL;
7524 SKIP_BLANKS;
7525
7526 if ((name == NULL) && (CUR == '*')) {
7527 /*
7528 * All elements
7529 */
7530 NEXT;
7531 *test = NODE_TEST_ALL;
7532 return(NULL);
7533 }
7534
7535 if (name == NULL)
7536 name = xmlXPathParseNCName(ctxt);
7537 if (name == NULL) {
7538 XP_ERROR0(XPATH_EXPR_ERROR);
7539 }
7540
7541 blanks = IS_BLANK(CUR);
7542 SKIP_BLANKS;
7543 if (CUR == '(') {
7544 NEXT;
7545 /*
7546 * NodeType or PI search
7547 */
7548 if (xmlStrEqual(name, BAD_CAST "comment"))
7549 *type = NODE_TYPE_COMMENT;
7550 else if (xmlStrEqual(name, BAD_CAST "node"))
7551 *type = NODE_TYPE_NODE;
7552 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7553 *type = NODE_TYPE_PI;
7554 else if (xmlStrEqual(name, BAD_CAST "text"))
7555 *type = NODE_TYPE_TEXT;
7556 else {
7557 if (name != NULL)
7558 xmlFree(name);
7559 XP_ERROR0(XPATH_EXPR_ERROR);
7560 }
7561
7562 *test = NODE_TEST_TYPE;
7563
7564 SKIP_BLANKS;
7565 if (*type == NODE_TYPE_PI) {
7566 /*
7567 * Specific case: search a PI by name.
7568 */
Owen Taylor3473f882001-02-23 17:55:21 +00007569 if (name != NULL)
7570 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007571 name = NULL;
7572 if (CUR != ')') {
7573 name = xmlXPathParseLiteral(ctxt);
7574 CHECK_ERROR 0;
7575 SKIP_BLANKS;
7576 }
Owen Taylor3473f882001-02-23 17:55:21 +00007577 }
7578 if (CUR != ')') {
7579 if (name != NULL)
7580 xmlFree(name);
7581 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7582 }
7583 NEXT;
7584 return(name);
7585 }
7586 *test = NODE_TEST_NAME;
7587 if ((!blanks) && (CUR == ':')) {
7588 NEXT;
7589
7590 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007591 * Since currently the parser context don't have a
7592 * namespace list associated:
7593 * The namespace name for this prefix can be computed
7594 * only at evaluation time. The compilation is done
7595 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007596 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007597#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007598 *prefix = xmlXPathNsLookup(ctxt->context, name);
7599 if (name != NULL)
7600 xmlFree(name);
7601 if (*prefix == NULL) {
7602 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7603 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007604#else
7605 *prefix = name;
7606#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007607
7608 if (CUR == '*') {
7609 /*
7610 * All elements
7611 */
7612 NEXT;
7613 *test = NODE_TEST_ALL;
7614 return(NULL);
7615 }
7616
7617 name = xmlXPathParseNCName(ctxt);
7618 if (name == NULL) {
7619 XP_ERROR0(XPATH_EXPR_ERROR);
7620 }
7621 }
7622 return(name);
7623}
7624
7625/**
7626 * xmlXPathIsAxisName:
7627 * @name: a preparsed name token
7628 *
7629 * [6] AxisName ::= 'ancestor'
7630 * | 'ancestor-or-self'
7631 * | 'attribute'
7632 * | 'child'
7633 * | 'descendant'
7634 * | 'descendant-or-self'
7635 * | 'following'
7636 * | 'following-sibling'
7637 * | 'namespace'
7638 * | 'parent'
7639 * | 'preceding'
7640 * | 'preceding-sibling'
7641 * | 'self'
7642 *
7643 * Returns the axis or 0
7644 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007645static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007646xmlXPathIsAxisName(const xmlChar *name) {
7647 xmlXPathAxisVal ret = 0;
7648 switch (name[0]) {
7649 case 'a':
7650 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7651 ret = AXIS_ANCESTOR;
7652 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7653 ret = AXIS_ANCESTOR_OR_SELF;
7654 if (xmlStrEqual(name, BAD_CAST "attribute"))
7655 ret = AXIS_ATTRIBUTE;
7656 break;
7657 case 'c':
7658 if (xmlStrEqual(name, BAD_CAST "child"))
7659 ret = AXIS_CHILD;
7660 break;
7661 case 'd':
7662 if (xmlStrEqual(name, BAD_CAST "descendant"))
7663 ret = AXIS_DESCENDANT;
7664 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7665 ret = AXIS_DESCENDANT_OR_SELF;
7666 break;
7667 case 'f':
7668 if (xmlStrEqual(name, BAD_CAST "following"))
7669 ret = AXIS_FOLLOWING;
7670 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7671 ret = AXIS_FOLLOWING_SIBLING;
7672 break;
7673 case 'n':
7674 if (xmlStrEqual(name, BAD_CAST "namespace"))
7675 ret = AXIS_NAMESPACE;
7676 break;
7677 case 'p':
7678 if (xmlStrEqual(name, BAD_CAST "parent"))
7679 ret = AXIS_PARENT;
7680 if (xmlStrEqual(name, BAD_CAST "preceding"))
7681 ret = AXIS_PRECEDING;
7682 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7683 ret = AXIS_PRECEDING_SIBLING;
7684 break;
7685 case 's':
7686 if (xmlStrEqual(name, BAD_CAST "self"))
7687 ret = AXIS_SELF;
7688 break;
7689 }
7690 return(ret);
7691}
7692
7693/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007694 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007695 * @ctxt: the XPath Parser context
7696 *
7697 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7698 * | AbbreviatedStep
7699 *
7700 * [12] AbbreviatedStep ::= '.' | '..'
7701 *
7702 * [5] AxisSpecifier ::= AxisName '::'
7703 * | AbbreviatedAxisSpecifier
7704 *
7705 * [13] AbbreviatedAxisSpecifier ::= '@'?
7706 *
7707 * Modified for XPtr range support as:
7708 *
7709 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7710 * | AbbreviatedStep
7711 * | 'range-to' '(' Expr ')' Predicate*
7712 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007713 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007714 * A location step of . is short for self::node(). This is
7715 * particularly useful in conjunction with //. For example, the
7716 * location path .//para is short for
7717 * self::node()/descendant-or-self::node()/child::para
7718 * and so will select all para descendant elements of the context
7719 * node.
7720 * Similarly, a location step of .. is short for parent::node().
7721 * For example, ../title is short for parent::node()/child::title
7722 * and so will select the title children of the parent of the context
7723 * node.
7724 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007725static void
7726xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007727#ifdef LIBXML_XPTR_ENABLED
7728 int rangeto = 0;
7729 int op2 = -1;
7730#endif
7731
Owen Taylor3473f882001-02-23 17:55:21 +00007732 SKIP_BLANKS;
7733 if ((CUR == '.') && (NXT(1) == '.')) {
7734 SKIP(2);
7735 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007736 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7737 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007738 } else if (CUR == '.') {
7739 NEXT;
7740 SKIP_BLANKS;
7741 } else {
7742 xmlChar *name = NULL;
7743 const xmlChar *prefix = NULL;
7744 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007745 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007746 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007747 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007748
7749 /*
7750 * The modification needed for XPointer change to the production
7751 */
7752#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007753 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007754 name = xmlXPathParseNCName(ctxt);
7755 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007756 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007757 xmlFree(name);
7758 SKIP_BLANKS;
7759 if (CUR != '(') {
7760 XP_ERROR(XPATH_EXPR_ERROR);
7761 }
7762 NEXT;
7763 SKIP_BLANKS;
7764
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007765 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007766 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007767 CHECK_ERROR;
7768
7769 SKIP_BLANKS;
7770 if (CUR != ')') {
7771 XP_ERROR(XPATH_EXPR_ERROR);
7772 }
7773 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007774 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007775 goto eval_predicates;
7776 }
7777 }
7778#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007779 if (CUR == '*') {
7780 axis = AXIS_CHILD;
7781 } else {
7782 if (name == NULL)
7783 name = xmlXPathParseNCName(ctxt);
7784 if (name != NULL) {
7785 axis = xmlXPathIsAxisName(name);
7786 if (axis != 0) {
7787 SKIP_BLANKS;
7788 if ((CUR == ':') && (NXT(1) == ':')) {
7789 SKIP(2);
7790 xmlFree(name);
7791 name = NULL;
7792 } else {
7793 /* an element name can conflict with an axis one :-\ */
7794 axis = AXIS_CHILD;
7795 }
Owen Taylor3473f882001-02-23 17:55:21 +00007796 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007797 axis = AXIS_CHILD;
7798 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007799 } else if (CUR == '@') {
7800 NEXT;
7801 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007802 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007803 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007804 }
Owen Taylor3473f882001-02-23 17:55:21 +00007805 }
7806
7807 CHECK_ERROR;
7808
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007809 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007810 if (test == 0)
7811 return;
7812
7813#ifdef DEBUG_STEP
7814 xmlGenericError(xmlGenericErrorContext,
7815 "Basis : computing new set\n");
7816#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007817
Owen Taylor3473f882001-02-23 17:55:21 +00007818#ifdef DEBUG_STEP
7819 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007820 if (ctxt->value == NULL)
7821 xmlGenericError(xmlGenericErrorContext, "no value\n");
7822 else if (ctxt->value->nodesetval == NULL)
7823 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7824 else
7825 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007826#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007827
7828eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007829 op1 = ctxt->comp->last;
7830 ctxt->comp->last = -1;
7831
Owen Taylor3473f882001-02-23 17:55:21 +00007832 SKIP_BLANKS;
7833 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007834 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007835 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007836
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007837#ifdef LIBXML_XPTR_ENABLED
7838 if (rangeto) {
7839 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7840 } else
7841#endif
7842 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7843 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007844
Owen Taylor3473f882001-02-23 17:55:21 +00007845 }
7846#ifdef DEBUG_STEP
7847 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007848 if (ctxt->value == NULL)
7849 xmlGenericError(xmlGenericErrorContext, "no value\n");
7850 else if (ctxt->value->nodesetval == NULL)
7851 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7852 else
7853 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7854 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007855#endif
7856}
7857
7858/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007859 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007860 * @ctxt: the XPath Parser context
7861 *
7862 * [3] RelativeLocationPath ::= Step
7863 * | RelativeLocationPath '/' Step
7864 * | AbbreviatedRelativeLocationPath
7865 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7866 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007867 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007868 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007869static void
Owen Taylor3473f882001-02-23 17:55:21 +00007870#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007871xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007872#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007873xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007874#endif
7875(xmlXPathParserContextPtr ctxt) {
7876 SKIP_BLANKS;
7877 if ((CUR == '/') && (NXT(1) == '/')) {
7878 SKIP(2);
7879 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007880 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7881 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007882 } else if (CUR == '/') {
7883 NEXT;
7884 SKIP_BLANKS;
7885 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007886 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007887 SKIP_BLANKS;
7888 while (CUR == '/') {
7889 if ((CUR == '/') && (NXT(1) == '/')) {
7890 SKIP(2);
7891 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007892 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007893 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007894 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007895 } else if (CUR == '/') {
7896 NEXT;
7897 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007898 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007899 }
7900 SKIP_BLANKS;
7901 }
7902}
7903
7904/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007905 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007906 * @ctxt: the XPath Parser context
7907 *
7908 * [1] LocationPath ::= RelativeLocationPath
7909 * | AbsoluteLocationPath
7910 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7911 * | AbbreviatedAbsoluteLocationPath
7912 * [10] AbbreviatedAbsoluteLocationPath ::=
7913 * '//' RelativeLocationPath
7914 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007915 * Compile a location path
7916 *
Owen Taylor3473f882001-02-23 17:55:21 +00007917 * // is short for /descendant-or-self::node()/. For example,
7918 * //para is short for /descendant-or-self::node()/child::para and
7919 * so will select any para element in the document (even a para element
7920 * that is a document element will be selected by //para since the
7921 * document element node is a child of the root node); div//para is
7922 * short for div/descendant-or-self::node()/child::para and so will
7923 * select all para descendants of div children.
7924 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007925static void
7926xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007927 SKIP_BLANKS;
7928 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007929 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007930 } else {
7931 while (CUR == '/') {
7932 if ((CUR == '/') && (NXT(1) == '/')) {
7933 SKIP(2);
7934 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007935 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7936 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007937 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007938 } else if (CUR == '/') {
7939 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007940 SKIP_BLANKS;
7941 if ((CUR != 0 ) &&
7942 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7943 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007944 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007945 }
7946 }
7947 }
7948}
7949
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007950/************************************************************************
7951 * *
7952 * XPath precompiled expression evaluation *
7953 * *
7954 ************************************************************************/
7955
Daniel Veillardf06307e2001-07-03 10:35:50 +00007956static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007957xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7958
7959/**
7960 * xmlXPathNodeCollectAndTest:
7961 * @ctxt: the XPath Parser context
7962 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007963 * @first: pointer to the first element in document order
7964 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007965 *
7966 * This is the function implementing a step: based on the current list
7967 * of nodes, it builds up a new list, looking at all nodes under that
7968 * axis and selecting them it also do the predicate filtering
7969 *
7970 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007971 *
7972 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007973 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007974static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007975xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007976 xmlXPathStepOpPtr op,
7977 xmlNodePtr * first, xmlNodePtr * last)
7978{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007979 xmlXPathAxisVal axis = op->value;
7980 xmlXPathTestVal test = op->value2;
7981 xmlXPathTypeVal type = op->value3;
7982 const xmlChar *prefix = op->value4;
7983 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007984 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007985
7986#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007987 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007988#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007989 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007990 xmlNodeSetPtr ret, list;
7991 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007992 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007993 xmlNodePtr cur = NULL;
7994 xmlXPathObjectPtr obj;
7995 xmlNodeSetPtr nodelist;
7996 xmlNodePtr tmp;
7997
Daniel Veillardf06307e2001-07-03 10:35:50 +00007998 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007999 obj = valuePop(ctxt);
8000 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008001 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008002 URI = xmlXPathNsLookup(ctxt->context, prefix);
8003 if (URI == NULL)
8004 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008005 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008006#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008007 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008008#endif
8009 switch (axis) {
8010 case AXIS_ANCESTOR:
8011#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008012 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008013#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008014 first = NULL;
8015 next = xmlXPathNextAncestor;
8016 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008017 case AXIS_ANCESTOR_OR_SELF:
8018#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008019 xmlGenericError(xmlGenericErrorContext,
8020 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008021#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008022 first = NULL;
8023 next = xmlXPathNextAncestorOrSelf;
8024 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008025 case AXIS_ATTRIBUTE:
8026#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008027 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008028#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008029 first = NULL;
8030 last = NULL;
8031 next = xmlXPathNextAttribute;
8032 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008033 case AXIS_CHILD:
8034#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008035 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008036#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008037 last = NULL;
8038 next = xmlXPathNextChild;
8039 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008040 case AXIS_DESCENDANT:
8041#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008042 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008043#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008044 last = NULL;
8045 next = xmlXPathNextDescendant;
8046 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008047 case AXIS_DESCENDANT_OR_SELF:
8048#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008049 xmlGenericError(xmlGenericErrorContext,
8050 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008051#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008052 last = NULL;
8053 next = xmlXPathNextDescendantOrSelf;
8054 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008055 case AXIS_FOLLOWING:
8056#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008057 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008058#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008059 last = NULL;
8060 next = xmlXPathNextFollowing;
8061 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008062 case AXIS_FOLLOWING_SIBLING:
8063#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008064 xmlGenericError(xmlGenericErrorContext,
8065 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008066#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008067 last = NULL;
8068 next = xmlXPathNextFollowingSibling;
8069 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008070 case AXIS_NAMESPACE:
8071#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008072 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008073#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008074 first = NULL;
8075 last = NULL;
8076 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8077 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008078 case AXIS_PARENT:
8079#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008080 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008081#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008082 first = NULL;
8083 next = xmlXPathNextParent;
8084 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008085 case AXIS_PRECEDING:
8086#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008087 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008088#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008089 first = NULL;
8090 next = xmlXPathNextPrecedingInternal;
8091 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008092 case AXIS_PRECEDING_SIBLING:
8093#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008094 xmlGenericError(xmlGenericErrorContext,
8095 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008096#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008097 first = NULL;
8098 next = xmlXPathNextPrecedingSibling;
8099 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008100 case AXIS_SELF:
8101#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008102 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008103#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008104 first = NULL;
8105 last = NULL;
8106 next = xmlXPathNextSelf;
8107 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008108 }
8109 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008110 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008111
8112 nodelist = obj->nodesetval;
8113 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008114 xmlXPathFreeObject(obj);
8115 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8116 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008117 }
8118 addNode = xmlXPathNodeSetAddUnique;
8119 ret = NULL;
8120#ifdef DEBUG_STEP
8121 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008122 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008123 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008124 case NODE_TEST_NONE:
8125 xmlGenericError(xmlGenericErrorContext,
8126 " searching for none !!!\n");
8127 break;
8128 case NODE_TEST_TYPE:
8129 xmlGenericError(xmlGenericErrorContext,
8130 " searching for type %d\n", type);
8131 break;
8132 case NODE_TEST_PI:
8133 xmlGenericError(xmlGenericErrorContext,
8134 " searching for PI !!!\n");
8135 break;
8136 case NODE_TEST_ALL:
8137 xmlGenericError(xmlGenericErrorContext,
8138 " searching for *\n");
8139 break;
8140 case NODE_TEST_NS:
8141 xmlGenericError(xmlGenericErrorContext,
8142 " searching for namespace %s\n",
8143 prefix);
8144 break;
8145 case NODE_TEST_NAME:
8146 xmlGenericError(xmlGenericErrorContext,
8147 " searching for name %s\n", name);
8148 if (prefix != NULL)
8149 xmlGenericError(xmlGenericErrorContext,
8150 " with namespace %s\n", prefix);
8151 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008152 }
8153 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8154#endif
8155 /*
8156 * 2.3 Node Tests
8157 * - For the attribute axis, the principal node type is attribute.
8158 * - For the namespace axis, the principal node type is namespace.
8159 * - For other axes, the principal node type is element.
8160 *
8161 * A node test * is true for any node of the
8162 * principal node type. For example, child::* willi
8163 * select all element children of the context node
8164 */
8165 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008166 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008167 ctxt->context->node = nodelist->nodeTab[i];
8168
Daniel Veillardf06307e2001-07-03 10:35:50 +00008169 cur = NULL;
8170 list = xmlXPathNodeSetCreate(NULL);
8171 do {
8172 cur = next(ctxt, cur);
8173 if (cur == NULL)
8174 break;
8175 if ((first != NULL) && (*first == cur))
8176 break;
8177 if (((t % 256) == 0) &&
8178 (first != NULL) && (*first != NULL) &&
8179 (xmlXPathCmpNodes(*first, cur) >= 0))
8180 break;
8181 if ((last != NULL) && (*last == cur))
8182 break;
8183 if (((t % 256) == 0) &&
8184 (last != NULL) && (*last != NULL) &&
8185 (xmlXPathCmpNodes(cur, *last) >= 0))
8186 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008187 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008188#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008189 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8190#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008191 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008192 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008193 ctxt->context->node = tmp;
8194 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008195 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008196 if ((cur->type == type) ||
8197 ((type == NODE_TYPE_NODE) &&
8198 ((cur->type == XML_DOCUMENT_NODE) ||
8199 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8200 (cur->type == XML_ELEMENT_NODE) ||
8201 (cur->type == XML_PI_NODE) ||
8202 (cur->type == XML_COMMENT_NODE) ||
8203 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008204 (cur->type == XML_TEXT_NODE))) ||
8205 ((type == NODE_TYPE_TEXT) &&
8206 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008207#ifdef DEBUG_STEP
8208 n++;
8209#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008210 addNode(list, cur);
8211 }
8212 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008213 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008214 if (cur->type == XML_PI_NODE) {
8215 if ((name != NULL) &&
8216 (!xmlStrEqual(name, cur->name)))
8217 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008218#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008219 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008220#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008221 addNode(list, cur);
8222 }
8223 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008224 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008225 if (axis == AXIS_ATTRIBUTE) {
8226 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008227#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008228 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008229#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008230 addNode(list, cur);
8231 }
8232 } else if (axis == AXIS_NAMESPACE) {
8233 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008234#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008235 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008236#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008237 addNode(list, cur);
8238 }
8239 } else {
8240 if (cur->type == XML_ELEMENT_NODE) {
8241 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008242#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008243 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008244#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008245 addNode(list, cur);
8246 } else if ((cur->ns != NULL) &&
8247 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008248#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008249 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008250#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008251 addNode(list, cur);
8252 }
8253 }
8254 }
8255 break;
8256 case NODE_TEST_NS:{
8257 TODO;
8258 break;
8259 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008260 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008261 switch (cur->type) {
8262 case XML_ELEMENT_NODE:
8263 if (xmlStrEqual(name, cur->name)) {
8264 if (prefix == NULL) {
8265 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008266#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008267 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008268#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008269 addNode(list, cur);
8270 }
8271 } else {
8272 if ((cur->ns != NULL) &&
8273 (xmlStrEqual(URI,
8274 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008275#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008276 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008277#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008278 addNode(list, cur);
8279 }
8280 }
8281 }
8282 break;
8283 case XML_ATTRIBUTE_NODE:{
8284 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008285
Daniel Veillardf06307e2001-07-03 10:35:50 +00008286 if (xmlStrEqual(name, attr->name)) {
8287 if (prefix == NULL) {
8288 if ((attr->ns == NULL) ||
8289 (attr->ns->prefix == NULL)) {
8290#ifdef DEBUG_STEP
8291 n++;
8292#endif
8293 addNode(list,
8294 (xmlNodePtr) attr);
8295 }
8296 } else {
8297 if ((attr->ns != NULL) &&
8298 (xmlStrEqual(URI,
8299 attr->ns->
8300 href))) {
8301#ifdef DEBUG_STEP
8302 n++;
8303#endif
8304 addNode(list,
8305 (xmlNodePtr) attr);
8306 }
8307 }
8308 }
8309 break;
8310 }
8311 case XML_NAMESPACE_DECL:
8312 if (cur->type == XML_NAMESPACE_DECL) {
8313 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008314
Daniel Veillardf06307e2001-07-03 10:35:50 +00008315 if ((ns->prefix != NULL) && (name != NULL)
8316 && (xmlStrEqual(ns->prefix, name))) {
8317#ifdef DEBUG_STEP
8318 n++;
8319#endif
8320 addNode(list, cur);
8321 }
8322 }
8323 break;
8324 default:
8325 break;
8326 }
8327 break;
8328 break;
8329 }
8330 } while (cur != NULL);
8331
8332 /*
8333 * If there is some predicate filtering do it now
8334 */
8335 if (op->ch2 != -1) {
8336 xmlXPathObjectPtr obj2;
8337
8338 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8339 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8340 CHECK_TYPE0(XPATH_NODESET);
8341 obj2 = valuePop(ctxt);
8342 list = obj2->nodesetval;
8343 obj2->nodesetval = NULL;
8344 xmlXPathFreeObject(obj2);
8345 }
8346 if (ret == NULL) {
8347 ret = list;
8348 } else {
8349 ret = xmlXPathNodeSetMerge(ret, list);
8350 xmlXPathFreeNodeSet(list);
8351 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008352 }
8353 ctxt->context->node = tmp;
8354#ifdef DEBUG_STEP
8355 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008356 "\nExamined %d nodes, found %d nodes at that step\n",
8357 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008358#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008359 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008360 if ((obj->boolval) && (obj->user != NULL)) {
8361 ctxt->value->boolval = 1;
8362 ctxt->value->user = obj->user;
8363 obj->user = NULL;
8364 obj->boolval = 0;
8365 }
8366 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008367 return(t);
8368}
8369
8370/**
8371 * xmlXPathNodeCollectAndTestNth:
8372 * @ctxt: the XPath Parser context
8373 * @op: the XPath precompiled step operation
8374 * @indx: the index to collect
8375 * @first: pointer to the first element in document order
8376 * @last: pointer to the last element in document order
8377 *
8378 * This is the function implementing a step: based on the current list
8379 * of nodes, it builds up a new list, looking at all nodes under that
8380 * axis and selecting them it also do the predicate filtering
8381 *
8382 * Pushes the new NodeSet resulting from the search.
8383 * Returns the number of node traversed
8384 */
8385static int
8386xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8387 xmlXPathStepOpPtr op, int indx,
8388 xmlNodePtr * first, xmlNodePtr * last)
8389{
8390 xmlXPathAxisVal axis = op->value;
8391 xmlXPathTestVal test = op->value2;
8392 xmlXPathTypeVal type = op->value3;
8393 const xmlChar *prefix = op->value4;
8394 const xmlChar *name = op->value5;
8395 const xmlChar *URI = NULL;
8396 int n = 0, t = 0;
8397
8398 int i;
8399 xmlNodeSetPtr list;
8400 xmlXPathTraversalFunction next = NULL;
8401 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8402 xmlNodePtr cur = NULL;
8403 xmlXPathObjectPtr obj;
8404 xmlNodeSetPtr nodelist;
8405 xmlNodePtr tmp;
8406
8407 CHECK_TYPE0(XPATH_NODESET);
8408 obj = valuePop(ctxt);
8409 addNode = xmlXPathNodeSetAdd;
8410 if (prefix != NULL) {
8411 URI = xmlXPathNsLookup(ctxt->context, prefix);
8412 if (URI == NULL)
8413 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8414 }
8415#ifdef DEBUG_STEP_NTH
8416 xmlGenericError(xmlGenericErrorContext, "new step : ");
8417 if (first != NULL) {
8418 if (*first != NULL)
8419 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8420 (*first)->name);
8421 else
8422 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8423 }
8424 if (last != NULL) {
8425 if (*last != NULL)
8426 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8427 (*last)->name);
8428 else
8429 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8430 }
8431#endif
8432 switch (axis) {
8433 case AXIS_ANCESTOR:
8434#ifdef DEBUG_STEP_NTH
8435 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8436#endif
8437 first = NULL;
8438 next = xmlXPathNextAncestor;
8439 break;
8440 case AXIS_ANCESTOR_OR_SELF:
8441#ifdef DEBUG_STEP_NTH
8442 xmlGenericError(xmlGenericErrorContext,
8443 "axis 'ancestors-or-self' ");
8444#endif
8445 first = NULL;
8446 next = xmlXPathNextAncestorOrSelf;
8447 break;
8448 case AXIS_ATTRIBUTE:
8449#ifdef DEBUG_STEP_NTH
8450 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8451#endif
8452 first = NULL;
8453 last = NULL;
8454 next = xmlXPathNextAttribute;
8455 break;
8456 case AXIS_CHILD:
8457#ifdef DEBUG_STEP_NTH
8458 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8459#endif
8460 last = NULL;
8461 next = xmlXPathNextChild;
8462 break;
8463 case AXIS_DESCENDANT:
8464#ifdef DEBUG_STEP_NTH
8465 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8466#endif
8467 last = NULL;
8468 next = xmlXPathNextDescendant;
8469 break;
8470 case AXIS_DESCENDANT_OR_SELF:
8471#ifdef DEBUG_STEP_NTH
8472 xmlGenericError(xmlGenericErrorContext,
8473 "axis 'descendant-or-self' ");
8474#endif
8475 last = NULL;
8476 next = xmlXPathNextDescendantOrSelf;
8477 break;
8478 case AXIS_FOLLOWING:
8479#ifdef DEBUG_STEP_NTH
8480 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8481#endif
8482 last = NULL;
8483 next = xmlXPathNextFollowing;
8484 break;
8485 case AXIS_FOLLOWING_SIBLING:
8486#ifdef DEBUG_STEP_NTH
8487 xmlGenericError(xmlGenericErrorContext,
8488 "axis 'following-siblings' ");
8489#endif
8490 last = NULL;
8491 next = xmlXPathNextFollowingSibling;
8492 break;
8493 case AXIS_NAMESPACE:
8494#ifdef DEBUG_STEP_NTH
8495 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8496#endif
8497 last = NULL;
8498 first = NULL;
8499 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8500 break;
8501 case AXIS_PARENT:
8502#ifdef DEBUG_STEP_NTH
8503 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8504#endif
8505 first = NULL;
8506 next = xmlXPathNextParent;
8507 break;
8508 case AXIS_PRECEDING:
8509#ifdef DEBUG_STEP_NTH
8510 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8511#endif
8512 first = NULL;
8513 next = xmlXPathNextPrecedingInternal;
8514 break;
8515 case AXIS_PRECEDING_SIBLING:
8516#ifdef DEBUG_STEP_NTH
8517 xmlGenericError(xmlGenericErrorContext,
8518 "axis 'preceding-sibling' ");
8519#endif
8520 first = NULL;
8521 next = xmlXPathNextPrecedingSibling;
8522 break;
8523 case AXIS_SELF:
8524#ifdef DEBUG_STEP_NTH
8525 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8526#endif
8527 first = NULL;
8528 last = NULL;
8529 next = xmlXPathNextSelf;
8530 break;
8531 }
8532 if (next == NULL)
8533 return(0);
8534
8535 nodelist = obj->nodesetval;
8536 if (nodelist == NULL) {
8537 xmlXPathFreeObject(obj);
8538 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8539 return(0);
8540 }
8541 addNode = xmlXPathNodeSetAddUnique;
8542#ifdef DEBUG_STEP_NTH
8543 xmlGenericError(xmlGenericErrorContext,
8544 " context contains %d nodes\n", nodelist->nodeNr);
8545 switch (test) {
8546 case NODE_TEST_NONE:
8547 xmlGenericError(xmlGenericErrorContext,
8548 " searching for none !!!\n");
8549 break;
8550 case NODE_TEST_TYPE:
8551 xmlGenericError(xmlGenericErrorContext,
8552 " searching for type %d\n", type);
8553 break;
8554 case NODE_TEST_PI:
8555 xmlGenericError(xmlGenericErrorContext,
8556 " searching for PI !!!\n");
8557 break;
8558 case NODE_TEST_ALL:
8559 xmlGenericError(xmlGenericErrorContext,
8560 " searching for *\n");
8561 break;
8562 case NODE_TEST_NS:
8563 xmlGenericError(xmlGenericErrorContext,
8564 " searching for namespace %s\n",
8565 prefix);
8566 break;
8567 case NODE_TEST_NAME:
8568 xmlGenericError(xmlGenericErrorContext,
8569 " searching for name %s\n", name);
8570 if (prefix != NULL)
8571 xmlGenericError(xmlGenericErrorContext,
8572 " with namespace %s\n", prefix);
8573 break;
8574 }
8575 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8576#endif
8577 /*
8578 * 2.3 Node Tests
8579 * - For the attribute axis, the principal node type is attribute.
8580 * - For the namespace axis, the principal node type is namespace.
8581 * - For other axes, the principal node type is element.
8582 *
8583 * A node test * is true for any node of the
8584 * principal node type. For example, child::* willi
8585 * select all element children of the context node
8586 */
8587 tmp = ctxt->context->node;
8588 list = xmlXPathNodeSetCreate(NULL);
8589 for (i = 0; i < nodelist->nodeNr; i++) {
8590 ctxt->context->node = nodelist->nodeTab[i];
8591
8592 cur = NULL;
8593 n = 0;
8594 do {
8595 cur = next(ctxt, cur);
8596 if (cur == NULL)
8597 break;
8598 if ((first != NULL) && (*first == cur))
8599 break;
8600 if (((t % 256) == 0) &&
8601 (first != NULL) && (*first != NULL) &&
8602 (xmlXPathCmpNodes(*first, cur) >= 0))
8603 break;
8604 if ((last != NULL) && (*last == cur))
8605 break;
8606 if (((t % 256) == 0) &&
8607 (last != NULL) && (*last != NULL) &&
8608 (xmlXPathCmpNodes(cur, *last) >= 0))
8609 break;
8610 t++;
8611 switch (test) {
8612 case NODE_TEST_NONE:
8613 ctxt->context->node = tmp;
8614 STRANGE return(0);
8615 case NODE_TEST_TYPE:
8616 if ((cur->type == type) ||
8617 ((type == NODE_TYPE_NODE) &&
8618 ((cur->type == XML_DOCUMENT_NODE) ||
8619 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8620 (cur->type == XML_ELEMENT_NODE) ||
8621 (cur->type == XML_PI_NODE) ||
8622 (cur->type == XML_COMMENT_NODE) ||
8623 (cur->type == XML_CDATA_SECTION_NODE) ||
8624 (cur->type == XML_TEXT_NODE)))) {
8625 n++;
8626 if (n == indx)
8627 addNode(list, cur);
8628 }
8629 break;
8630 case NODE_TEST_PI:
8631 if (cur->type == XML_PI_NODE) {
8632 if ((name != NULL) &&
8633 (!xmlStrEqual(name, cur->name)))
8634 break;
8635 n++;
8636 if (n == indx)
8637 addNode(list, cur);
8638 }
8639 break;
8640 case NODE_TEST_ALL:
8641 if (axis == AXIS_ATTRIBUTE) {
8642 if (cur->type == XML_ATTRIBUTE_NODE) {
8643 n++;
8644 if (n == indx)
8645 addNode(list, cur);
8646 }
8647 } else if (axis == AXIS_NAMESPACE) {
8648 if (cur->type == XML_NAMESPACE_DECL) {
8649 n++;
8650 if (n == indx)
8651 addNode(list, cur);
8652 }
8653 } else {
8654 if (cur->type == XML_ELEMENT_NODE) {
8655 if (prefix == NULL) {
8656 n++;
8657 if (n == indx)
8658 addNode(list, cur);
8659 } else if ((cur->ns != NULL) &&
8660 (xmlStrEqual(URI, cur->ns->href))) {
8661 n++;
8662 if (n == indx)
8663 addNode(list, cur);
8664 }
8665 }
8666 }
8667 break;
8668 case NODE_TEST_NS:{
8669 TODO;
8670 break;
8671 }
8672 case NODE_TEST_NAME:
8673 switch (cur->type) {
8674 case XML_ELEMENT_NODE:
8675 if (xmlStrEqual(name, cur->name)) {
8676 if (prefix == NULL) {
8677 if (cur->ns == NULL) {
8678 n++;
8679 if (n == indx)
8680 addNode(list, cur);
8681 }
8682 } else {
8683 if ((cur->ns != NULL) &&
8684 (xmlStrEqual(URI,
8685 cur->ns->href))) {
8686 n++;
8687 if (n == indx)
8688 addNode(list, cur);
8689 }
8690 }
8691 }
8692 break;
8693 case XML_ATTRIBUTE_NODE:{
8694 xmlAttrPtr attr = (xmlAttrPtr) cur;
8695
8696 if (xmlStrEqual(name, attr->name)) {
8697 if (prefix == NULL) {
8698 if ((attr->ns == NULL) ||
8699 (attr->ns->prefix == NULL)) {
8700 n++;
8701 if (n == indx)
8702 addNode(list, cur);
8703 }
8704 } else {
8705 if ((attr->ns != NULL) &&
8706 (xmlStrEqual(URI,
8707 attr->ns->
8708 href))) {
8709 n++;
8710 if (n == indx)
8711 addNode(list, cur);
8712 }
8713 }
8714 }
8715 break;
8716 }
8717 case XML_NAMESPACE_DECL:
8718 if (cur->type == XML_NAMESPACE_DECL) {
8719 xmlNsPtr ns = (xmlNsPtr) cur;
8720
8721 if ((ns->prefix != NULL) && (name != NULL)
8722 && (xmlStrEqual(ns->prefix, name))) {
8723 n++;
8724 if (n == indx)
8725 addNode(list, cur);
8726 }
8727 }
8728 break;
8729 default:
8730 break;
8731 }
8732 break;
8733 break;
8734 }
8735 } while (n < indx);
8736 }
8737 ctxt->context->node = tmp;
8738#ifdef DEBUG_STEP_NTH
8739 xmlGenericError(xmlGenericErrorContext,
8740 "\nExamined %d nodes, found %d nodes at that step\n",
8741 t, list->nodeNr);
8742#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008743 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008744 if ((obj->boolval) && (obj->user != NULL)) {
8745 ctxt->value->boolval = 1;
8746 ctxt->value->user = obj->user;
8747 obj->user = NULL;
8748 obj->boolval = 0;
8749 }
8750 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008751 return(t);
8752}
8753
8754/**
8755 * xmlXPathCompOpEvalFirst:
8756 * @ctxt: the XPath parser context with the compiled expression
8757 * @op: an XPath compiled operation
8758 * @first: the first elem found so far
8759 *
8760 * Evaluate the Precompiled XPath operation searching only the first
8761 * element in document order
8762 *
8763 * Returns the number of examined objects.
8764 */
8765static int
8766xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8767 xmlXPathStepOpPtr op, xmlNodePtr * first)
8768{
8769 int total = 0, cur;
8770 xmlXPathCompExprPtr comp;
8771 xmlXPathObjectPtr arg1, arg2;
8772
Daniel Veillard556c6682001-10-06 09:59:51 +00008773 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008774 comp = ctxt->comp;
8775 switch (op->op) {
8776 case XPATH_OP_END:
8777 return (0);
8778 case XPATH_OP_UNION:
8779 total =
8780 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8781 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008782 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008783 if ((ctxt->value != NULL)
8784 && (ctxt->value->type == XPATH_NODESET)
8785 && (ctxt->value->nodesetval != NULL)
8786 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8787 /*
8788 * limit tree traversing to first node in the result
8789 */
8790 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8791 *first = ctxt->value->nodesetval->nodeTab[0];
8792 }
8793 cur =
8794 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8795 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008796 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008797 CHECK_TYPE0(XPATH_NODESET);
8798 arg2 = valuePop(ctxt);
8799
8800 CHECK_TYPE0(XPATH_NODESET);
8801 arg1 = valuePop(ctxt);
8802
8803 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8804 arg2->nodesetval);
8805 valuePush(ctxt, arg1);
8806 xmlXPathFreeObject(arg2);
8807 /* optimizer */
8808 if (total > cur)
8809 xmlXPathCompSwap(op);
8810 return (total + cur);
8811 case XPATH_OP_ROOT:
8812 xmlXPathRoot(ctxt);
8813 return (0);
8814 case XPATH_OP_NODE:
8815 if (op->ch1 != -1)
8816 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008817 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008818 if (op->ch2 != -1)
8819 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008820 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008821 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8822 return (total);
8823 case XPATH_OP_RESET:
8824 if (op->ch1 != -1)
8825 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008826 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008827 if (op->ch2 != -1)
8828 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008829 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008830 ctxt->context->node = NULL;
8831 return (total);
8832 case XPATH_OP_COLLECT:{
8833 if (op->ch1 == -1)
8834 return (total);
8835
8836 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008837 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008838
8839 /*
8840 * Optimization for [n] selection where n is a number
8841 */
8842 if ((op->ch2 != -1) &&
8843 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8844 (comp->steps[op->ch2].ch1 == -1) &&
8845 (comp->steps[op->ch2].ch2 != -1) &&
8846 (comp->steps[comp->steps[op->ch2].ch2].op ==
8847 XPATH_OP_VALUE)) {
8848 xmlXPathObjectPtr val;
8849
8850 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8851 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8852 int indx = (int) val->floatval;
8853
8854 if (val->floatval == (float) indx) {
8855 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8856 first, NULL);
8857 return (total);
8858 }
8859 }
8860 }
8861 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8862 return (total);
8863 }
8864 case XPATH_OP_VALUE:
8865 valuePush(ctxt,
8866 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8867 return (0);
8868 case XPATH_OP_SORT:
8869 if (op->ch1 != -1)
8870 total +=
8871 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8872 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008873 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008874 if ((ctxt->value != NULL)
8875 && (ctxt->value->type == XPATH_NODESET)
8876 && (ctxt->value->nodesetval != NULL))
8877 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8878 return (total);
8879 default:
8880 return (xmlXPathCompOpEval(ctxt, op));
8881 }
8882}
8883
8884/**
8885 * xmlXPathCompOpEvalLast:
8886 * @ctxt: the XPath parser context with the compiled expression
8887 * @op: an XPath compiled operation
8888 * @last: the last elem found so far
8889 *
8890 * Evaluate the Precompiled XPath operation searching only the last
8891 * element in document order
8892 *
8893 * Returns the number of node traversed
8894 */
8895static int
8896xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8897 xmlNodePtr * last)
8898{
8899 int total = 0, cur;
8900 xmlXPathCompExprPtr comp;
8901 xmlXPathObjectPtr arg1, arg2;
8902
Daniel Veillard556c6682001-10-06 09:59:51 +00008903 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008904 comp = ctxt->comp;
8905 switch (op->op) {
8906 case XPATH_OP_END:
8907 return (0);
8908 case XPATH_OP_UNION:
8909 total =
8910 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008911 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 if ((ctxt->value != NULL)
8913 && (ctxt->value->type == XPATH_NODESET)
8914 && (ctxt->value->nodesetval != NULL)
8915 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8916 /*
8917 * limit tree traversing to first node in the result
8918 */
8919 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8920 *last =
8921 ctxt->value->nodesetval->nodeTab[ctxt->value->
8922 nodesetval->nodeNr -
8923 1];
8924 }
8925 cur =
8926 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008927 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008928 if ((ctxt->value != NULL)
8929 && (ctxt->value->type == XPATH_NODESET)
8930 && (ctxt->value->nodesetval != NULL)
8931 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8932 }
8933 CHECK_TYPE0(XPATH_NODESET);
8934 arg2 = valuePop(ctxt);
8935
8936 CHECK_TYPE0(XPATH_NODESET);
8937 arg1 = valuePop(ctxt);
8938
8939 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8940 arg2->nodesetval);
8941 valuePush(ctxt, arg1);
8942 xmlXPathFreeObject(arg2);
8943 /* optimizer */
8944 if (total > cur)
8945 xmlXPathCompSwap(op);
8946 return (total + cur);
8947 case XPATH_OP_ROOT:
8948 xmlXPathRoot(ctxt);
8949 return (0);
8950 case XPATH_OP_NODE:
8951 if (op->ch1 != -1)
8952 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008953 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008954 if (op->ch2 != -1)
8955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008956 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008957 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8958 return (total);
8959 case XPATH_OP_RESET:
8960 if (op->ch1 != -1)
8961 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008962 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008963 if (op->ch2 != -1)
8964 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008965 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008966 ctxt->context->node = NULL;
8967 return (total);
8968 case XPATH_OP_COLLECT:{
8969 if (op->ch1 == -1)
8970 return (0);
8971
8972 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008973 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974
8975 /*
8976 * Optimization for [n] selection where n is a number
8977 */
8978 if ((op->ch2 != -1) &&
8979 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8980 (comp->steps[op->ch2].ch1 == -1) &&
8981 (comp->steps[op->ch2].ch2 != -1) &&
8982 (comp->steps[comp->steps[op->ch2].ch2].op ==
8983 XPATH_OP_VALUE)) {
8984 xmlXPathObjectPtr val;
8985
8986 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8987 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8988 int indx = (int) val->floatval;
8989
8990 if (val->floatval == (float) indx) {
8991 total +=
8992 xmlXPathNodeCollectAndTestNth(ctxt, op,
8993 indx, NULL,
8994 last);
8995 return (total);
8996 }
8997 }
8998 }
8999 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9000 return (total);
9001 }
9002 case XPATH_OP_VALUE:
9003 valuePush(ctxt,
9004 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9005 return (0);
9006 case XPATH_OP_SORT:
9007 if (op->ch1 != -1)
9008 total +=
9009 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9010 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009011 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009012 if ((ctxt->value != NULL)
9013 && (ctxt->value->type == XPATH_NODESET)
9014 && (ctxt->value->nodesetval != NULL))
9015 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9016 return (total);
9017 default:
9018 return (xmlXPathCompOpEval(ctxt, op));
9019 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009020}
9021
Owen Taylor3473f882001-02-23 17:55:21 +00009022/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009023 * xmlXPathCompOpEval:
9024 * @ctxt: the XPath parser context with the compiled expression
9025 * @op: an XPath compiled operation
9026 *
9027 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009029 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009030static int
9031xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9032{
9033 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009034 int equal, ret;
9035 xmlXPathCompExprPtr comp;
9036 xmlXPathObjectPtr arg1, arg2;
9037
Daniel Veillard556c6682001-10-06 09:59:51 +00009038 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009039 comp = ctxt->comp;
9040 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009041 case XPATH_OP_END:
9042 return (0);
9043 case XPATH_OP_AND:
9044 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009045 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009046 xmlXPathBooleanFunction(ctxt, 1);
9047 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9048 return (total);
9049 arg2 = valuePop(ctxt);
9050 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009051 if (ctxt->error) {
9052 xmlXPathFreeObject(arg2);
9053 return(0);
9054 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009055 xmlXPathBooleanFunction(ctxt, 1);
9056 arg1 = valuePop(ctxt);
9057 arg1->boolval &= arg2->boolval;
9058 valuePush(ctxt, arg1);
9059 xmlXPathFreeObject(arg2);
9060 return (total);
9061 case XPATH_OP_OR:
9062 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009063 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 xmlXPathBooleanFunction(ctxt, 1);
9065 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9066 return (total);
9067 arg2 = valuePop(ctxt);
9068 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009069 if (ctxt->error) {
9070 xmlXPathFreeObject(arg2);
9071 return(0);
9072 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009073 xmlXPathBooleanFunction(ctxt, 1);
9074 arg1 = valuePop(ctxt);
9075 arg1->boolval |= arg2->boolval;
9076 valuePush(ctxt, arg1);
9077 xmlXPathFreeObject(arg2);
9078 return (total);
9079 case XPATH_OP_EQUAL:
9080 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009081 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009082 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009083 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 equal = xmlXPathEqualValues(ctxt);
9085 if (op->value)
9086 valuePush(ctxt, xmlXPathNewBoolean(equal));
9087 else
9088 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9089 return (total);
9090 case XPATH_OP_CMP:
9091 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009092 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009093 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009094 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009095 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9096 valuePush(ctxt, xmlXPathNewBoolean(ret));
9097 return (total);
9098 case XPATH_OP_PLUS:
9099 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009100 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 if (op->ch2 != -1)
9102 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009103 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009104 if (op->value == 0)
9105 xmlXPathSubValues(ctxt);
9106 else if (op->value == 1)
9107 xmlXPathAddValues(ctxt);
9108 else if (op->value == 2)
9109 xmlXPathValueFlipSign(ctxt);
9110 else if (op->value == 3) {
9111 CAST_TO_NUMBER;
9112 CHECK_TYPE0(XPATH_NUMBER);
9113 }
9114 return (total);
9115 case XPATH_OP_MULT:
9116 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009117 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009118 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009119 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120 if (op->value == 0)
9121 xmlXPathMultValues(ctxt);
9122 else if (op->value == 1)
9123 xmlXPathDivValues(ctxt);
9124 else if (op->value == 2)
9125 xmlXPathModValues(ctxt);
9126 return (total);
9127 case XPATH_OP_UNION:
9128 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009129 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009130 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009131 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 CHECK_TYPE0(XPATH_NODESET);
9133 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009134
Daniel Veillardf06307e2001-07-03 10:35:50 +00009135 CHECK_TYPE0(XPATH_NODESET);
9136 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009137
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9139 arg2->nodesetval);
9140 valuePush(ctxt, arg1);
9141 xmlXPathFreeObject(arg2);
9142 return (total);
9143 case XPATH_OP_ROOT:
9144 xmlXPathRoot(ctxt);
9145 return (total);
9146 case XPATH_OP_NODE:
9147 if (op->ch1 != -1)
9148 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009149 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009150 if (op->ch2 != -1)
9151 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009152 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009153 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9154 return (total);
9155 case XPATH_OP_RESET:
9156 if (op->ch1 != -1)
9157 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009158 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009159 if (op->ch2 != -1)
9160 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009161 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009162 ctxt->context->node = NULL;
9163 return (total);
9164 case XPATH_OP_COLLECT:{
9165 if (op->ch1 == -1)
9166 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009167
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009169 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009170
Daniel Veillardf06307e2001-07-03 10:35:50 +00009171 /*
9172 * Optimization for [n] selection where n is a number
9173 */
9174 if ((op->ch2 != -1) &&
9175 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9176 (comp->steps[op->ch2].ch1 == -1) &&
9177 (comp->steps[op->ch2].ch2 != -1) &&
9178 (comp->steps[comp->steps[op->ch2].ch2].op ==
9179 XPATH_OP_VALUE)) {
9180 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009181
Daniel Veillardf06307e2001-07-03 10:35:50 +00009182 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9183 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9184 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009185
Daniel Veillardf06307e2001-07-03 10:35:50 +00009186 if (val->floatval == (float) indx) {
9187 total +=
9188 xmlXPathNodeCollectAndTestNth(ctxt, op,
9189 indx, NULL,
9190 NULL);
9191 return (total);
9192 }
9193 }
9194 }
9195 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9196 return (total);
9197 }
9198 case XPATH_OP_VALUE:
9199 valuePush(ctxt,
9200 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9201 return (total);
9202 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009203 xmlXPathObjectPtr val;
9204
Daniel Veillardf06307e2001-07-03 10:35:50 +00009205 if (op->ch1 != -1)
9206 total +=
9207 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009208 if (op->value5 == NULL) {
9209 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9210 if (val == NULL) {
9211 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9212 return(0);
9213 }
9214 valuePush(ctxt, val);
9215 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009216 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009217
Daniel Veillardf06307e2001-07-03 10:35:50 +00009218 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9219 if (URI == NULL) {
9220 xmlGenericError(xmlGenericErrorContext,
9221 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
9222 op->value4, op->value5);
9223 return (total);
9224 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009225 val = xmlXPathVariableLookupNS(ctxt->context,
9226 op->value4, URI);
9227 if (val == NULL) {
9228 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9229 return(0);
9230 }
9231 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009232 }
9233 return (total);
9234 }
9235 case XPATH_OP_FUNCTION:{
9236 xmlXPathFunction func;
9237 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009238 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009239
9240 if (op->ch1 != -1)
9241 total +=
9242 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009243 if (ctxt->valueNr < op->value) {
9244 xmlGenericError(xmlGenericErrorContext,
9245 "xmlXPathRunEval: parameter error\n");
9246 ctxt->error = XPATH_INVALID_OPERAND;
9247 return (total);
9248 }
9249 for (i = 0; i < op->value; i++)
9250 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9251 xmlGenericError(xmlGenericErrorContext,
9252 "xmlXPathRunEval: parameter error\n");
9253 ctxt->error = XPATH_INVALID_OPERAND;
9254 return (total);
9255 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009256 if (op->cache != NULL)
9257 func = (xmlXPathFunction) op->cache;
9258 else {
9259 const xmlChar *URI = NULL;
9260
9261 if (op->value5 == NULL)
9262 func =
9263 xmlXPathFunctionLookup(ctxt->context,
9264 op->value4);
9265 else {
9266 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9267 if (URI == NULL) {
9268 xmlGenericError(xmlGenericErrorContext,
9269 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
9270 op->value4, op->value5);
9271 return (total);
9272 }
9273 func = xmlXPathFunctionLookupNS(ctxt->context,
9274 op->value4, URI);
9275 }
9276 if (func == NULL) {
9277 xmlGenericError(xmlGenericErrorContext,
9278 "xmlXPathRunEval: function %s not found\n",
9279 op->value4);
9280 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
9281 return (total);
9282 }
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 */