blob: 8bbe15cb85edb4c900800b071252c12147ddc12a [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);
2424 if (ret != NULL) return(ret);
2425 }
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;
2758 ret->user = xmlCopyNode(val->nodesetval->nodeTab[0], 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002759 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002760 (xmlNodePtr) ret->user);
2761 } else
Owen Taylor3473f882001-02-23 17:55:21 +00002762 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002763 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00002764 break;
2765 case XPATH_NODESET:
2766 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002767 /* Do not deallocate the copied tree value */
2768 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002769 break;
2770 case XPATH_LOCATIONSET:
2771#ifdef LIBXML_XPTR_ENABLED
2772 {
2773 xmlLocationSetPtr loc = val->user;
2774 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2775 break;
2776 }
2777#endif
2778 case XPATH_UNDEFINED:
2779 case XPATH_USERS:
2780 xmlGenericError(xmlGenericErrorContext,
2781 "xmlXPathObjectCopy: unsupported type %d\n",
2782 val->type);
2783 break;
2784 }
2785 return(ret);
2786}
2787
2788/**
2789 * xmlXPathFreeObject:
2790 * @obj: the object to free
2791 *
2792 * Free up an xmlXPathObjectPtr object.
2793 */
2794void
2795xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2796 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002797 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00002798 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002799 if (obj->user != NULL) {
2800 xmlFreeNodeList((xmlNodePtr) obj->user);
2801 xmlXPathFreeNodeSet(obj->nodesetval);
2802 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00002803 xmlXPathFreeValueTree(obj->nodesetval);
2804 } else {
2805 if (obj->nodesetval != NULL)
2806 xmlXPathFreeNodeSet(obj->nodesetval);
2807 }
Owen Taylor3473f882001-02-23 17:55:21 +00002808#ifdef LIBXML_XPTR_ENABLED
2809 } else if (obj->type == XPATH_LOCATIONSET) {
2810 if (obj->user != NULL)
2811 xmlXPtrFreeLocationSet(obj->user);
2812#endif
2813 } else if (obj->type == XPATH_STRING) {
2814 if (obj->stringval != NULL)
2815 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00002816 }
2817
Owen Taylor3473f882001-02-23 17:55:21 +00002818 xmlFree(obj);
2819}
2820
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002821
2822/************************************************************************
2823 * *
2824 * Type Casting Routines *
2825 * *
2826 ************************************************************************/
2827
2828/**
2829 * xmlXPathCastBooleanToString:
2830 * @val: a boolean
2831 *
2832 * Converts a boolean to its string value.
2833 *
2834 * Returns a newly allocated string.
2835 */
2836xmlChar *
2837xmlXPathCastBooleanToString (int val) {
2838 xmlChar *ret;
2839 if (val)
2840 ret = xmlStrdup((const xmlChar *) "true");
2841 else
2842 ret = xmlStrdup((const xmlChar *) "false");
2843 return(ret);
2844}
2845
2846/**
2847 * xmlXPathCastNumberToString:
2848 * @val: a number
2849 *
2850 * Converts a number to its string value.
2851 *
2852 * Returns a newly allocated string.
2853 */
2854xmlChar *
2855xmlXPathCastNumberToString (double val) {
2856 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00002857 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002858 case 1:
2859 ret = xmlStrdup((const xmlChar *) "+Infinity");
2860 break;
2861 case -1:
2862 ret = xmlStrdup((const xmlChar *) "-Infinity");
2863 break;
2864 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002865 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002866 ret = xmlStrdup((const xmlChar *) "NaN");
2867 } else {
2868 /* could be improved */
2869 char buf[100];
2870 xmlXPathFormatNumber(val, buf, 100);
2871 ret = xmlStrdup((const xmlChar *) buf);
2872 }
2873 }
2874 return(ret);
2875}
2876
2877/**
2878 * xmlXPathCastNodeToString:
2879 * @node: a node
2880 *
2881 * Converts a node to its string value.
2882 *
2883 * Returns a newly allocated string.
2884 */
2885xmlChar *
2886xmlXPathCastNodeToString (xmlNodePtr node) {
2887 return(xmlNodeGetContent(node));
2888}
2889
2890/**
2891 * xmlXPathCastNodeSetToString:
2892 * @ns: a node-set
2893 *
2894 * Converts a node-set to its string value.
2895 *
2896 * Returns a newly allocated string.
2897 */
2898xmlChar *
2899xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2900 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2901 return(xmlStrdup((const xmlChar *) ""));
2902
2903 xmlXPathNodeSetSort(ns);
2904 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2905}
2906
2907/**
2908 * xmlXPathCastToString:
2909 * @val: an XPath object
2910 *
2911 * Converts an existing object to its string() equivalent
2912 *
2913 * Returns the string value of the object, NULL in case of error.
2914 * A new string is allocated only if needed (val isn't a
2915 * string object).
2916 */
2917xmlChar *
2918xmlXPathCastToString(xmlXPathObjectPtr val) {
2919 xmlChar *ret = NULL;
2920
2921 if (val == NULL)
2922 return(xmlStrdup((const xmlChar *) ""));
2923 switch (val->type) {
2924 case XPATH_UNDEFINED:
2925#ifdef DEBUG_EXPR
2926 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2927#endif
2928 ret = xmlStrdup((const xmlChar *) "");
2929 break;
2930 case XPATH_XSLT_TREE:
2931 case XPATH_NODESET:
2932 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2933 break;
2934 case XPATH_STRING:
2935 return(val->stringval);
2936 case XPATH_BOOLEAN:
2937 ret = xmlXPathCastBooleanToString(val->boolval);
2938 break;
2939 case XPATH_NUMBER: {
2940 ret = xmlXPathCastNumberToString(val->floatval);
2941 break;
2942 }
2943 case XPATH_USERS:
2944 case XPATH_POINT:
2945 case XPATH_RANGE:
2946 case XPATH_LOCATIONSET:
2947 TODO
2948 ret = xmlStrdup((const xmlChar *) "");
2949 break;
2950 }
2951 return(ret);
2952}
2953
2954/**
2955 * xmlXPathConvertString:
2956 * @val: an XPath object
2957 *
2958 * Converts an existing object to its string() equivalent
2959 *
2960 * Returns the new object, the old one is freed (or the operation
2961 * is done directly on @val)
2962 */
2963xmlXPathObjectPtr
2964xmlXPathConvertString(xmlXPathObjectPtr val) {
2965 xmlChar *res = NULL;
2966
2967 if (val == NULL)
2968 return(xmlXPathNewCString(""));
2969
2970 switch (val->type) {
2971 case XPATH_UNDEFINED:
2972#ifdef DEBUG_EXPR
2973 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2974#endif
2975 break;
2976 case XPATH_XSLT_TREE:
2977 case XPATH_NODESET:
2978 res = xmlXPathCastNodeSetToString(val->nodesetval);
2979 break;
2980 case XPATH_STRING:
2981 return(val);
2982 case XPATH_BOOLEAN:
2983 res = xmlXPathCastBooleanToString(val->boolval);
2984 break;
2985 case XPATH_NUMBER:
2986 res = xmlXPathCastNumberToString(val->floatval);
2987 break;
2988 case XPATH_USERS:
2989 case XPATH_POINT:
2990 case XPATH_RANGE:
2991 case XPATH_LOCATIONSET:
2992 TODO;
2993 break;
2994 }
2995 xmlXPathFreeObject(val);
2996 if (res == NULL)
2997 return(xmlXPathNewCString(""));
2998 return(xmlXPathWrapString(res));
2999}
3000
3001/**
3002 * xmlXPathCastBooleanToNumber:
3003 * @val: a boolean
3004 *
3005 * Converts a boolean to its number value
3006 *
3007 * Returns the number value
3008 */
3009double
3010xmlXPathCastBooleanToNumber(int val) {
3011 if (val)
3012 return(1.0);
3013 return(0.0);
3014}
3015
3016/**
3017 * xmlXPathCastStringToNumber:
3018 * @val: a string
3019 *
3020 * Converts a string to its number value
3021 *
3022 * Returns the number value
3023 */
3024double
3025xmlXPathCastStringToNumber(const xmlChar * val) {
3026 return(xmlXPathStringEvalNumber(val));
3027}
3028
3029/**
3030 * xmlXPathCastNodeToNumber:
3031 * @node: a node
3032 *
3033 * Converts a node to its number value
3034 *
3035 * Returns the number value
3036 */
3037double
3038xmlXPathCastNodeToNumber (xmlNodePtr node) {
3039 xmlChar *strval;
3040 double ret;
3041
3042 if (node == NULL)
3043 return(xmlXPathNAN);
3044 strval = xmlXPathCastNodeToString(node);
3045 if (strval == NULL)
3046 return(xmlXPathNAN);
3047 ret = xmlXPathCastStringToNumber(strval);
3048 xmlFree(strval);
3049
3050 return(ret);
3051}
3052
3053/**
3054 * xmlXPathCastNodeSetToNumber:
3055 * @ns: a node-set
3056 *
3057 * Converts a node-set to its number value
3058 *
3059 * Returns the number value
3060 */
3061double
3062xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3063 xmlChar *str;
3064 double ret;
3065
3066 if (ns == NULL)
3067 return(xmlXPathNAN);
3068 str = xmlXPathCastNodeSetToString(ns);
3069 ret = xmlXPathCastStringToNumber(str);
3070 xmlFree(str);
3071 return(ret);
3072}
3073
3074/**
3075 * xmlXPathCastToNumber:
3076 * @val: an XPath object
3077 *
3078 * Converts an XPath object to its number value
3079 *
3080 * Returns the number value
3081 */
3082double
3083xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3084 double ret = 0.0;
3085
3086 if (val == NULL)
3087 return(xmlXPathNAN);
3088 switch (val->type) {
3089 case XPATH_UNDEFINED:
3090#ifdef DEGUB_EXPR
3091 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3092#endif
3093 ret = xmlXPathNAN;
3094 break;
3095 case XPATH_XSLT_TREE:
3096 case XPATH_NODESET:
3097 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3098 break;
3099 case XPATH_STRING:
3100 ret = xmlXPathCastStringToNumber(val->stringval);
3101 break;
3102 case XPATH_NUMBER:
3103 ret = val->floatval;
3104 break;
3105 case XPATH_BOOLEAN:
3106 ret = xmlXPathCastBooleanToNumber(val->boolval);
3107 break;
3108 case XPATH_USERS:
3109 case XPATH_POINT:
3110 case XPATH_RANGE:
3111 case XPATH_LOCATIONSET:
3112 TODO;
3113 ret = xmlXPathNAN;
3114 break;
3115 }
3116 return(ret);
3117}
3118
3119/**
3120 * xmlXPathConvertNumber:
3121 * @val: an XPath object
3122 *
3123 * Converts an existing object to its number() equivalent
3124 *
3125 * Returns the new object, the old one is freed (or the operation
3126 * is done directly on @val)
3127 */
3128xmlXPathObjectPtr
3129xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3130 xmlXPathObjectPtr ret;
3131
3132 if (val == NULL)
3133 return(xmlXPathNewFloat(0.0));
3134 if (val->type == XPATH_NUMBER)
3135 return(val);
3136 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3137 xmlXPathFreeObject(val);
3138 return(ret);
3139}
3140
3141/**
3142 * xmlXPathCastNumberToBoolean:
3143 * @val: a number
3144 *
3145 * Converts a number to its boolean value
3146 *
3147 * Returns the boolean value
3148 */
3149int
3150xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003151 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003152 return(0);
3153 return(1);
3154}
3155
3156/**
3157 * xmlXPathCastStringToBoolean:
3158 * @val: a string
3159 *
3160 * Converts a string to its boolean value
3161 *
3162 * Returns the boolean value
3163 */
3164int
3165xmlXPathCastStringToBoolean (const xmlChar *val) {
3166 if ((val == NULL) || (xmlStrlen(val) == 0))
3167 return(0);
3168 return(1);
3169}
3170
3171/**
3172 * xmlXPathCastNodeSetToBoolean:
3173 * @ns: a node-set
3174 *
3175 * Converts a node-set to its boolean value
3176 *
3177 * Returns the boolean value
3178 */
3179int
3180xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3181 if ((ns == NULL) || (ns->nodeNr == 0))
3182 return(0);
3183 return(1);
3184}
3185
3186/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003187 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003188 * @val: an XPath object
3189 *
3190 * Converts an XPath object to its boolean value
3191 *
3192 * Returns the boolean value
3193 */
3194int
3195xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3196 int ret = 0;
3197
3198 if (val == NULL)
3199 return(0);
3200 switch (val->type) {
3201 case XPATH_UNDEFINED:
3202#ifdef DEBUG_EXPR
3203 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3204#endif
3205 ret = 0;
3206 break;
3207 case XPATH_XSLT_TREE:
3208 case XPATH_NODESET:
3209 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3210 break;
3211 case XPATH_STRING:
3212 ret = xmlXPathCastStringToBoolean(val->stringval);
3213 break;
3214 case XPATH_NUMBER:
3215 ret = xmlXPathCastNumberToBoolean(val->floatval);
3216 break;
3217 case XPATH_BOOLEAN:
3218 ret = val->boolval;
3219 break;
3220 case XPATH_USERS:
3221 case XPATH_POINT:
3222 case XPATH_RANGE:
3223 case XPATH_LOCATIONSET:
3224 TODO;
3225 ret = 0;
3226 break;
3227 }
3228 return(ret);
3229}
3230
3231
3232/**
3233 * xmlXPathConvertBoolean:
3234 * @val: an XPath object
3235 *
3236 * Converts an existing object to its boolean() equivalent
3237 *
3238 * Returns the new object, the old one is freed (or the operation
3239 * is done directly on @val)
3240 */
3241xmlXPathObjectPtr
3242xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3243 xmlXPathObjectPtr ret;
3244
3245 if (val == NULL)
3246 return(xmlXPathNewBoolean(0));
3247 if (val->type == XPATH_BOOLEAN)
3248 return(val);
3249 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3250 xmlXPathFreeObject(val);
3251 return(ret);
3252}
3253
Owen Taylor3473f882001-02-23 17:55:21 +00003254/************************************************************************
3255 * *
3256 * Routines to handle XPath contexts *
3257 * *
3258 ************************************************************************/
3259
3260/**
3261 * xmlXPathNewContext:
3262 * @doc: the XML document
3263 *
3264 * Create a new xmlXPathContext
3265 *
3266 * Returns the xmlXPathContext just allocated.
3267 */
3268xmlXPathContextPtr
3269xmlXPathNewContext(xmlDocPtr doc) {
3270 xmlXPathContextPtr ret;
3271
3272 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3273 if (ret == NULL) {
3274 xmlGenericError(xmlGenericErrorContext,
3275 "xmlXPathNewContext: out of memory\n");
3276 return(NULL);
3277 }
3278 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3279 ret->doc = doc;
3280 ret->node = NULL;
3281
3282 ret->varHash = NULL;
3283
3284 ret->nb_types = 0;
3285 ret->max_types = 0;
3286 ret->types = NULL;
3287
3288 ret->funcHash = xmlHashCreate(0);
3289
3290 ret->nb_axis = 0;
3291 ret->max_axis = 0;
3292 ret->axis = NULL;
3293
3294 ret->nsHash = NULL;
3295 ret->user = NULL;
3296
3297 ret->contextSize = -1;
3298 ret->proximityPosition = -1;
3299
3300 xmlXPathRegisterAllFunctions(ret);
3301
3302 return(ret);
3303}
3304
3305/**
3306 * xmlXPathFreeContext:
3307 * @ctxt: the context to free
3308 *
3309 * Free up an xmlXPathContext
3310 */
3311void
3312xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3313 xmlXPathRegisteredNsCleanup(ctxt);
3314 xmlXPathRegisteredFuncsCleanup(ctxt);
3315 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003316 xmlFree(ctxt);
3317}
3318
3319/************************************************************************
3320 * *
3321 * Routines to handle XPath parser contexts *
3322 * *
3323 ************************************************************************/
3324
3325#define CHECK_CTXT(ctxt) \
3326 if (ctxt == NULL) { \
3327 xmlGenericError(xmlGenericErrorContext, \
3328 "%s:%d Internal error: ctxt == NULL\n", \
3329 __FILE__, __LINE__); \
3330 } \
3331
3332
3333#define CHECK_CONTEXT(ctxt) \
3334 if (ctxt == NULL) { \
3335 xmlGenericError(xmlGenericErrorContext, \
3336 "%s:%d Internal error: no context\n", \
3337 __FILE__, __LINE__); \
3338 } \
3339 else if (ctxt->doc == NULL) { \
3340 xmlGenericError(xmlGenericErrorContext, \
3341 "%s:%d Internal error: no document\n", \
3342 __FILE__, __LINE__); \
3343 } \
3344 else if (ctxt->doc->children == NULL) { \
3345 xmlGenericError(xmlGenericErrorContext, \
3346 "%s:%d Internal error: document without root\n", \
3347 __FILE__, __LINE__); \
3348 } \
3349
3350
3351/**
3352 * xmlXPathNewParserContext:
3353 * @str: the XPath expression
3354 * @ctxt: the XPath context
3355 *
3356 * Create a new xmlXPathParserContext
3357 *
3358 * Returns the xmlXPathParserContext just allocated.
3359 */
3360xmlXPathParserContextPtr
3361xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3362 xmlXPathParserContextPtr ret;
3363
3364 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3365 if (ret == NULL) {
3366 xmlGenericError(xmlGenericErrorContext,
3367 "xmlXPathNewParserContext: out of memory\n");
3368 return(NULL);
3369 }
3370 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3371 ret->cur = ret->base = str;
3372 ret->context = ctxt;
3373
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003374 ret->comp = xmlXPathNewCompExpr();
3375 if (ret->comp == NULL) {
3376 xmlFree(ret->valueTab);
3377 xmlFree(ret);
3378 return(NULL);
3379 }
3380
3381 return(ret);
3382}
3383
3384/**
3385 * xmlXPathCompParserContext:
3386 * @comp: the XPath compiled expression
3387 * @ctxt: the XPath context
3388 *
3389 * Create a new xmlXPathParserContext when processing a compiled expression
3390 *
3391 * Returns the xmlXPathParserContext just allocated.
3392 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003393static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003394xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3395 xmlXPathParserContextPtr ret;
3396
3397 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3398 if (ret == NULL) {
3399 xmlGenericError(xmlGenericErrorContext,
3400 "xmlXPathNewParserContext: out of memory\n");
3401 return(NULL);
3402 }
3403 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3404
Owen Taylor3473f882001-02-23 17:55:21 +00003405 /* Allocate the value stack */
3406 ret->valueTab = (xmlXPathObjectPtr *)
3407 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003408 if (ret->valueTab == NULL) {
3409 xmlFree(ret);
3410 xmlGenericError(xmlGenericErrorContext,
3411 "xmlXPathNewParserContext: out of memory\n");
3412 return(NULL);
3413 }
Owen Taylor3473f882001-02-23 17:55:21 +00003414 ret->valueNr = 0;
3415 ret->valueMax = 10;
3416 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003417
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003418 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003419 ret->comp = comp;
3420
Owen Taylor3473f882001-02-23 17:55:21 +00003421 return(ret);
3422}
3423
3424/**
3425 * xmlXPathFreeParserContext:
3426 * @ctxt: the context to free
3427 *
3428 * Free up an xmlXPathParserContext
3429 */
3430void
3431xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3432 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003433 xmlFree(ctxt->valueTab);
3434 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003435 if (ctxt->comp)
3436 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003437 xmlFree(ctxt);
3438}
3439
3440/************************************************************************
3441 * *
3442 * The implicit core function library *
3443 * *
3444 ************************************************************************/
3445
Owen Taylor3473f882001-02-23 17:55:21 +00003446/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003447 * xmlXPathNodeStringHash:
3448 * @node: a node pointer
3449 *
3450 * Function computing the beginning of the string value of the node,
3451 * used to speed up comparisons
3452 *
3453 * Returns an int usable as a hash
3454 */
3455static unsigned int
3456xmlXPathNodeValHash(xmlNodePtr node) {
3457 int len = 2;
3458 const xmlChar * string = NULL;
3459 xmlNodePtr tmp = NULL;
3460 unsigned int ret = 0;
3461
3462 if (node == NULL)
3463 return(0);
3464
3465
3466 switch (node->type) {
3467 case XML_COMMENT_NODE:
3468 case XML_PI_NODE:
3469 case XML_CDATA_SECTION_NODE:
3470 case XML_TEXT_NODE:
3471 string = node->content;
3472 if (string == NULL)
3473 return(0);
3474 if (string[0] == 0)
3475 return(0);
3476 return(((unsigned int) string[0]) +
3477 (((unsigned int) string[1]) << 8));
3478 case XML_NAMESPACE_DECL:
3479 string = ((xmlNsPtr)node)->href;
3480 if (string == NULL)
3481 return(0);
3482 if (string[0] == 0)
3483 return(0);
3484 return(((unsigned int) string[0]) +
3485 (((unsigned int) string[1]) << 8));
3486 case XML_ATTRIBUTE_NODE:
3487 tmp = ((xmlAttrPtr) node)->children;
3488 break;
3489 case XML_ELEMENT_NODE:
3490 tmp = node->children;
3491 break;
3492 default:
3493 return(0);
3494 }
3495 while (tmp != NULL) {
3496 switch (tmp->type) {
3497 case XML_COMMENT_NODE:
3498 case XML_PI_NODE:
3499 case XML_CDATA_SECTION_NODE:
3500 case XML_TEXT_NODE:
3501 string = tmp->content;
3502 break;
3503 case XML_NAMESPACE_DECL:
3504 string = ((xmlNsPtr)tmp)->href;
3505 break;
3506 default:
3507 break;
3508 }
3509 if ((string != NULL) && (string[0] != 0)) {
3510 if (string[0] == 0)
3511 return(0);
3512 if (len == 1) {
3513 return(ret + (((unsigned int) string[0]) << 8));
3514 }
3515 if (string[1] == 0) {
3516 len = 1;
3517 ret = (unsigned int) string[0];
3518 } else {
3519 return(((unsigned int) string[0]) +
3520 (((unsigned int) string[1]) << 8));
3521 }
3522 }
3523 /*
3524 * Skip to next node
3525 */
3526 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3527 if (tmp->children->type != XML_ENTITY_DECL) {
3528 tmp = tmp->children;
3529 continue;
3530 }
3531 }
3532 if (tmp == node)
3533 break;
3534
3535 if (tmp->next != NULL) {
3536 tmp = tmp->next;
3537 continue;
3538 }
3539
3540 do {
3541 tmp = tmp->parent;
3542 if (tmp == NULL)
3543 break;
3544 if (tmp == node) {
3545 tmp = NULL;
3546 break;
3547 }
3548 if (tmp->next != NULL) {
3549 tmp = tmp->next;
3550 break;
3551 }
3552 } while (tmp != NULL);
3553 }
3554 return(ret);
3555}
3556
3557/**
3558 * xmlXPathStringHash:
3559 * @string: a string
3560 *
3561 * Function computing the beginning of the string value of the node,
3562 * used to speed up comparisons
3563 *
3564 * Returns an int usable as a hash
3565 */
3566static unsigned int
3567xmlXPathStringHash(const xmlChar * string) {
3568 if (string == NULL)
3569 return((unsigned int) 0);
3570 if (string[0] == 0)
3571 return(0);
3572 return(((unsigned int) string[0]) +
3573 (((unsigned int) string[1]) << 8));
3574}
3575
3576/**
Owen Taylor3473f882001-02-23 17:55:21 +00003577 * xmlXPathCompareNodeSetFloat:
3578 * @ctxt: the XPath Parser context
3579 * @inf: less than (1) or greater than (0)
3580 * @strict: is the comparison strict
3581 * @arg: the node set
3582 * @f: the value
3583 *
3584 * Implement the compare operation between a nodeset and a number
3585 * @ns < @val (1, 1, ...
3586 * @ns <= @val (1, 0, ...
3587 * @ns > @val (0, 1, ...
3588 * @ns >= @val (0, 0, ...
3589 *
3590 * If one object to be compared is a node-set and the other is a number,
3591 * then the comparison will be true if and only if there is a node in the
3592 * node-set such that the result of performing the comparison on the number
3593 * to be compared and on the result of converting the string-value of that
3594 * node to a number using the number function is true.
3595 *
3596 * Returns 0 or 1 depending on the results of the test.
3597 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003598static int
Owen Taylor3473f882001-02-23 17:55:21 +00003599xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3600 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3601 int i, ret = 0;
3602 xmlNodeSetPtr ns;
3603 xmlChar *str2;
3604
3605 if ((f == NULL) || (arg == NULL) ||
3606 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3607 xmlXPathFreeObject(arg);
3608 xmlXPathFreeObject(f);
3609 return(0);
3610 }
3611 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003612 if (ns != NULL) {
3613 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003614 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003615 if (str2 != NULL) {
3616 valuePush(ctxt,
3617 xmlXPathNewString(str2));
3618 xmlFree(str2);
3619 xmlXPathNumberFunction(ctxt, 1);
3620 valuePush(ctxt, xmlXPathObjectCopy(f));
3621 ret = xmlXPathCompareValues(ctxt, inf, strict);
3622 if (ret)
3623 break;
3624 }
3625 }
Owen Taylor3473f882001-02-23 17:55:21 +00003626 }
3627 xmlXPathFreeObject(arg);
3628 xmlXPathFreeObject(f);
3629 return(ret);
3630}
3631
3632/**
3633 * xmlXPathCompareNodeSetString:
3634 * @ctxt: the XPath Parser context
3635 * @inf: less than (1) or greater than (0)
3636 * @strict: is the comparison strict
3637 * @arg: the node set
3638 * @s: the value
3639 *
3640 * Implement the compare operation between a nodeset and a string
3641 * @ns < @val (1, 1, ...
3642 * @ns <= @val (1, 0, ...
3643 * @ns > @val (0, 1, ...
3644 * @ns >= @val (0, 0, ...
3645 *
3646 * If one object to be compared is a node-set and the other is a string,
3647 * then the comparison will be true if and only if there is a node in
3648 * the node-set such that the result of performing the comparison on the
3649 * string-value of the node and the other string is true.
3650 *
3651 * Returns 0 or 1 depending on the results of the test.
3652 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003653static int
Owen Taylor3473f882001-02-23 17:55:21 +00003654xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3655 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3656 int i, ret = 0;
3657 xmlNodeSetPtr ns;
3658 xmlChar *str2;
3659
3660 if ((s == NULL) || (arg == NULL) ||
3661 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3662 xmlXPathFreeObject(arg);
3663 xmlXPathFreeObject(s);
3664 return(0);
3665 }
3666 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003667 if (ns != NULL) {
3668 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003669 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003670 if (str2 != NULL) {
3671 valuePush(ctxt,
3672 xmlXPathNewString(str2));
3673 xmlFree(str2);
3674 valuePush(ctxt, xmlXPathObjectCopy(s));
3675 ret = xmlXPathCompareValues(ctxt, inf, strict);
3676 if (ret)
3677 break;
3678 }
3679 }
Owen Taylor3473f882001-02-23 17:55:21 +00003680 }
3681 xmlXPathFreeObject(arg);
3682 xmlXPathFreeObject(s);
3683 return(ret);
3684}
3685
3686/**
3687 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003688 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003689 * @strict: is the comparison strict
3690 * @arg1: the fist node set object
3691 * @arg2: the second node set object
3692 *
3693 * Implement the compare operation on nodesets:
3694 *
3695 * If both objects to be compared are node-sets, then the comparison
3696 * will be true if and only if there is a node in the first node-set
3697 * and a node in the second node-set such that the result of performing
3698 * the comparison on the string-values of the two nodes is true.
3699 * ....
3700 * When neither object to be compared is a node-set and the operator
3701 * is <=, <, >= or >, then the objects are compared by converting both
3702 * objects to numbers and comparing the numbers according to IEEE 754.
3703 * ....
3704 * The number function converts its argument to a number as follows:
3705 * - a string that consists of optional whitespace followed by an
3706 * optional minus sign followed by a Number followed by whitespace
3707 * is converted to the IEEE 754 number that is nearest (according
3708 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3709 * represented by the string; any other string is converted to NaN
3710 *
3711 * Conclusion all nodes need to be converted first to their string value
3712 * and then the comparison must be done when possible
3713 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003714static int
3715xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003716 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3717 int i, j, init = 0;
3718 double val1;
3719 double *values2;
3720 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003721 xmlNodeSetPtr ns1;
3722 xmlNodeSetPtr ns2;
3723
3724 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003725 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3726 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003727 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003728 }
Owen Taylor3473f882001-02-23 17:55:21 +00003729 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003730 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3731 xmlXPathFreeObject(arg1);
3732 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003733 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003734 }
Owen Taylor3473f882001-02-23 17:55:21 +00003735
3736 ns1 = arg1->nodesetval;
3737 ns2 = arg2->nodesetval;
3738
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003739 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003740 xmlXPathFreeObject(arg1);
3741 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003742 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003743 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003744 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003745 xmlXPathFreeObject(arg1);
3746 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003747 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003748 }
Owen Taylor3473f882001-02-23 17:55:21 +00003749
3750 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3751 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003752 xmlXPathFreeObject(arg1);
3753 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003754 return(0);
3755 }
3756 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003757 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00003758 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00003759 continue;
3760 for (j = 0;j < ns2->nodeNr;j++) {
3761 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003762 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003763 }
Daniel Veillardcda96922001-08-21 10:56:31 +00003764 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00003765 continue;
3766 if (inf && strict)
3767 ret = (val1 < values2[j]);
3768 else if (inf && !strict)
3769 ret = (val1 <= values2[j]);
3770 else if (!inf && strict)
3771 ret = (val1 > values2[j]);
3772 else if (!inf && !strict)
3773 ret = (val1 >= values2[j]);
3774 if (ret)
3775 break;
3776 }
3777 if (ret)
3778 break;
3779 init = 1;
3780 }
3781 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003782 xmlXPathFreeObject(arg1);
3783 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003784 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003785}
3786
3787/**
3788 * xmlXPathCompareNodeSetValue:
3789 * @ctxt: the XPath Parser context
3790 * @inf: less than (1) or greater than (0)
3791 * @strict: is the comparison strict
3792 * @arg: the node set
3793 * @val: the value
3794 *
3795 * Implement the compare operation between a nodeset and a value
3796 * @ns < @val (1, 1, ...
3797 * @ns <= @val (1, 0, ...
3798 * @ns > @val (0, 1, ...
3799 * @ns >= @val (0, 0, ...
3800 *
3801 * If one object to be compared is a node-set and the other is a boolean,
3802 * then the comparison will be true if and only if the result of performing
3803 * the comparison on the boolean and on the result of converting
3804 * the node-set to a boolean using the boolean function is true.
3805 *
3806 * Returns 0 or 1 depending on the results of the test.
3807 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003808static int
Owen Taylor3473f882001-02-23 17:55:21 +00003809xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3810 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3811 if ((val == NULL) || (arg == NULL) ||
3812 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3813 return(0);
3814
3815 switch(val->type) {
3816 case XPATH_NUMBER:
3817 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3818 case XPATH_NODESET:
3819 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003820 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003821 case XPATH_STRING:
3822 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3823 case XPATH_BOOLEAN:
3824 valuePush(ctxt, arg);
3825 xmlXPathBooleanFunction(ctxt, 1);
3826 valuePush(ctxt, val);
3827 return(xmlXPathCompareValues(ctxt, inf, strict));
3828 default:
3829 TODO
3830 return(0);
3831 }
3832 return(0);
3833}
3834
3835/**
3836 * xmlXPathEqualNodeSetString
3837 * @arg: the nodeset object argument
3838 * @str: the string to compare to.
3839 *
3840 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3841 * If one object to be compared is a node-set and the other is a string,
3842 * then the comparison will be true if and only if there is a node in
3843 * the node-set such that the result of performing the comparison on the
3844 * string-value of the node and the other string is true.
3845 *
3846 * Returns 0 or 1 depending on the results of the test.
3847 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003848static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003849xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3850{
Owen Taylor3473f882001-02-23 17:55:21 +00003851 int i;
3852 xmlNodeSetPtr ns;
3853 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003854 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003855
3856 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003857 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3858 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003859 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003860 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003861 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003862 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003863 if (ns->nodeNr <= 0) {
3864 if (hash == 0)
3865 return(1);
3866 return(0);
3867 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003868 for (i = 0; i < ns->nodeNr; i++) {
3869 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3870 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3871 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3872 xmlFree(str2);
3873 return (1);
3874 }
3875 if (str2 != NULL)
3876 xmlFree(str2);
3877 }
Owen Taylor3473f882001-02-23 17:55:21 +00003878 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003879 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003880}
3881
3882/**
3883 * xmlXPathEqualNodeSetFloat
3884 * @arg: the nodeset object argument
3885 * @f: the float to compare to
3886 *
3887 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3888 * If one object to be compared is a node-set and the other is a number,
3889 * then the comparison will be true if and only if there is a node in
3890 * the node-set such that the result of performing the comparison on the
3891 * number to be compared and on the result of converting the string-value
3892 * of that node to a number using the number function is true.
3893 *
3894 * Returns 0 or 1 depending on the results of the test.
3895 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003896static int
Owen Taylor3473f882001-02-23 17:55:21 +00003897xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3898 char buf[100] = "";
3899
3900 if ((arg == NULL) ||
3901 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3902 return(0);
3903
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003904 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003905 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3906}
3907
3908
3909/**
3910 * xmlXPathEqualNodeSets
3911 * @arg1: first nodeset object argument
3912 * @arg2: second nodeset object argument
3913 *
3914 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3915 * If both objects to be compared are node-sets, then the comparison
3916 * will be true if and only if there is a node in the first node-set and
3917 * a node in the second node-set such that the result of performing the
3918 * comparison on the string-values of the two nodes is true.
3919 *
3920 * (needless to say, this is a costly operation)
3921 *
3922 * Returns 0 or 1 depending on the results of the test.
3923 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003924static int
Owen Taylor3473f882001-02-23 17:55:21 +00003925xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3926 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003927 unsigned int *hashs1;
3928 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003929 xmlChar **values1;
3930 xmlChar **values2;
3931 int ret = 0;
3932 xmlNodeSetPtr ns1;
3933 xmlNodeSetPtr ns2;
3934
3935 if ((arg1 == NULL) ||
3936 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3937 return(0);
3938 if ((arg2 == NULL) ||
3939 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3940 return(0);
3941
3942 ns1 = arg1->nodesetval;
3943 ns2 = arg2->nodesetval;
3944
Daniel Veillard911f49a2001-04-07 15:39:35 +00003945 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003946 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003947 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003948 return(0);
3949
3950 /*
3951 * check if there is a node pertaining to both sets
3952 */
3953 for (i = 0;i < ns1->nodeNr;i++)
3954 for (j = 0;j < ns2->nodeNr;j++)
3955 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3956 return(1);
3957
3958 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3959 if (values1 == NULL)
3960 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003961 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3962 if (hashs1 == NULL) {
3963 xmlFree(values1);
3964 return(0);
3965 }
Owen Taylor3473f882001-02-23 17:55:21 +00003966 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3967 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3968 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003969 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003970 xmlFree(values1);
3971 return(0);
3972 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003973 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3974 if (hashs2 == NULL) {
3975 xmlFree(hashs1);
3976 xmlFree(values1);
3977 xmlFree(values2);
3978 return(0);
3979 }
Owen Taylor3473f882001-02-23 17:55:21 +00003980 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3981 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003982 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003983 for (j = 0;j < ns2->nodeNr;j++) {
3984 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003985 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
3986 if (hashs1[i] == hashs2[j]) {
3987 if (values1[i] == NULL)
3988 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3989 if (values2[j] == NULL)
3990 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3991 ret = xmlStrEqual(values1[i], values2[j]);
3992 if (ret)
3993 break;
3994 }
Owen Taylor3473f882001-02-23 17:55:21 +00003995 }
3996 if (ret)
3997 break;
3998 }
3999 for (i = 0;i < ns1->nodeNr;i++)
4000 if (values1[i] != NULL)
4001 xmlFree(values1[i]);
4002 for (j = 0;j < ns2->nodeNr;j++)
4003 if (values2[j] != NULL)
4004 xmlFree(values2[j]);
4005 xmlFree(values1);
4006 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004007 xmlFree(hashs1);
4008 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004009 return(ret);
4010}
4011
4012/**
4013 * xmlXPathEqualValues:
4014 * @ctxt: the XPath Parser context
4015 *
4016 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4017 *
4018 * Returns 0 or 1 depending on the results of the test.
4019 */
4020int
4021xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4022 xmlXPathObjectPtr arg1, arg2;
4023 int ret = 0;
4024
4025 arg1 = valuePop(ctxt);
4026 if (arg1 == NULL)
4027 XP_ERROR0(XPATH_INVALID_OPERAND);
4028
4029 arg2 = valuePop(ctxt);
4030 if (arg2 == NULL) {
4031 xmlXPathFreeObject(arg1);
4032 XP_ERROR0(XPATH_INVALID_OPERAND);
4033 }
4034
4035 if (arg1 == arg2) {
4036#ifdef DEBUG_EXPR
4037 xmlGenericError(xmlGenericErrorContext,
4038 "Equal: by pointer\n");
4039#endif
4040 return(1);
4041 }
4042
4043 switch (arg1->type) {
4044 case XPATH_UNDEFINED:
4045#ifdef DEBUG_EXPR
4046 xmlGenericError(xmlGenericErrorContext,
4047 "Equal: undefined\n");
4048#endif
4049 break;
4050 case XPATH_XSLT_TREE:
4051 case XPATH_NODESET:
4052 switch (arg2->type) {
4053 case XPATH_UNDEFINED:
4054#ifdef DEBUG_EXPR
4055 xmlGenericError(xmlGenericErrorContext,
4056 "Equal: undefined\n");
4057#endif
4058 break;
4059 case XPATH_XSLT_TREE:
4060 case XPATH_NODESET:
4061 ret = xmlXPathEqualNodeSets(arg1, arg2);
4062 break;
4063 case XPATH_BOOLEAN:
4064 if ((arg1->nodesetval == NULL) ||
4065 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4066 else
4067 ret = 1;
4068 ret = (ret == arg2->boolval);
4069 break;
4070 case XPATH_NUMBER:
4071 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4072 break;
4073 case XPATH_STRING:
4074 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4075 break;
4076 case XPATH_USERS:
4077 case XPATH_POINT:
4078 case XPATH_RANGE:
4079 case XPATH_LOCATIONSET:
4080 TODO
4081 break;
4082 }
4083 break;
4084 case XPATH_BOOLEAN:
4085 switch (arg2->type) {
4086 case XPATH_UNDEFINED:
4087#ifdef DEBUG_EXPR
4088 xmlGenericError(xmlGenericErrorContext,
4089 "Equal: undefined\n");
4090#endif
4091 break;
4092 case XPATH_NODESET:
4093 case XPATH_XSLT_TREE:
4094 if ((arg2->nodesetval == NULL) ||
4095 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4096 else
4097 ret = 1;
4098 break;
4099 case XPATH_BOOLEAN:
4100#ifdef DEBUG_EXPR
4101 xmlGenericError(xmlGenericErrorContext,
4102 "Equal: %d boolean %d \n",
4103 arg1->boolval, arg2->boolval);
4104#endif
4105 ret = (arg1->boolval == arg2->boolval);
4106 break;
4107 case XPATH_NUMBER:
4108 if (arg2->floatval) ret = 1;
4109 else ret = 0;
4110 ret = (arg1->boolval == ret);
4111 break;
4112 case XPATH_STRING:
4113 if ((arg2->stringval == NULL) ||
4114 (arg2->stringval[0] == 0)) ret = 0;
4115 else
4116 ret = 1;
4117 ret = (arg1->boolval == ret);
4118 break;
4119 case XPATH_USERS:
4120 case XPATH_POINT:
4121 case XPATH_RANGE:
4122 case XPATH_LOCATIONSET:
4123 TODO
4124 break;
4125 }
4126 break;
4127 case XPATH_NUMBER:
4128 switch (arg2->type) {
4129 case XPATH_UNDEFINED:
4130#ifdef DEBUG_EXPR
4131 xmlGenericError(xmlGenericErrorContext,
4132 "Equal: undefined\n");
4133#endif
4134 break;
4135 case XPATH_NODESET:
4136 case XPATH_XSLT_TREE:
4137 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4138 break;
4139 case XPATH_BOOLEAN:
4140 if (arg1->floatval) ret = 1;
4141 else ret = 0;
4142 ret = (arg2->boolval == ret);
4143 break;
4144 case XPATH_STRING:
4145 valuePush(ctxt, arg2);
4146 xmlXPathNumberFunction(ctxt, 1);
4147 arg2 = valuePop(ctxt);
4148 /* no break on purpose */
4149 case XPATH_NUMBER:
4150 ret = (arg1->floatval == arg2->floatval);
4151 break;
4152 case XPATH_USERS:
4153 case XPATH_POINT:
4154 case XPATH_RANGE:
4155 case XPATH_LOCATIONSET:
4156 TODO
4157 break;
4158 }
4159 break;
4160 case XPATH_STRING:
4161 switch (arg2->type) {
4162 case XPATH_UNDEFINED:
4163#ifdef DEBUG_EXPR
4164 xmlGenericError(xmlGenericErrorContext,
4165 "Equal: undefined\n");
4166#endif
4167 break;
4168 case XPATH_NODESET:
4169 case XPATH_XSLT_TREE:
4170 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4171 break;
4172 case XPATH_BOOLEAN:
4173 if ((arg1->stringval == NULL) ||
4174 (arg1->stringval[0] == 0)) ret = 0;
4175 else
4176 ret = 1;
4177 ret = (arg2->boolval == ret);
4178 break;
4179 case XPATH_STRING:
4180 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4181 break;
4182 case XPATH_NUMBER:
4183 valuePush(ctxt, arg1);
4184 xmlXPathNumberFunction(ctxt, 1);
4185 arg1 = valuePop(ctxt);
4186 ret = (arg1->floatval == arg2->floatval);
4187 break;
4188 case XPATH_USERS:
4189 case XPATH_POINT:
4190 case XPATH_RANGE:
4191 case XPATH_LOCATIONSET:
4192 TODO
4193 break;
4194 }
4195 break;
4196 case XPATH_USERS:
4197 case XPATH_POINT:
4198 case XPATH_RANGE:
4199 case XPATH_LOCATIONSET:
4200 TODO
4201 break;
4202 }
4203 xmlXPathFreeObject(arg1);
4204 xmlXPathFreeObject(arg2);
4205 return(ret);
4206}
4207
4208
4209/**
4210 * xmlXPathCompareValues:
4211 * @ctxt: the XPath Parser context
4212 * @inf: less than (1) or greater than (0)
4213 * @strict: is the comparison strict
4214 *
4215 * Implement the compare operation on XPath objects:
4216 * @arg1 < @arg2 (1, 1, ...
4217 * @arg1 <= @arg2 (1, 0, ...
4218 * @arg1 > @arg2 (0, 1, ...
4219 * @arg1 >= @arg2 (0, 0, ...
4220 *
4221 * When neither object to be compared is a node-set and the operator is
4222 * <=, <, >=, >, then the objects are compared by converted both objects
4223 * to numbers and comparing the numbers according to IEEE 754. The <
4224 * comparison will be true if and only if the first number is less than the
4225 * second number. The <= comparison will be true if and only if the first
4226 * number is less than or equal to the second number. The > comparison
4227 * will be true if and only if the first number is greater than the second
4228 * number. The >= comparison will be true if and only if the first number
4229 * is greater than or equal to the second number.
4230 *
4231 * Returns 1 if the comparaison succeeded, 0 if it failed
4232 */
4233int
4234xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4235 int ret = 0;
4236 xmlXPathObjectPtr arg1, arg2;
4237
4238 arg2 = valuePop(ctxt);
4239 if (arg2 == NULL) {
4240 XP_ERROR0(XPATH_INVALID_OPERAND);
4241 }
4242
4243 arg1 = valuePop(ctxt);
4244 if (arg1 == NULL) {
4245 xmlXPathFreeObject(arg2);
4246 XP_ERROR0(XPATH_INVALID_OPERAND);
4247 }
4248
4249 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4250 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004251 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004252 } else {
4253 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004254 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4255 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004256 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004257 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4258 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004259 }
4260 }
4261 return(ret);
4262 }
4263
4264 if (arg1->type != XPATH_NUMBER) {
4265 valuePush(ctxt, arg1);
4266 xmlXPathNumberFunction(ctxt, 1);
4267 arg1 = valuePop(ctxt);
4268 }
4269 if (arg1->type != XPATH_NUMBER) {
4270 xmlXPathFreeObject(arg1);
4271 xmlXPathFreeObject(arg2);
4272 XP_ERROR0(XPATH_INVALID_OPERAND);
4273 }
4274 if (arg2->type != XPATH_NUMBER) {
4275 valuePush(ctxt, arg2);
4276 xmlXPathNumberFunction(ctxt, 1);
4277 arg2 = valuePop(ctxt);
4278 }
4279 if (arg2->type != XPATH_NUMBER) {
4280 xmlXPathFreeObject(arg1);
4281 xmlXPathFreeObject(arg2);
4282 XP_ERROR0(XPATH_INVALID_OPERAND);
4283 }
4284 /*
4285 * Add tests for infinity and nan
4286 * => feedback on 3.4 for Inf and NaN
4287 */
4288 if (inf && strict)
4289 ret = (arg1->floatval < arg2->floatval);
4290 else if (inf && !strict)
4291 ret = (arg1->floatval <= arg2->floatval);
4292 else if (!inf && strict)
4293 ret = (arg1->floatval > arg2->floatval);
4294 else if (!inf && !strict)
4295 ret = (arg1->floatval >= arg2->floatval);
4296 xmlXPathFreeObject(arg1);
4297 xmlXPathFreeObject(arg2);
4298 return(ret);
4299}
4300
4301/**
4302 * xmlXPathValueFlipSign:
4303 * @ctxt: the XPath Parser context
4304 *
4305 * Implement the unary - operation on an XPath object
4306 * The numeric operators convert their operands to numbers as if
4307 * by calling the number function.
4308 */
4309void
4310xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004311 CAST_TO_NUMBER;
4312 CHECK_TYPE(XPATH_NUMBER);
4313 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004314}
4315
4316/**
4317 * xmlXPathAddValues:
4318 * @ctxt: the XPath Parser context
4319 *
4320 * Implement the add operation on XPath objects:
4321 * The numeric operators convert their operands to numbers as if
4322 * by calling the number function.
4323 */
4324void
4325xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4326 xmlXPathObjectPtr arg;
4327 double val;
4328
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004329 arg = valuePop(ctxt);
4330 if (arg == NULL)
4331 XP_ERROR(XPATH_INVALID_OPERAND);
4332 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004333 xmlXPathFreeObject(arg);
4334
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004335 CAST_TO_NUMBER;
4336 CHECK_TYPE(XPATH_NUMBER);
4337 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004338}
4339
4340/**
4341 * xmlXPathSubValues:
4342 * @ctxt: the XPath Parser context
4343 *
4344 * Implement the substraction operation on XPath objects:
4345 * The numeric operators convert their operands to numbers as if
4346 * by calling the number function.
4347 */
4348void
4349xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4350 xmlXPathObjectPtr arg;
4351 double val;
4352
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004353 arg = valuePop(ctxt);
4354 if (arg == NULL)
4355 XP_ERROR(XPATH_INVALID_OPERAND);
4356 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004357 xmlXPathFreeObject(arg);
4358
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004359 CAST_TO_NUMBER;
4360 CHECK_TYPE(XPATH_NUMBER);
4361 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004362}
4363
4364/**
4365 * xmlXPathMultValues:
4366 * @ctxt: the XPath Parser context
4367 *
4368 * Implement the multiply operation on XPath objects:
4369 * The numeric operators convert their operands to numbers as if
4370 * by calling the number function.
4371 */
4372void
4373xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4374 xmlXPathObjectPtr arg;
4375 double val;
4376
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004377 arg = valuePop(ctxt);
4378 if (arg == NULL)
4379 XP_ERROR(XPATH_INVALID_OPERAND);
4380 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004381 xmlXPathFreeObject(arg);
4382
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004383 CAST_TO_NUMBER;
4384 CHECK_TYPE(XPATH_NUMBER);
4385 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004386}
4387
4388/**
4389 * xmlXPathDivValues:
4390 * @ctxt: the XPath Parser context
4391 *
4392 * Implement the div operation on XPath objects @arg1 / @arg2:
4393 * The numeric operators convert their operands to numbers as if
4394 * by calling the number function.
4395 */
4396void
4397xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4398 xmlXPathObjectPtr arg;
4399 double val;
4400
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004401 arg = valuePop(ctxt);
4402 if (arg == NULL)
4403 XP_ERROR(XPATH_INVALID_OPERAND);
4404 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004405 xmlXPathFreeObject(arg);
4406
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004407 CAST_TO_NUMBER;
4408 CHECK_TYPE(XPATH_NUMBER);
4409 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004410}
4411
4412/**
4413 * xmlXPathModValues:
4414 * @ctxt: the XPath Parser context
4415 *
4416 * Implement the mod operation on XPath objects: @arg1 / @arg2
4417 * The numeric operators convert their operands to numbers as if
4418 * by calling the number function.
4419 */
4420void
4421xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4422 xmlXPathObjectPtr arg;
4423 int arg1, arg2;
4424
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004425 arg = valuePop(ctxt);
4426 if (arg == NULL)
4427 XP_ERROR(XPATH_INVALID_OPERAND);
4428 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004429 xmlXPathFreeObject(arg);
4430
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004431 CAST_TO_NUMBER;
4432 CHECK_TYPE(XPATH_NUMBER);
4433 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004434 if (arg2 == 0)
4435 ctxt->value->floatval = xmlXPathNAN;
4436 else
4437 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004438}
4439
4440/************************************************************************
4441 * *
4442 * The traversal functions *
4443 * *
4444 ************************************************************************/
4445
Owen Taylor3473f882001-02-23 17:55:21 +00004446/*
4447 * A traversal function enumerates nodes along an axis.
4448 * Initially it must be called with NULL, and it indicates
4449 * termination on the axis by returning NULL.
4450 */
4451typedef xmlNodePtr (*xmlXPathTraversalFunction)
4452 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4453
4454/**
4455 * xmlXPathNextSelf:
4456 * @ctxt: the XPath Parser context
4457 * @cur: the current node in the traversal
4458 *
4459 * Traversal function for the "self" direction
4460 * The self axis contains just the context node itself
4461 *
4462 * Returns the next element following that axis
4463 */
4464xmlNodePtr
4465xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4466 if (cur == NULL)
4467 return(ctxt->context->node);
4468 return(NULL);
4469}
4470
4471/**
4472 * xmlXPathNextChild:
4473 * @ctxt: the XPath Parser context
4474 * @cur: the current node in the traversal
4475 *
4476 * Traversal function for the "child" direction
4477 * The child axis contains the children of the context node in document order.
4478 *
4479 * Returns the next element following that axis
4480 */
4481xmlNodePtr
4482xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4483 if (cur == NULL) {
4484 if (ctxt->context->node == NULL) return(NULL);
4485 switch (ctxt->context->node->type) {
4486 case XML_ELEMENT_NODE:
4487 case XML_TEXT_NODE:
4488 case XML_CDATA_SECTION_NODE:
4489 case XML_ENTITY_REF_NODE:
4490 case XML_ENTITY_NODE:
4491 case XML_PI_NODE:
4492 case XML_COMMENT_NODE:
4493 case XML_NOTATION_NODE:
4494 case XML_DTD_NODE:
4495 return(ctxt->context->node->children);
4496 case XML_DOCUMENT_NODE:
4497 case XML_DOCUMENT_TYPE_NODE:
4498 case XML_DOCUMENT_FRAG_NODE:
4499 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004500#ifdef LIBXML_DOCB_ENABLED
4501 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004502#endif
4503 return(((xmlDocPtr) ctxt->context->node)->children);
4504 case XML_ELEMENT_DECL:
4505 case XML_ATTRIBUTE_DECL:
4506 case XML_ENTITY_DECL:
4507 case XML_ATTRIBUTE_NODE:
4508 case XML_NAMESPACE_DECL:
4509 case XML_XINCLUDE_START:
4510 case XML_XINCLUDE_END:
4511 return(NULL);
4512 }
4513 return(NULL);
4514 }
4515 if ((cur->type == XML_DOCUMENT_NODE) ||
4516 (cur->type == XML_HTML_DOCUMENT_NODE))
4517 return(NULL);
4518 return(cur->next);
4519}
4520
4521/**
4522 * xmlXPathNextDescendant:
4523 * @ctxt: the XPath Parser context
4524 * @cur: the current node in the traversal
4525 *
4526 * Traversal function for the "descendant" direction
4527 * the descendant axis contains the descendants of the context node in document
4528 * order; a descendant is a child or a child of a child and so on.
4529 *
4530 * Returns the next element following that axis
4531 */
4532xmlNodePtr
4533xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4534 if (cur == NULL) {
4535 if (ctxt->context->node == NULL)
4536 return(NULL);
4537 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4538 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4539 return(NULL);
4540
4541 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4542 return(ctxt->context->doc->children);
4543 return(ctxt->context->node->children);
4544 }
4545
Daniel Veillard567e1b42001-08-01 15:53:47 +00004546 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004547 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004548 return(cur->children);
4549 }
4550
4551 if (cur == ctxt->context->node) return(NULL);
4552
Owen Taylor3473f882001-02-23 17:55:21 +00004553 if (cur->next != NULL) return(cur->next);
4554
4555 do {
4556 cur = cur->parent;
4557 if (cur == NULL) return(NULL);
4558 if (cur == ctxt->context->node) return(NULL);
4559 if (cur->next != NULL) {
4560 cur = cur->next;
4561 return(cur);
4562 }
4563 } while (cur != NULL);
4564 return(cur);
4565}
4566
4567/**
4568 * xmlXPathNextDescendantOrSelf:
4569 * @ctxt: the XPath Parser context
4570 * @cur: the current node in the traversal
4571 *
4572 * Traversal function for the "descendant-or-self" direction
4573 * the descendant-or-self axis contains the context node and the descendants
4574 * of the context node in document order; thus the context node is the first
4575 * node on the axis, and the first child of the context node is the second node
4576 * on the axis
4577 *
4578 * Returns the next element following that axis
4579 */
4580xmlNodePtr
4581xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4582 if (cur == NULL) {
4583 if (ctxt->context->node == NULL)
4584 return(NULL);
4585 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4586 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4587 return(NULL);
4588 return(ctxt->context->node);
4589 }
4590
4591 return(xmlXPathNextDescendant(ctxt, cur));
4592}
4593
4594/**
4595 * xmlXPathNextParent:
4596 * @ctxt: the XPath Parser context
4597 * @cur: the current node in the traversal
4598 *
4599 * Traversal function for the "parent" direction
4600 * The parent axis contains the parent of the context node, if there is one.
4601 *
4602 * Returns the next element following that axis
4603 */
4604xmlNodePtr
4605xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4606 /*
4607 * the parent of an attribute or namespace node is the element
4608 * to which the attribute or namespace node is attached
4609 * Namespace handling !!!
4610 */
4611 if (cur == NULL) {
4612 if (ctxt->context->node == NULL) return(NULL);
4613 switch (ctxt->context->node->type) {
4614 case XML_ELEMENT_NODE:
4615 case XML_TEXT_NODE:
4616 case XML_CDATA_SECTION_NODE:
4617 case XML_ENTITY_REF_NODE:
4618 case XML_ENTITY_NODE:
4619 case XML_PI_NODE:
4620 case XML_COMMENT_NODE:
4621 case XML_NOTATION_NODE:
4622 case XML_DTD_NODE:
4623 case XML_ELEMENT_DECL:
4624 case XML_ATTRIBUTE_DECL:
4625 case XML_XINCLUDE_START:
4626 case XML_XINCLUDE_END:
4627 case XML_ENTITY_DECL:
4628 if (ctxt->context->node->parent == NULL)
4629 return((xmlNodePtr) ctxt->context->doc);
4630 return(ctxt->context->node->parent);
4631 case XML_ATTRIBUTE_NODE: {
4632 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4633
4634 return(att->parent);
4635 }
4636 case XML_DOCUMENT_NODE:
4637 case XML_DOCUMENT_TYPE_NODE:
4638 case XML_DOCUMENT_FRAG_NODE:
4639 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004640#ifdef LIBXML_DOCB_ENABLED
4641 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004642#endif
4643 return(NULL);
4644 case XML_NAMESPACE_DECL:
4645 /*
4646 * TODO !!! may require extending struct _xmlNs with
4647 * parent field
4648 * C.f. Infoset case...
4649 */
4650 return(NULL);
4651 }
4652 }
4653 return(NULL);
4654}
4655
4656/**
4657 * xmlXPathNextAncestor:
4658 * @ctxt: the XPath Parser context
4659 * @cur: the current node in the traversal
4660 *
4661 * Traversal function for the "ancestor" direction
4662 * the ancestor axis contains the ancestors of the context node; the ancestors
4663 * of the context node consist of the parent of context node and the parent's
4664 * parent and so on; the nodes are ordered in reverse document order; thus the
4665 * parent is the first node on the axis, and the parent's parent is the second
4666 * node on the axis
4667 *
4668 * Returns the next element following that axis
4669 */
4670xmlNodePtr
4671xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4672 /*
4673 * the parent of an attribute or namespace node is the element
4674 * to which the attribute or namespace node is attached
4675 * !!!!!!!!!!!!!
4676 */
4677 if (cur == NULL) {
4678 if (ctxt->context->node == NULL) return(NULL);
4679 switch (ctxt->context->node->type) {
4680 case XML_ELEMENT_NODE:
4681 case XML_TEXT_NODE:
4682 case XML_CDATA_SECTION_NODE:
4683 case XML_ENTITY_REF_NODE:
4684 case XML_ENTITY_NODE:
4685 case XML_PI_NODE:
4686 case XML_COMMENT_NODE:
4687 case XML_DTD_NODE:
4688 case XML_ELEMENT_DECL:
4689 case XML_ATTRIBUTE_DECL:
4690 case XML_ENTITY_DECL:
4691 case XML_NOTATION_NODE:
4692 case XML_XINCLUDE_START:
4693 case XML_XINCLUDE_END:
4694 if (ctxt->context->node->parent == NULL)
4695 return((xmlNodePtr) ctxt->context->doc);
4696 return(ctxt->context->node->parent);
4697 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004698 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004699
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004700 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004701 }
4702 case XML_DOCUMENT_NODE:
4703 case XML_DOCUMENT_TYPE_NODE:
4704 case XML_DOCUMENT_FRAG_NODE:
4705 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004706#ifdef LIBXML_DOCB_ENABLED
4707 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004708#endif
4709 return(NULL);
4710 case XML_NAMESPACE_DECL:
4711 /*
4712 * TODO !!! may require extending struct _xmlNs with
4713 * parent field
4714 * C.f. Infoset case...
4715 */
4716 return(NULL);
4717 }
4718 return(NULL);
4719 }
4720 if (cur == ctxt->context->doc->children)
4721 return((xmlNodePtr) ctxt->context->doc);
4722 if (cur == (xmlNodePtr) ctxt->context->doc)
4723 return(NULL);
4724 switch (cur->type) {
4725 case XML_ELEMENT_NODE:
4726 case XML_TEXT_NODE:
4727 case XML_CDATA_SECTION_NODE:
4728 case XML_ENTITY_REF_NODE:
4729 case XML_ENTITY_NODE:
4730 case XML_PI_NODE:
4731 case XML_COMMENT_NODE:
4732 case XML_NOTATION_NODE:
4733 case XML_DTD_NODE:
4734 case XML_ELEMENT_DECL:
4735 case XML_ATTRIBUTE_DECL:
4736 case XML_ENTITY_DECL:
4737 case XML_XINCLUDE_START:
4738 case XML_XINCLUDE_END:
4739 return(cur->parent);
4740 case XML_ATTRIBUTE_NODE: {
4741 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4742
4743 return(att->parent);
4744 }
4745 case XML_DOCUMENT_NODE:
4746 case XML_DOCUMENT_TYPE_NODE:
4747 case XML_DOCUMENT_FRAG_NODE:
4748 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004749#ifdef LIBXML_DOCB_ENABLED
4750 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004751#endif
4752 return(NULL);
4753 case XML_NAMESPACE_DECL:
4754 /*
4755 * TODO !!! may require extending struct _xmlNs with
4756 * parent field
4757 * C.f. Infoset case...
4758 */
4759 return(NULL);
4760 }
4761 return(NULL);
4762}
4763
4764/**
4765 * xmlXPathNextAncestorOrSelf:
4766 * @ctxt: the XPath Parser context
4767 * @cur: the current node in the traversal
4768 *
4769 * Traversal function for the "ancestor-or-self" direction
4770 * he ancestor-or-self axis contains the context node and ancestors of
4771 * the context node in reverse document order; thus the context node is
4772 * the first node on the axis, and the context node's parent the second;
4773 * parent here is defined the same as with the parent axis.
4774 *
4775 * Returns the next element following that axis
4776 */
4777xmlNodePtr
4778xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4779 if (cur == NULL)
4780 return(ctxt->context->node);
4781 return(xmlXPathNextAncestor(ctxt, cur));
4782}
4783
4784/**
4785 * xmlXPathNextFollowingSibling:
4786 * @ctxt: the XPath Parser context
4787 * @cur: the current node in the traversal
4788 *
4789 * Traversal function for the "following-sibling" direction
4790 * The following-sibling axis contains the following siblings of the context
4791 * node in document order.
4792 *
4793 * Returns the next element following that axis
4794 */
4795xmlNodePtr
4796xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4797 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4798 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4799 return(NULL);
4800 if (cur == (xmlNodePtr) ctxt->context->doc)
4801 return(NULL);
4802 if (cur == NULL)
4803 return(ctxt->context->node->next);
4804 return(cur->next);
4805}
4806
4807/**
4808 * xmlXPathNextPrecedingSibling:
4809 * @ctxt: the XPath Parser context
4810 * @cur: the current node in the traversal
4811 *
4812 * Traversal function for the "preceding-sibling" direction
4813 * The preceding-sibling axis contains the preceding siblings of the context
4814 * node in reverse document order; the first preceding sibling is first on the
4815 * axis; the sibling preceding that node is the second on the axis and so on.
4816 *
4817 * Returns the next element following that axis
4818 */
4819xmlNodePtr
4820xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4821 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4822 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4823 return(NULL);
4824 if (cur == (xmlNodePtr) ctxt->context->doc)
4825 return(NULL);
4826 if (cur == NULL)
4827 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004828 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4829 cur = cur->prev;
4830 if (cur == NULL)
4831 return(ctxt->context->node->prev);
4832 }
Owen Taylor3473f882001-02-23 17:55:21 +00004833 return(cur->prev);
4834}
4835
4836/**
4837 * xmlXPathNextFollowing:
4838 * @ctxt: the XPath Parser context
4839 * @cur: the current node in the traversal
4840 *
4841 * Traversal function for the "following" direction
4842 * The following axis contains all nodes in the same document as the context
4843 * node that are after the context node in document order, excluding any
4844 * descendants and excluding attribute nodes and namespace nodes; the nodes
4845 * are ordered in document order
4846 *
4847 * Returns the next element following that axis
4848 */
4849xmlNodePtr
4850xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4851 if (cur != NULL && cur->children != NULL)
4852 return cur->children ;
4853 if (cur == NULL) cur = ctxt->context->node;
4854 if (cur == NULL) return(NULL) ; /* ERROR */
4855 if (cur->next != NULL) return(cur->next) ;
4856 do {
4857 cur = cur->parent;
4858 if (cur == NULL) return(NULL);
4859 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4860 if (cur->next != NULL) return(cur->next);
4861 } while (cur != NULL);
4862 return(cur);
4863}
4864
4865/*
4866 * xmlXPathIsAncestor:
4867 * @ancestor: the ancestor node
4868 * @node: the current node
4869 *
4870 * Check that @ancestor is a @node's ancestor
4871 *
4872 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4873 */
4874static int
4875xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4876 if ((ancestor == NULL) || (node == NULL)) return(0);
4877 /* nodes need to be in the same document */
4878 if (ancestor->doc != node->doc) return(0);
4879 /* avoid searching if ancestor or node is the root node */
4880 if (ancestor == (xmlNodePtr) node->doc) return(1);
4881 if (node == (xmlNodePtr) ancestor->doc) return(0);
4882 while (node->parent != NULL) {
4883 if (node->parent == ancestor)
4884 return(1);
4885 node = node->parent;
4886 }
4887 return(0);
4888}
4889
4890/**
4891 * xmlXPathNextPreceding:
4892 * @ctxt: the XPath Parser context
4893 * @cur: the current node in the traversal
4894 *
4895 * Traversal function for the "preceding" direction
4896 * the preceding axis contains all nodes in the same document as the context
4897 * node that are before the context node in document order, excluding any
4898 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4899 * ordered in reverse document order
4900 *
4901 * Returns the next element following that axis
4902 */
4903xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004904xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4905{
Owen Taylor3473f882001-02-23 17:55:21 +00004906 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004907 cur = ctxt->context->node;
4908 if (cur == NULL)
4909 return (NULL);
4910 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4911 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004912 do {
4913 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004914 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4915 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004916 }
4917
4918 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004919 if (cur == NULL)
4920 return (NULL);
4921 if (cur == ctxt->context->doc->children)
4922 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004923 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004924 return (cur);
4925}
4926
4927/**
4928 * xmlXPathNextPrecedingInternal:
4929 * @ctxt: the XPath Parser context
4930 * @cur: the current node in the traversal
4931 *
4932 * Traversal function for the "preceding" direction
4933 * the preceding axis contains all nodes in the same document as the context
4934 * node that are before the context node in document order, excluding any
4935 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4936 * ordered in reverse document order
4937 * This is a faster implementation but internal only since it requires a
4938 * state kept in the parser context: ctxt->ancestor.
4939 *
4940 * Returns the next element following that axis
4941 */
4942static xmlNodePtr
4943xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4944 xmlNodePtr cur)
4945{
4946 if (cur == NULL) {
4947 cur = ctxt->context->node;
4948 if (cur == NULL)
4949 return (NULL);
4950 ctxt->ancestor = cur->parent;
4951 }
4952 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4953 cur = cur->prev;
4954 while (cur->prev == NULL) {
4955 cur = cur->parent;
4956 if (cur == NULL)
4957 return (NULL);
4958 if (cur == ctxt->context->doc->children)
4959 return (NULL);
4960 if (cur != ctxt->ancestor)
4961 return (cur);
4962 ctxt->ancestor = cur->parent;
4963 }
4964 cur = cur->prev;
4965 while (cur->last != NULL)
4966 cur = cur->last;
4967 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004968}
4969
4970/**
4971 * xmlXPathNextNamespace:
4972 * @ctxt: the XPath Parser context
4973 * @cur: the current attribute in the traversal
4974 *
4975 * Traversal function for the "namespace" direction
4976 * the namespace axis contains the namespace nodes of the context node;
4977 * the order of nodes on this axis is implementation-defined; the axis will
4978 * be empty unless the context node is an element
4979 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00004980 * We keep the XML namespace node at the end of the list.
4981 *
Owen Taylor3473f882001-02-23 17:55:21 +00004982 * Returns the next element following that axis
4983 */
4984xmlNodePtr
4985xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004986 xmlNodePtr ret;
4987
Owen Taylor3473f882001-02-23 17:55:21 +00004988 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00004989 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
4990 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004991 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
4992 if (ctxt->context->tmpNsList != NULL)
4993 xmlFree(ctxt->context->tmpNsList);
4994 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00004995 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004996 if (ctxt->context->tmpNsList == NULL) return(NULL);
4997 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004998 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004999 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5000 if (ret == NULL) {
5001 xmlFree(ctxt->context->tmpNsList);
5002 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005003 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005004 }
5005 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005006}
5007
5008/**
5009 * xmlXPathNextAttribute:
5010 * @ctxt: the XPath Parser context
5011 * @cur: the current attribute in the traversal
5012 *
5013 * Traversal function for the "attribute" direction
5014 * TODO: support DTD inherited default attributes
5015 *
5016 * Returns the next element following that axis
5017 */
5018xmlNodePtr
5019xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005020 if (ctxt->context->node == NULL)
5021 return(NULL);
5022 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5023 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005024 if (cur == NULL) {
5025 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5026 return(NULL);
5027 return((xmlNodePtr)ctxt->context->node->properties);
5028 }
5029 return((xmlNodePtr)cur->next);
5030}
5031
5032/************************************************************************
5033 * *
5034 * NodeTest Functions *
5035 * *
5036 ************************************************************************/
5037
Owen Taylor3473f882001-02-23 17:55:21 +00005038#define IS_FUNCTION 200
5039
Owen Taylor3473f882001-02-23 17:55:21 +00005040
5041/************************************************************************
5042 * *
5043 * Implicit tree core function library *
5044 * *
5045 ************************************************************************/
5046
5047/**
5048 * xmlXPathRoot:
5049 * @ctxt: the XPath Parser context
5050 *
5051 * Initialize the context to the root of the document
5052 */
5053void
5054xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5055 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5056 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5057}
5058
5059/************************************************************************
5060 * *
5061 * The explicit core function library *
5062 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5063 * *
5064 ************************************************************************/
5065
5066
5067/**
5068 * xmlXPathLastFunction:
5069 * @ctxt: the XPath Parser context
5070 * @nargs: the number of arguments
5071 *
5072 * Implement the last() XPath function
5073 * number last()
5074 * The last function returns the number of nodes in the context node list.
5075 */
5076void
5077xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5078 CHECK_ARITY(0);
5079 if (ctxt->context->contextSize >= 0) {
5080 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5081#ifdef DEBUG_EXPR
5082 xmlGenericError(xmlGenericErrorContext,
5083 "last() : %d\n", ctxt->context->contextSize);
5084#endif
5085 } else {
5086 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5087 }
5088}
5089
5090/**
5091 * xmlXPathPositionFunction:
5092 * @ctxt: the XPath Parser context
5093 * @nargs: the number of arguments
5094 *
5095 * Implement the position() XPath function
5096 * number position()
5097 * The position function returns the position of the context node in the
5098 * context node list. The first position is 1, and so the last positionr
5099 * will be equal to last().
5100 */
5101void
5102xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5103 CHECK_ARITY(0);
5104 if (ctxt->context->proximityPosition >= 0) {
5105 valuePush(ctxt,
5106 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5107#ifdef DEBUG_EXPR
5108 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5109 ctxt->context->proximityPosition);
5110#endif
5111 } else {
5112 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5113 }
5114}
5115
5116/**
5117 * xmlXPathCountFunction:
5118 * @ctxt: the XPath Parser context
5119 * @nargs: the number of arguments
5120 *
5121 * Implement the count() XPath function
5122 * number count(node-set)
5123 */
5124void
5125xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5126 xmlXPathObjectPtr cur;
5127
5128 CHECK_ARITY(1);
5129 if ((ctxt->value == NULL) ||
5130 ((ctxt->value->type != XPATH_NODESET) &&
5131 (ctxt->value->type != XPATH_XSLT_TREE)))
5132 XP_ERROR(XPATH_INVALID_TYPE);
5133 cur = valuePop(ctxt);
5134
Daniel Veillard911f49a2001-04-07 15:39:35 +00005135 if ((cur == NULL) || (cur->nodesetval == NULL))
5136 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005137 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005138 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005139 } else {
5140 if ((cur->nodesetval->nodeNr != 1) ||
5141 (cur->nodesetval->nodeTab == NULL)) {
5142 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5143 } else {
5144 xmlNodePtr tmp;
5145 int i = 0;
5146
5147 tmp = cur->nodesetval->nodeTab[0];
5148 if (tmp != NULL) {
5149 tmp = tmp->children;
5150 while (tmp != NULL) {
5151 tmp = tmp->next;
5152 i++;
5153 }
5154 }
5155 valuePush(ctxt, xmlXPathNewFloat((double) i));
5156 }
5157 }
Owen Taylor3473f882001-02-23 17:55:21 +00005158 xmlXPathFreeObject(cur);
5159}
5160
5161/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005162 * xmlXPathGetElementsByIds:
5163 * @doc: the document
5164 * @ids: a whitespace separated list of IDs
5165 *
5166 * Selects elements by their unique ID.
5167 *
5168 * Returns a node-set of selected elements.
5169 */
5170static xmlNodeSetPtr
5171xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5172 xmlNodeSetPtr ret;
5173 const xmlChar *cur = ids;
5174 xmlChar *ID;
5175 xmlAttrPtr attr;
5176 xmlNodePtr elem = NULL;
5177
5178 ret = xmlXPathNodeSetCreate(NULL);
5179
5180 while (IS_BLANK(*cur)) cur++;
5181 while (*cur != 0) {
5182 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5183 (*cur == '.') || (*cur == '-') ||
5184 (*cur == '_') || (*cur == ':') ||
5185 (IS_COMBINING(*cur)) ||
5186 (IS_EXTENDER(*cur)))
5187 cur++;
5188
5189 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5190
5191 ID = xmlStrndup(ids, cur - ids);
5192 attr = xmlGetID(doc, ID);
5193 if (attr != NULL) {
5194 elem = attr->parent;
5195 xmlXPathNodeSetAdd(ret, elem);
5196 }
5197 if (ID != NULL)
5198 xmlFree(ID);
5199
5200 while (IS_BLANK(*cur)) cur++;
5201 ids = cur;
5202 }
5203 return(ret);
5204}
5205
5206/**
Owen Taylor3473f882001-02-23 17:55:21 +00005207 * xmlXPathIdFunction:
5208 * @ctxt: the XPath Parser context
5209 * @nargs: the number of arguments
5210 *
5211 * Implement the id() XPath function
5212 * node-set id(object)
5213 * The id function selects elements by their unique ID
5214 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5215 * then the result is the union of the result of applying id to the
5216 * string value of each of the nodes in the argument node-set. When the
5217 * argument to id is of any other type, the argument is converted to a
5218 * string as if by a call to the string function; the string is split
5219 * into a whitespace-separated list of tokens (whitespace is any sequence
5220 * of characters matching the production S); the result is a node-set
5221 * containing the elements in the same document as the context node that
5222 * have a unique ID equal to any of the tokens in the list.
5223 */
5224void
5225xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005226 xmlChar *tokens;
5227 xmlNodeSetPtr ret;
5228 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005229
5230 CHECK_ARITY(1);
5231 obj = valuePop(ctxt);
5232 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5233 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005234 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005235 int i;
5236
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005237 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005238
Daniel Veillard911f49a2001-04-07 15:39:35 +00005239 if (obj->nodesetval != NULL) {
5240 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005241 tokens =
5242 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5243 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5244 ret = xmlXPathNodeSetMerge(ret, ns);
5245 xmlXPathFreeNodeSet(ns);
5246 if (tokens != NULL)
5247 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005248 }
Owen Taylor3473f882001-02-23 17:55:21 +00005249 }
5250
5251 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005252 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005253 return;
5254 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005255 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005256
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005257 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5258 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005259
Owen Taylor3473f882001-02-23 17:55:21 +00005260 xmlXPathFreeObject(obj);
5261 return;
5262}
5263
5264/**
5265 * xmlXPathLocalNameFunction:
5266 * @ctxt: the XPath Parser context
5267 * @nargs: the number of arguments
5268 *
5269 * Implement the local-name() XPath function
5270 * string local-name(node-set?)
5271 * The local-name function returns a string containing the local part
5272 * of the name of the node in the argument node-set that is first in
5273 * document order. If the node-set is empty or the first node has no
5274 * name, an empty string is returned. If the argument is omitted it
5275 * defaults to the context node.
5276 */
5277void
5278xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5279 xmlXPathObjectPtr cur;
5280
5281 if (nargs == 0) {
5282 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5283 nargs = 1;
5284 }
5285
5286 CHECK_ARITY(1);
5287 if ((ctxt->value == NULL) ||
5288 ((ctxt->value->type != XPATH_NODESET) &&
5289 (ctxt->value->type != XPATH_XSLT_TREE)))
5290 XP_ERROR(XPATH_INVALID_TYPE);
5291 cur = valuePop(ctxt);
5292
Daniel Veillard911f49a2001-04-07 15:39:35 +00005293 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005294 valuePush(ctxt, xmlXPathNewCString(""));
5295 } else {
5296 int i = 0; /* Should be first in document order !!!!! */
5297 switch (cur->nodesetval->nodeTab[i]->type) {
5298 case XML_ELEMENT_NODE:
5299 case XML_ATTRIBUTE_NODE:
5300 case XML_PI_NODE:
5301 valuePush(ctxt,
5302 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5303 break;
5304 case XML_NAMESPACE_DECL:
5305 valuePush(ctxt, xmlXPathNewString(
5306 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5307 break;
5308 default:
5309 valuePush(ctxt, xmlXPathNewCString(""));
5310 }
5311 }
5312 xmlXPathFreeObject(cur);
5313}
5314
5315/**
5316 * xmlXPathNamespaceURIFunction:
5317 * @ctxt: the XPath Parser context
5318 * @nargs: the number of arguments
5319 *
5320 * Implement the namespace-uri() XPath function
5321 * string namespace-uri(node-set?)
5322 * The namespace-uri function returns a string containing the
5323 * namespace URI of the expanded name of the node in the argument
5324 * node-set that is first in document order. If the node-set is empty,
5325 * the first node has no name, or the expanded name has no namespace
5326 * URI, an empty string is returned. If the argument is omitted it
5327 * defaults to the context node.
5328 */
5329void
5330xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5331 xmlXPathObjectPtr cur;
5332
5333 if (nargs == 0) {
5334 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5335 nargs = 1;
5336 }
5337 CHECK_ARITY(1);
5338 if ((ctxt->value == NULL) ||
5339 ((ctxt->value->type != XPATH_NODESET) &&
5340 (ctxt->value->type != XPATH_XSLT_TREE)))
5341 XP_ERROR(XPATH_INVALID_TYPE);
5342 cur = valuePop(ctxt);
5343
Daniel Veillard911f49a2001-04-07 15:39:35 +00005344 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005345 valuePush(ctxt, xmlXPathNewCString(""));
5346 } else {
5347 int i = 0; /* Should be first in document order !!!!! */
5348 switch (cur->nodesetval->nodeTab[i]->type) {
5349 case XML_ELEMENT_NODE:
5350 case XML_ATTRIBUTE_NODE:
5351 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5352 valuePush(ctxt, xmlXPathNewCString(""));
5353 else
5354 valuePush(ctxt, xmlXPathNewString(
5355 cur->nodesetval->nodeTab[i]->ns->href));
5356 break;
5357 default:
5358 valuePush(ctxt, xmlXPathNewCString(""));
5359 }
5360 }
5361 xmlXPathFreeObject(cur);
5362}
5363
5364/**
5365 * xmlXPathNameFunction:
5366 * @ctxt: the XPath Parser context
5367 * @nargs: the number of arguments
5368 *
5369 * Implement the name() XPath function
5370 * string name(node-set?)
5371 * The name function returns a string containing a QName representing
5372 * the name of the node in the argument node-set that is first in documenti
5373 * order. The QName must represent the name with respect to the namespace
5374 * declarations in effect on the node whose name is being represented.
5375 * Typically, this will be the form in which the name occurred in the XML
5376 * source. This need not be the case if there are namespace declarations
5377 * in effect on the node that associate multiple prefixes with the same
5378 * namespace. However, an implementation may include information about
5379 * the original prefix in its representation of nodes; in this case, an
5380 * implementation can ensure that the returned string is always the same
5381 * as the QName used in the XML source. If the argument it omitted it
5382 * defaults to the context node.
5383 * Libxml keep the original prefix so the "real qualified name" used is
5384 * returned.
5385 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005386static void
Daniel Veillard04383752001-07-08 14:27:15 +00005387xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5388{
Owen Taylor3473f882001-02-23 17:55:21 +00005389 xmlXPathObjectPtr cur;
5390
5391 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005392 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5393 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005394 }
5395
5396 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005397 if ((ctxt->value == NULL) ||
5398 ((ctxt->value->type != XPATH_NODESET) &&
5399 (ctxt->value->type != XPATH_XSLT_TREE)))
5400 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005401 cur = valuePop(ctxt);
5402
Daniel Veillard911f49a2001-04-07 15:39:35 +00005403 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005404 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005405 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005406 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005407
Daniel Veillard04383752001-07-08 14:27:15 +00005408 switch (cur->nodesetval->nodeTab[i]->type) {
5409 case XML_ELEMENT_NODE:
5410 case XML_ATTRIBUTE_NODE:
5411 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5412 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5413 valuePush(ctxt,
5414 xmlXPathNewString(cur->nodesetval->
5415 nodeTab[i]->name));
5416
5417 else {
5418 char name[2000];
5419
5420 snprintf(name, sizeof(name), "%s:%s",
5421 (char *) cur->nodesetval->nodeTab[i]->ns->
5422 prefix,
5423 (char *) cur->nodesetval->nodeTab[i]->name);
5424 name[sizeof(name) - 1] = 0;
5425 valuePush(ctxt, xmlXPathNewCString(name));
5426 }
5427 break;
5428 default:
5429 valuePush(ctxt,
5430 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5431 xmlXPathLocalNameFunction(ctxt, 1);
5432 }
Owen Taylor3473f882001-02-23 17:55:21 +00005433 }
5434 xmlXPathFreeObject(cur);
5435}
5436
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005437
5438/**
Owen Taylor3473f882001-02-23 17:55:21 +00005439 * xmlXPathStringFunction:
5440 * @ctxt: the XPath Parser context
5441 * @nargs: the number of arguments
5442 *
5443 * Implement the string() XPath function
5444 * string string(object?)
5445 * he string function converts an object to a string as follows:
5446 * - A node-set is converted to a string by returning the value of
5447 * the node in the node-set that is first in document order.
5448 * If the node-set is empty, an empty string is returned.
5449 * - A number is converted to a string as follows
5450 * + NaN is converted to the string NaN
5451 * + positive zero is converted to the string 0
5452 * + negative zero is converted to the string 0
5453 * + positive infinity is converted to the string Infinity
5454 * + negative infinity is converted to the string -Infinity
5455 * + if the number is an integer, the number is represented in
5456 * decimal form as a Number with no decimal point and no leading
5457 * zeros, preceded by a minus sign (-) if the number is negative
5458 * + otherwise, the number is represented in decimal form as a
5459 * Number including a decimal point with at least one digit
5460 * before the decimal point and at least one digit after the
5461 * decimal point, preceded by a minus sign (-) if the number
5462 * is negative; there must be no leading zeros before the decimal
5463 * point apart possibly from the one required digit immediatelyi
5464 * before the decimal point; beyond the one required digit
5465 * after the decimal point there must be as many, but only as
5466 * many, more digits as are needed to uniquely distinguish the
5467 * number from all other IEEE 754 numeric values.
5468 * - The boolean false value is converted to the string false.
5469 * The boolean true value is converted to the string true.
5470 *
5471 * If the argument is omitted, it defaults to a node-set with the
5472 * context node as its only member.
5473 */
5474void
5475xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5476 xmlXPathObjectPtr cur;
5477
5478 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005479 valuePush(ctxt,
5480 xmlXPathWrapString(
5481 xmlXPathCastNodeToString(ctxt->context->node)));
5482 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005483 }
5484
5485 CHECK_ARITY(1);
5486 cur = valuePop(ctxt);
5487 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005488 cur = xmlXPathConvertString(cur);
5489 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005490}
5491
5492/**
5493 * xmlXPathStringLengthFunction:
5494 * @ctxt: the XPath Parser context
5495 * @nargs: the number of arguments
5496 *
5497 * Implement the string-length() XPath function
5498 * number string-length(string?)
5499 * The string-length returns the number of characters in the string
5500 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5501 * the context node converted to a string, in other words the value
5502 * of the context node.
5503 */
5504void
5505xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5506 xmlXPathObjectPtr cur;
5507
5508 if (nargs == 0) {
5509 if (ctxt->context->node == NULL) {
5510 valuePush(ctxt, xmlXPathNewFloat(0));
5511 } else {
5512 xmlChar *content;
5513
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005514 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005515 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005516 xmlFree(content);
5517 }
5518 return;
5519 }
5520 CHECK_ARITY(1);
5521 CAST_TO_STRING;
5522 CHECK_TYPE(XPATH_STRING);
5523 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005524 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005525 xmlXPathFreeObject(cur);
5526}
5527
5528/**
5529 * xmlXPathConcatFunction:
5530 * @ctxt: the XPath Parser context
5531 * @nargs: the number of arguments
5532 *
5533 * Implement the concat() XPath function
5534 * string concat(string, string, string*)
5535 * The concat function returns the concatenation of its arguments.
5536 */
5537void
5538xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5539 xmlXPathObjectPtr cur, newobj;
5540 xmlChar *tmp;
5541
5542 if (nargs < 2) {
5543 CHECK_ARITY(2);
5544 }
5545
5546 CAST_TO_STRING;
5547 cur = valuePop(ctxt);
5548 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5549 xmlXPathFreeObject(cur);
5550 return;
5551 }
5552 nargs--;
5553
5554 while (nargs > 0) {
5555 CAST_TO_STRING;
5556 newobj = valuePop(ctxt);
5557 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5558 xmlXPathFreeObject(newobj);
5559 xmlXPathFreeObject(cur);
5560 XP_ERROR(XPATH_INVALID_TYPE);
5561 }
5562 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5563 newobj->stringval = cur->stringval;
5564 cur->stringval = tmp;
5565
5566 xmlXPathFreeObject(newobj);
5567 nargs--;
5568 }
5569 valuePush(ctxt, cur);
5570}
5571
5572/**
5573 * xmlXPathContainsFunction:
5574 * @ctxt: the XPath Parser context
5575 * @nargs: the number of arguments
5576 *
5577 * Implement the contains() XPath function
5578 * boolean contains(string, string)
5579 * The contains function returns true if the first argument string
5580 * contains the second argument string, and otherwise returns false.
5581 */
5582void
5583xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5584 xmlXPathObjectPtr hay, needle;
5585
5586 CHECK_ARITY(2);
5587 CAST_TO_STRING;
5588 CHECK_TYPE(XPATH_STRING);
5589 needle = valuePop(ctxt);
5590 CAST_TO_STRING;
5591 hay = valuePop(ctxt);
5592 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5593 xmlXPathFreeObject(hay);
5594 xmlXPathFreeObject(needle);
5595 XP_ERROR(XPATH_INVALID_TYPE);
5596 }
5597 if (xmlStrstr(hay->stringval, needle->stringval))
5598 valuePush(ctxt, xmlXPathNewBoolean(1));
5599 else
5600 valuePush(ctxt, xmlXPathNewBoolean(0));
5601 xmlXPathFreeObject(hay);
5602 xmlXPathFreeObject(needle);
5603}
5604
5605/**
5606 * xmlXPathStartsWithFunction:
5607 * @ctxt: the XPath Parser context
5608 * @nargs: the number of arguments
5609 *
5610 * Implement the starts-with() XPath function
5611 * boolean starts-with(string, string)
5612 * The starts-with function returns true if the first argument string
5613 * starts with the second argument string, and otherwise returns false.
5614 */
5615void
5616xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5617 xmlXPathObjectPtr hay, needle;
5618 int n;
5619
5620 CHECK_ARITY(2);
5621 CAST_TO_STRING;
5622 CHECK_TYPE(XPATH_STRING);
5623 needle = valuePop(ctxt);
5624 CAST_TO_STRING;
5625 hay = valuePop(ctxt);
5626 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5627 xmlXPathFreeObject(hay);
5628 xmlXPathFreeObject(needle);
5629 XP_ERROR(XPATH_INVALID_TYPE);
5630 }
5631 n = xmlStrlen(needle->stringval);
5632 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5633 valuePush(ctxt, xmlXPathNewBoolean(0));
5634 else
5635 valuePush(ctxt, xmlXPathNewBoolean(1));
5636 xmlXPathFreeObject(hay);
5637 xmlXPathFreeObject(needle);
5638}
5639
5640/**
5641 * xmlXPathSubstringFunction:
5642 * @ctxt: the XPath Parser context
5643 * @nargs: the number of arguments
5644 *
5645 * Implement the substring() XPath function
5646 * string substring(string, number, number?)
5647 * The substring function returns the substring of the first argument
5648 * starting at the position specified in the second argument with
5649 * length specified in the third argument. For example,
5650 * substring("12345",2,3) returns "234". If the third argument is not
5651 * specified, it returns the substring starting at the position specified
5652 * in the second argument and continuing to the end of the string. For
5653 * example, substring("12345",2) returns "2345". More precisely, each
5654 * character in the string (see [3.6 Strings]) is considered to have a
5655 * numeric position: the position of the first character is 1, the position
5656 * of the second character is 2 and so on. The returned substring contains
5657 * those characters for which the position of the character is greater than
5658 * or equal to the second argument and, if the third argument is specified,
5659 * less than the sum of the second and third arguments; the comparisons
5660 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5661 * - substring("12345", 1.5, 2.6) returns "234"
5662 * - substring("12345", 0, 3) returns "12"
5663 * - substring("12345", 0 div 0, 3) returns ""
5664 * - substring("12345", 1, 0 div 0) returns ""
5665 * - substring("12345", -42, 1 div 0) returns "12345"
5666 * - substring("12345", -1 div 0, 1 div 0) returns ""
5667 */
5668void
5669xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5670 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005671 double le=0, in;
5672 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005673 xmlChar *ret;
5674
Owen Taylor3473f882001-02-23 17:55:21 +00005675 if (nargs < 2) {
5676 CHECK_ARITY(2);
5677 }
5678 if (nargs > 3) {
5679 CHECK_ARITY(3);
5680 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005681 /*
5682 * take care of possible last (position) argument
5683 */
Owen Taylor3473f882001-02-23 17:55:21 +00005684 if (nargs == 3) {
5685 CAST_TO_NUMBER;
5686 CHECK_TYPE(XPATH_NUMBER);
5687 len = valuePop(ctxt);
5688 le = len->floatval;
5689 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005690 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005691
Owen Taylor3473f882001-02-23 17:55:21 +00005692 CAST_TO_NUMBER;
5693 CHECK_TYPE(XPATH_NUMBER);
5694 start = valuePop(ctxt);
5695 in = start->floatval;
5696 xmlXPathFreeObject(start);
5697 CAST_TO_STRING;
5698 CHECK_TYPE(XPATH_STRING);
5699 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005700 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005701
Daniel Veillard97ac1312001-05-30 19:14:17 +00005702 /*
5703 * If last pos not present, calculate last position
5704 */
5705 if (nargs != 3)
5706 le = m;
5707
5708 /*
5709 * To meet our requirements, initial index calculations
5710 * must be done before we convert to integer format
5711 *
5712 * First we normalize indices
5713 */
5714 in -= 1.0;
5715 le += in;
5716 if (in < 0.0)
5717 in = 0.0;
5718 if (le > (double)m)
5719 le = (double)m;
5720
5721 /*
5722 * Now we go to integer form, rounding up
5723 */
Owen Taylor3473f882001-02-23 17:55:21 +00005724 i = (int) in;
5725 if (((double)i) != in) i++;
5726
Owen Taylor3473f882001-02-23 17:55:21 +00005727 l = (int) le;
5728 if (((double)l) != le) l++;
5729
Daniel Veillard97ac1312001-05-30 19:14:17 +00005730 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005731
5732 /* number of chars to copy */
5733 l -= i;
5734
Daniel Veillard97ac1312001-05-30 19:14:17 +00005735 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005736 if (ret == NULL)
5737 valuePush(ctxt, xmlXPathNewCString(""));
5738 else {
5739 valuePush(ctxt, xmlXPathNewString(ret));
5740 xmlFree(ret);
5741 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005742
Owen Taylor3473f882001-02-23 17:55:21 +00005743 xmlXPathFreeObject(str);
5744}
5745
5746/**
5747 * xmlXPathSubstringBeforeFunction:
5748 * @ctxt: the XPath Parser context
5749 * @nargs: the number of arguments
5750 *
5751 * Implement the substring-before() XPath function
5752 * string substring-before(string, string)
5753 * The substring-before function returns the substring of the first
5754 * argument string that precedes the first occurrence of the second
5755 * argument string in the first argument string, or the empty string
5756 * if the first argument string does not contain the second argument
5757 * string. For example, substring-before("1999/04/01","/") returns 1999.
5758 */
5759void
5760xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5761 xmlXPathObjectPtr str;
5762 xmlXPathObjectPtr find;
5763 xmlBufferPtr target;
5764 const xmlChar *point;
5765 int offset;
5766
5767 CHECK_ARITY(2);
5768 CAST_TO_STRING;
5769 find = valuePop(ctxt);
5770 CAST_TO_STRING;
5771 str = valuePop(ctxt);
5772
5773 target = xmlBufferCreate();
5774 if (target) {
5775 point = xmlStrstr(str->stringval, find->stringval);
5776 if (point) {
5777 offset = (int)(point - str->stringval);
5778 xmlBufferAdd(target, str->stringval, offset);
5779 }
5780 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5781 xmlBufferFree(target);
5782 }
5783
5784 xmlXPathFreeObject(str);
5785 xmlXPathFreeObject(find);
5786}
5787
5788/**
5789 * xmlXPathSubstringAfterFunction:
5790 * @ctxt: the XPath Parser context
5791 * @nargs: the number of arguments
5792 *
5793 * Implement the substring-after() XPath function
5794 * string substring-after(string, string)
5795 * The substring-after function returns the substring of the first
5796 * argument string that follows the first occurrence of the second
5797 * argument string in the first argument string, or the empty stringi
5798 * if the first argument string does not contain the second argument
5799 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5800 * and substring-after("1999/04/01","19") returns 99/04/01.
5801 */
5802void
5803xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5804 xmlXPathObjectPtr str;
5805 xmlXPathObjectPtr find;
5806 xmlBufferPtr target;
5807 const xmlChar *point;
5808 int offset;
5809
5810 CHECK_ARITY(2);
5811 CAST_TO_STRING;
5812 find = valuePop(ctxt);
5813 CAST_TO_STRING;
5814 str = valuePop(ctxt);
5815
5816 target = xmlBufferCreate();
5817 if (target) {
5818 point = xmlStrstr(str->stringval, find->stringval);
5819 if (point) {
5820 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5821 xmlBufferAdd(target, &str->stringval[offset],
5822 xmlStrlen(str->stringval) - offset);
5823 }
5824 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5825 xmlBufferFree(target);
5826 }
5827
5828 xmlXPathFreeObject(str);
5829 xmlXPathFreeObject(find);
5830}
5831
5832/**
5833 * xmlXPathNormalizeFunction:
5834 * @ctxt: the XPath Parser context
5835 * @nargs: the number of arguments
5836 *
5837 * Implement the normalize-space() XPath function
5838 * string normalize-space(string?)
5839 * The normalize-space function returns the argument string with white
5840 * space normalized by stripping leading and trailing whitespace
5841 * and replacing sequences of whitespace characters by a single
5842 * space. Whitespace characters are the same allowed by the S production
5843 * in XML. If the argument is omitted, it defaults to the context
5844 * node converted to a string, in other words the value of the context node.
5845 */
5846void
5847xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5848 xmlXPathObjectPtr obj = NULL;
5849 xmlChar *source = NULL;
5850 xmlBufferPtr target;
5851 xmlChar blank;
5852
5853 if (nargs == 0) {
5854 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005855 valuePush(ctxt,
5856 xmlXPathWrapString(
5857 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005858 nargs = 1;
5859 }
5860
5861 CHECK_ARITY(1);
5862 CAST_TO_STRING;
5863 CHECK_TYPE(XPATH_STRING);
5864 obj = valuePop(ctxt);
5865 source = obj->stringval;
5866
5867 target = xmlBufferCreate();
5868 if (target && source) {
5869
5870 /* Skip leading whitespaces */
5871 while (IS_BLANK(*source))
5872 source++;
5873
5874 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5875 blank = 0;
5876 while (*source) {
5877 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005878 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005879 } else {
5880 if (blank) {
5881 xmlBufferAdd(target, &blank, 1);
5882 blank = 0;
5883 }
5884 xmlBufferAdd(target, source, 1);
5885 }
5886 source++;
5887 }
5888
5889 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5890 xmlBufferFree(target);
5891 }
5892 xmlXPathFreeObject(obj);
5893}
5894
5895/**
5896 * xmlXPathTranslateFunction:
5897 * @ctxt: the XPath Parser context
5898 * @nargs: the number of arguments
5899 *
5900 * Implement the translate() XPath function
5901 * string translate(string, string, string)
5902 * The translate function returns the first argument string with
5903 * occurrences of characters in the second argument string replaced
5904 * by the character at the corresponding position in the third argument
5905 * string. For example, translate("bar","abc","ABC") returns the string
5906 * BAr. If there is a character in the second argument string with no
5907 * character at a corresponding position in the third argument string
5908 * (because the second argument string is longer than the third argument
5909 * string), then occurrences of that character in the first argument
5910 * string are removed. For example, translate("--aaa--","abc-","ABC")
5911 * returns "AAA". If a character occurs more than once in second
5912 * argument string, then the first occurrence determines the replacement
5913 * character. If the third argument string is longer than the second
5914 * argument string, then excess characters are ignored.
5915 */
5916void
5917xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005918 xmlXPathObjectPtr str;
5919 xmlXPathObjectPtr from;
5920 xmlXPathObjectPtr to;
5921 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005922 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005923 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005924 xmlChar *point;
5925 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005926
Daniel Veillarde043ee12001-04-16 14:08:07 +00005927 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005928
Daniel Veillarde043ee12001-04-16 14:08:07 +00005929 CAST_TO_STRING;
5930 to = valuePop(ctxt);
5931 CAST_TO_STRING;
5932 from = valuePop(ctxt);
5933 CAST_TO_STRING;
5934 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005935
Daniel Veillarde043ee12001-04-16 14:08:07 +00005936 target = xmlBufferCreate();
5937 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005938 max = xmlUTF8Strlen(to->stringval);
5939 for (cptr = str->stringval; (ch=*cptr); ) {
5940 offset = xmlUTF8Strloc(from->stringval, cptr);
5941 if (offset >= 0) {
5942 if (offset < max) {
5943 point = xmlUTF8Strpos(to->stringval, offset);
5944 if (point)
5945 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5946 }
5947 } else
5948 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5949
5950 /* Step to next character in input */
5951 cptr++;
5952 if ( ch & 0x80 ) {
5953 /* if not simple ascii, verify proper format */
5954 if ( (ch & 0xc0) != 0xc0 ) {
5955 xmlGenericError(xmlGenericErrorContext,
5956 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5957 break;
5958 }
5959 /* then skip over remaining bytes for this char */
5960 while ( (ch <<= 1) & 0x80 )
5961 if ( (*cptr++ & 0xc0) != 0x80 ) {
5962 xmlGenericError(xmlGenericErrorContext,
5963 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5964 break;
5965 }
5966 if (ch & 0x80) /* must have had error encountered */
5967 break;
5968 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005969 }
Owen Taylor3473f882001-02-23 17:55:21 +00005970 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005971 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5972 xmlBufferFree(target);
5973 xmlXPathFreeObject(str);
5974 xmlXPathFreeObject(from);
5975 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005976}
5977
5978/**
5979 * xmlXPathBooleanFunction:
5980 * @ctxt: the XPath Parser context
5981 * @nargs: the number of arguments
5982 *
5983 * Implement the boolean() XPath function
5984 * boolean boolean(object)
5985 * he boolean function converts its argument to a boolean as follows:
5986 * - a number is true if and only if it is neither positive or
5987 * negative zero nor NaN
5988 * - a node-set is true if and only if it is non-empty
5989 * - a string is true if and only if its length is non-zero
5990 */
5991void
5992xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5993 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005994
5995 CHECK_ARITY(1);
5996 cur = valuePop(ctxt);
5997 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005998 cur = xmlXPathConvertBoolean(cur);
5999 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006000}
6001
6002/**
6003 * xmlXPathNotFunction:
6004 * @ctxt: the XPath Parser context
6005 * @nargs: the number of arguments
6006 *
6007 * Implement the not() XPath function
6008 * boolean not(boolean)
6009 * The not function returns true if its argument is false,
6010 * and false otherwise.
6011 */
6012void
6013xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6014 CHECK_ARITY(1);
6015 CAST_TO_BOOLEAN;
6016 CHECK_TYPE(XPATH_BOOLEAN);
6017 ctxt->value->boolval = ! ctxt->value->boolval;
6018}
6019
6020/**
6021 * xmlXPathTrueFunction:
6022 * @ctxt: the XPath Parser context
6023 * @nargs: the number of arguments
6024 *
6025 * Implement the true() XPath function
6026 * boolean true()
6027 */
6028void
6029xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6030 CHECK_ARITY(0);
6031 valuePush(ctxt, xmlXPathNewBoolean(1));
6032}
6033
6034/**
6035 * xmlXPathFalseFunction:
6036 * @ctxt: the XPath Parser context
6037 * @nargs: the number of arguments
6038 *
6039 * Implement the false() XPath function
6040 * boolean false()
6041 */
6042void
6043xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6044 CHECK_ARITY(0);
6045 valuePush(ctxt, xmlXPathNewBoolean(0));
6046}
6047
6048/**
6049 * xmlXPathLangFunction:
6050 * @ctxt: the XPath Parser context
6051 * @nargs: the number of arguments
6052 *
6053 * Implement the lang() XPath function
6054 * boolean lang(string)
6055 * The lang function returns true or false depending on whether the
6056 * language of the context node as specified by xml:lang attributes
6057 * is the same as or is a sublanguage of the language specified by
6058 * the argument string. The language of the context node is determined
6059 * by the value of the xml:lang attribute on the context node, or, if
6060 * the context node has no xml:lang attribute, by the value of the
6061 * xml:lang attribute on the nearest ancestor of the context node that
6062 * has an xml:lang attribute. If there is no such attribute, then lang
6063 * returns false. If there is such an attribute, then lang returns
6064 * true if the attribute value is equal to the argument ignoring case,
6065 * or if there is some suffix starting with - such that the attribute
6066 * value is equal to the argument ignoring that suffix of the attribute
6067 * value and ignoring case.
6068 */
6069void
6070xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6071 xmlXPathObjectPtr val;
6072 const xmlChar *theLang;
6073 const xmlChar *lang;
6074 int ret = 0;
6075 int i;
6076
6077 CHECK_ARITY(1);
6078 CAST_TO_STRING;
6079 CHECK_TYPE(XPATH_STRING);
6080 val = valuePop(ctxt);
6081 lang = val->stringval;
6082 theLang = xmlNodeGetLang(ctxt->context->node);
6083 if ((theLang != NULL) && (lang != NULL)) {
6084 for (i = 0;lang[i] != 0;i++)
6085 if (toupper(lang[i]) != toupper(theLang[i]))
6086 goto not_equal;
6087 ret = 1;
6088 }
6089not_equal:
6090 xmlXPathFreeObject(val);
6091 valuePush(ctxt, xmlXPathNewBoolean(ret));
6092}
6093
6094/**
6095 * xmlXPathNumberFunction:
6096 * @ctxt: the XPath Parser context
6097 * @nargs: the number of arguments
6098 *
6099 * Implement the number() XPath function
6100 * number number(object?)
6101 */
6102void
6103xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6104 xmlXPathObjectPtr cur;
6105 double res;
6106
6107 if (nargs == 0) {
6108 if (ctxt->context->node == NULL) {
6109 valuePush(ctxt, xmlXPathNewFloat(0.0));
6110 } else {
6111 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6112
6113 res = xmlXPathStringEvalNumber(content);
6114 valuePush(ctxt, xmlXPathNewFloat(res));
6115 xmlFree(content);
6116 }
6117 return;
6118 }
6119
6120 CHECK_ARITY(1);
6121 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006122 cur = xmlXPathConvertNumber(cur);
6123 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006124}
6125
6126/**
6127 * xmlXPathSumFunction:
6128 * @ctxt: the XPath Parser context
6129 * @nargs: the number of arguments
6130 *
6131 * Implement the sum() XPath function
6132 * number sum(node-set)
6133 * The sum function returns the sum of the values of the nodes in
6134 * the argument node-set.
6135 */
6136void
6137xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6138 xmlXPathObjectPtr cur;
6139 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006140 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006141
6142 CHECK_ARITY(1);
6143 if ((ctxt->value == NULL) ||
6144 ((ctxt->value->type != XPATH_NODESET) &&
6145 (ctxt->value->type != XPATH_XSLT_TREE)))
6146 XP_ERROR(XPATH_INVALID_TYPE);
6147 cur = valuePop(ctxt);
6148
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006149 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006150 valuePush(ctxt, xmlXPathNewFloat(0.0));
6151 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006152 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6153 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006154 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006155 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006156 }
6157 xmlXPathFreeObject(cur);
6158}
6159
6160/**
6161 * xmlXPathFloorFunction:
6162 * @ctxt: the XPath Parser context
6163 * @nargs: the number of arguments
6164 *
6165 * Implement the floor() XPath function
6166 * number floor(number)
6167 * The floor function returns the largest (closest to positive infinity)
6168 * number that is not greater than the argument and that is an integer.
6169 */
6170void
6171xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6172 CHECK_ARITY(1);
6173 CAST_TO_NUMBER;
6174 CHECK_TYPE(XPATH_NUMBER);
6175#if 0
6176 ctxt->value->floatval = floor(ctxt->value->floatval);
6177#else
6178 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6179 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6180#endif
6181}
6182
6183/**
6184 * xmlXPathCeilingFunction:
6185 * @ctxt: the XPath Parser context
6186 * @nargs: the number of arguments
6187 *
6188 * Implement the ceiling() XPath function
6189 * number ceiling(number)
6190 * The ceiling function returns the smallest (closest to negative infinity)
6191 * number that is not less than the argument and that is an integer.
6192 */
6193void
6194xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6195 double f;
6196
6197 CHECK_ARITY(1);
6198 CAST_TO_NUMBER;
6199 CHECK_TYPE(XPATH_NUMBER);
6200
6201#if 0
6202 ctxt->value->floatval = ceil(ctxt->value->floatval);
6203#else
6204 f = (double)((int) ctxt->value->floatval);
6205 if (f != ctxt->value->floatval)
6206 ctxt->value->floatval = f + 1;
6207#endif
6208}
6209
6210/**
6211 * xmlXPathRoundFunction:
6212 * @ctxt: the XPath Parser context
6213 * @nargs: the number of arguments
6214 *
6215 * Implement the round() XPath function
6216 * number round(number)
6217 * The round function returns the number that is closest to the
6218 * argument and that is an integer. If there are two such numbers,
6219 * then the one that is even is returned.
6220 */
6221void
6222xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6223 double f;
6224
6225 CHECK_ARITY(1);
6226 CAST_TO_NUMBER;
6227 CHECK_TYPE(XPATH_NUMBER);
6228
Daniel Veillardcda96922001-08-21 10:56:31 +00006229 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6230 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6231 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006232 (ctxt->value->floatval == 0.0))
6233 return;
6234
6235#if 0
6236 f = floor(ctxt->value->floatval);
6237#else
6238 f = (double)((int) ctxt->value->floatval);
6239#endif
6240 if (ctxt->value->floatval < f + 0.5)
6241 ctxt->value->floatval = f;
6242 else
6243 ctxt->value->floatval = f + 1;
6244}
6245
6246/************************************************************************
6247 * *
6248 * The Parser *
6249 * *
6250 ************************************************************************/
6251
6252/*
6253 * a couple of forward declarations since we use a recursive call based
6254 * implementation.
6255 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006256static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006257static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006258static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006259#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006260static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6261#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006262#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006263static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006264#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006265static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6266 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006267
6268/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006269 * xmlXPathCurrentChar:
6270 * @ctxt: the XPath parser context
6271 * @cur: pointer to the beginning of the char
6272 * @len: pointer to the length of the char read
6273 *
6274 * The current char value, if using UTF-8 this may actaully span multiple
6275 * bytes in the input buffer.
6276 *
6277 * Returns the current char value and its lenght
6278 */
6279
6280static int
6281xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6282 unsigned char c;
6283 unsigned int val;
6284 const xmlChar *cur;
6285
6286 if (ctxt == NULL)
6287 return(0);
6288 cur = ctxt->cur;
6289
6290 /*
6291 * We are supposed to handle UTF8, check it's valid
6292 * From rfc2044: encoding of the Unicode values on UTF-8:
6293 *
6294 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6295 * 0000 0000-0000 007F 0xxxxxxx
6296 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6297 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6298 *
6299 * Check for the 0x110000 limit too
6300 */
6301 c = *cur;
6302 if (c & 0x80) {
6303 if ((cur[1] & 0xc0) != 0x80)
6304 goto encoding_error;
6305 if ((c & 0xe0) == 0xe0) {
6306
6307 if ((cur[2] & 0xc0) != 0x80)
6308 goto encoding_error;
6309 if ((c & 0xf0) == 0xf0) {
6310 if (((c & 0xf8) != 0xf0) ||
6311 ((cur[3] & 0xc0) != 0x80))
6312 goto encoding_error;
6313 /* 4-byte code */
6314 *len = 4;
6315 val = (cur[0] & 0x7) << 18;
6316 val |= (cur[1] & 0x3f) << 12;
6317 val |= (cur[2] & 0x3f) << 6;
6318 val |= cur[3] & 0x3f;
6319 } else {
6320 /* 3-byte code */
6321 *len = 3;
6322 val = (cur[0] & 0xf) << 12;
6323 val |= (cur[1] & 0x3f) << 6;
6324 val |= cur[2] & 0x3f;
6325 }
6326 } else {
6327 /* 2-byte code */
6328 *len = 2;
6329 val = (cur[0] & 0x1f) << 6;
6330 val |= cur[1] & 0x3f;
6331 }
6332 if (!IS_CHAR(val)) {
6333 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6334 }
6335 return(val);
6336 } else {
6337 /* 1-byte code */
6338 *len = 1;
6339 return((int) *cur);
6340 }
6341encoding_error:
6342 /*
6343 * If we detect an UTF8 error that probably mean that the
6344 * input encoding didn't get properly advertized in the
6345 * declaration header. Report the error and switch the encoding
6346 * to ISO-Latin-1 (if you don't like this policy, just declare the
6347 * encoding !)
6348 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006349 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006350 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006351}
6352
6353/**
Owen Taylor3473f882001-02-23 17:55:21 +00006354 * xmlXPathParseNCName:
6355 * @ctxt: the XPath Parser context
6356 *
6357 * parse an XML namespace non qualified name.
6358 *
6359 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6360 *
6361 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6362 * CombiningChar | Extender
6363 *
6364 * Returns the namespace name or NULL
6365 */
6366
6367xmlChar *
6368xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006369 const xmlChar *in;
6370 xmlChar *ret;
6371 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006372
Daniel Veillard2156a562001-04-28 12:24:34 +00006373 /*
6374 * Accelerator for simple ASCII names
6375 */
6376 in = ctxt->cur;
6377 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6378 ((*in >= 0x41) && (*in <= 0x5A)) ||
6379 (*in == '_')) {
6380 in++;
6381 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6382 ((*in >= 0x41) && (*in <= 0x5A)) ||
6383 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006384 (*in == '_') || (*in == '.') ||
6385 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006386 in++;
6387 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6388 (*in == '[') || (*in == ']') || (*in == ':') ||
6389 (*in == '@') || (*in == '*')) {
6390 count = in - ctxt->cur;
6391 if (count == 0)
6392 return(NULL);
6393 ret = xmlStrndup(ctxt->cur, count);
6394 ctxt->cur = in;
6395 return(ret);
6396 }
6397 }
6398 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006399}
6400
Daniel Veillard2156a562001-04-28 12:24:34 +00006401
Owen Taylor3473f882001-02-23 17:55:21 +00006402/**
6403 * xmlXPathParseQName:
6404 * @ctxt: the XPath Parser context
6405 * @prefix: a xmlChar **
6406 *
6407 * parse an XML qualified name
6408 *
6409 * [NS 5] QName ::= (Prefix ':')? LocalPart
6410 *
6411 * [NS 6] Prefix ::= NCName
6412 *
6413 * [NS 7] LocalPart ::= NCName
6414 *
6415 * Returns the function returns the local part, and prefix is updated
6416 * to get the Prefix if any.
6417 */
6418
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006419static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006420xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6421 xmlChar *ret = NULL;
6422
6423 *prefix = NULL;
6424 ret = xmlXPathParseNCName(ctxt);
6425 if (CUR == ':') {
6426 *prefix = ret;
6427 NEXT;
6428 ret = xmlXPathParseNCName(ctxt);
6429 }
6430 return(ret);
6431}
6432
6433/**
6434 * xmlXPathParseName:
6435 * @ctxt: the XPath Parser context
6436 *
6437 * parse an XML name
6438 *
6439 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6440 * CombiningChar | Extender
6441 *
6442 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6443 *
6444 * Returns the namespace name or NULL
6445 */
6446
6447xmlChar *
6448xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006449 const xmlChar *in;
6450 xmlChar *ret;
6451 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006452
Daniel Veillard61d80a22001-04-27 17:13:01 +00006453 /*
6454 * Accelerator for simple ASCII names
6455 */
6456 in = ctxt->cur;
6457 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6458 ((*in >= 0x41) && (*in <= 0x5A)) ||
6459 (*in == '_') || (*in == ':')) {
6460 in++;
6461 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6462 ((*in >= 0x41) && (*in <= 0x5A)) ||
6463 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006464 (*in == '_') || (*in == '-') ||
6465 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006466 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006467 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006468 count = in - ctxt->cur;
6469 ret = xmlStrndup(ctxt->cur, count);
6470 ctxt->cur = in;
6471 return(ret);
6472 }
6473 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006474 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006475}
6476
Daniel Veillard61d80a22001-04-27 17:13:01 +00006477static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006478xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006479 xmlChar buf[XML_MAX_NAMELEN + 5];
6480 int len = 0, l;
6481 int c;
6482
6483 /*
6484 * Handler for more complex cases
6485 */
6486 c = CUR_CHAR(l);
6487 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006488 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6489 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006490 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006491 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006492 return(NULL);
6493 }
6494
6495 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6496 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6497 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006498 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006499 (IS_COMBINING(c)) ||
6500 (IS_EXTENDER(c)))) {
6501 COPY_BUF(l,buf,len,c);
6502 NEXTL(l);
6503 c = CUR_CHAR(l);
6504 if (len >= XML_MAX_NAMELEN) {
6505 /*
6506 * Okay someone managed to make a huge name, so he's ready to pay
6507 * for the processing speed.
6508 */
6509 xmlChar *buffer;
6510 int max = len * 2;
6511
6512 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6513 if (buffer == NULL) {
6514 XP_ERROR0(XPATH_MEMORY_ERROR);
6515 }
6516 memcpy(buffer, buf, len);
6517 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6518 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006519 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006520 (IS_COMBINING(c)) ||
6521 (IS_EXTENDER(c))) {
6522 if (len + 10 > max) {
6523 max *= 2;
6524 buffer = (xmlChar *) xmlRealloc(buffer,
6525 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006526 if (buffer == NULL) {
6527 XP_ERROR0(XPATH_MEMORY_ERROR);
6528 }
6529 }
6530 COPY_BUF(l,buffer,len,c);
6531 NEXTL(l);
6532 c = CUR_CHAR(l);
6533 }
6534 buffer[len] = 0;
6535 return(buffer);
6536 }
6537 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006538 if (len == 0)
6539 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006540 return(xmlStrndup(buf, len));
6541}
Owen Taylor3473f882001-02-23 17:55:21 +00006542/**
6543 * xmlXPathStringEvalNumber:
6544 * @str: A string to scan
6545 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006546 * [30a] Float ::= Number ('e' Digits?)?
6547 *
Owen Taylor3473f882001-02-23 17:55:21 +00006548 * [30] Number ::= Digits ('.' Digits?)?
6549 * | '.' Digits
6550 * [31] Digits ::= [0-9]+
6551 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006552 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006553 * In complement of the Number expression, this function also handles
6554 * negative values : '-' Number.
6555 *
6556 * Returns the double value.
6557 */
6558double
6559xmlXPathStringEvalNumber(const xmlChar *str) {
6560 const xmlChar *cur = str;
6561 double ret = 0.0;
6562 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006563 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006564 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006565 int exponent = 0;
6566 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006567#ifdef __GNUC__
6568 unsigned long tmp = 0;
6569#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006570
Owen Taylor3473f882001-02-23 17:55:21 +00006571 while (IS_BLANK(*cur)) cur++;
6572 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6573 return(xmlXPathNAN);
6574 }
6575 if (*cur == '-') {
6576 isneg = 1;
6577 cur++;
6578 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006579
6580#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006581 /*
Daniel Veillardb06c6142001-08-27 14:26:30 +00006582 * tmp is a workaround against a gcc compiler bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006583 */
Owen Taylor3473f882001-02-23 17:55:21 +00006584 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006585 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006586 ok = 1;
6587 cur++;
6588 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006589 ret = (double) tmp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006590#else
6591 while ((*cur >= '0') && (*cur <= '9')) {
6592 ret = ret * 10 + (*cur - '0');
6593 ok = 1;
6594 cur++;
6595 }
6596#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006597
Owen Taylor3473f882001-02-23 17:55:21 +00006598 if (*cur == '.') {
6599 cur++;
6600 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6601 return(xmlXPathNAN);
6602 }
6603 while ((*cur >= '0') && (*cur <= '9')) {
6604 mult /= 10;
6605 ret = ret + (*cur - '0') * mult;
6606 cur++;
6607 }
6608 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006609 if ((*cur == 'e') || (*cur == 'E')) {
6610 cur++;
6611 if (*cur == '-') {
6612 is_exponent_negative = 1;
6613 cur++;
6614 }
6615 while ((*cur >= '0') && (*cur <= '9')) {
6616 exponent = exponent * 10 + (*cur - '0');
6617 cur++;
6618 }
6619 }
Owen Taylor3473f882001-02-23 17:55:21 +00006620 while (IS_BLANK(*cur)) cur++;
6621 if (*cur != 0) return(xmlXPathNAN);
6622 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006623 if (is_exponent_negative) exponent = -exponent;
6624 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006625 return(ret);
6626}
6627
6628/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006629 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006630 * @ctxt: the XPath Parser context
6631 *
6632 * [30] Number ::= Digits ('.' Digits?)?
6633 * | '.' Digits
6634 * [31] Digits ::= [0-9]+
6635 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006636 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006637 *
6638 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006639static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006640xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6641{
Owen Taylor3473f882001-02-23 17:55:21 +00006642 double ret = 0.0;
6643 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006644 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006645 int exponent = 0;
6646 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006647
6648 CHECK_ERROR;
6649 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6650 XP_ERROR(XPATH_NUMBER_ERROR);
6651 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006652 /*
6653 * Try to work around a gcc optimizer bug
6654 */
Owen Taylor3473f882001-02-23 17:55:21 +00006655 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006656 tmp = tmp * 10 + (CUR - '0');
6657 ok = 1;
6658 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006659 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006660 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006661 if (CUR == '.') {
6662 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006663 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6664 XP_ERROR(XPATH_NUMBER_ERROR);
6665 }
6666 while ((CUR >= '0') && (CUR <= '9')) {
6667 mult /= 10;
6668 ret = ret + (CUR - '0') * mult;
6669 NEXT;
6670 }
Owen Taylor3473f882001-02-23 17:55:21 +00006671 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006672 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006673 NEXT;
6674 if (CUR == '-') {
6675 is_exponent_negative = 1;
6676 NEXT;
6677 }
6678 while ((CUR >= '0') && (CUR <= '9')) {
6679 exponent = exponent * 10 + (CUR - '0');
6680 NEXT;
6681 }
6682 if (is_exponent_negative)
6683 exponent = -exponent;
6684 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006685 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006686 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006687 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006688}
6689
6690/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006691 * xmlXPathParseLiteral:
6692 * @ctxt: the XPath Parser context
6693 *
6694 * Parse a Literal
6695 *
6696 * [29] Literal ::= '"' [^"]* '"'
6697 * | "'" [^']* "'"
6698 *
6699 * Returns the value found or NULL in case of error
6700 */
6701static xmlChar *
6702xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6703 const xmlChar *q;
6704 xmlChar *ret = NULL;
6705
6706 if (CUR == '"') {
6707 NEXT;
6708 q = CUR_PTR;
6709 while ((IS_CHAR(CUR)) && (CUR != '"'))
6710 NEXT;
6711 if (!IS_CHAR(CUR)) {
6712 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6713 } else {
6714 ret = xmlStrndup(q, CUR_PTR - q);
6715 NEXT;
6716 }
6717 } else if (CUR == '\'') {
6718 NEXT;
6719 q = CUR_PTR;
6720 while ((IS_CHAR(CUR)) && (CUR != '\''))
6721 NEXT;
6722 if (!IS_CHAR(CUR)) {
6723 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6724 } else {
6725 ret = xmlStrndup(q, CUR_PTR - q);
6726 NEXT;
6727 }
6728 } else {
6729 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6730 }
6731 return(ret);
6732}
6733
6734/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006735 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006736 * @ctxt: the XPath Parser context
6737 *
6738 * Parse a Literal and push it on the stack.
6739 *
6740 * [29] Literal ::= '"' [^"]* '"'
6741 * | "'" [^']* "'"
6742 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006743 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006744 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006745static void
6746xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006747 const xmlChar *q;
6748 xmlChar *ret = NULL;
6749
6750 if (CUR == '"') {
6751 NEXT;
6752 q = CUR_PTR;
6753 while ((IS_CHAR(CUR)) && (CUR != '"'))
6754 NEXT;
6755 if (!IS_CHAR(CUR)) {
6756 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6757 } else {
6758 ret = xmlStrndup(q, CUR_PTR - q);
6759 NEXT;
6760 }
6761 } else if (CUR == '\'') {
6762 NEXT;
6763 q = CUR_PTR;
6764 while ((IS_CHAR(CUR)) && (CUR != '\''))
6765 NEXT;
6766 if (!IS_CHAR(CUR)) {
6767 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6768 } else {
6769 ret = xmlStrndup(q, CUR_PTR - q);
6770 NEXT;
6771 }
6772 } else {
6773 XP_ERROR(XPATH_START_LITERAL_ERROR);
6774 }
6775 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006776 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6777 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006778 xmlFree(ret);
6779}
6780
6781/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006782 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006783 * @ctxt: the XPath Parser context
6784 *
6785 * Parse a VariableReference, evaluate it and push it on the stack.
6786 *
6787 * The variable bindings consist of a mapping from variable names
6788 * to variable values. The value of a variable is an object, which
6789 * of any of the types that are possible for the value of an expression,
6790 * and may also be of additional types not specified here.
6791 *
6792 * Early evaluation is possible since:
6793 * The variable bindings [...] used to evaluate a subexpression are
6794 * always the same as those used to evaluate the containing expression.
6795 *
6796 * [36] VariableReference ::= '$' QName
6797 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006798static void
6799xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006800 xmlChar *name;
6801 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006802
6803 SKIP_BLANKS;
6804 if (CUR != '$') {
6805 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6806 }
6807 NEXT;
6808 name = xmlXPathParseQName(ctxt, &prefix);
6809 if (name == NULL) {
6810 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6811 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006812 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006813 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6814 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006815 SKIP_BLANKS;
6816}
6817
6818/**
6819 * xmlXPathIsNodeType:
6820 * @ctxt: the XPath Parser context
6821 * @name: a name string
6822 *
6823 * Is the name given a NodeType one.
6824 *
6825 * [38] NodeType ::= 'comment'
6826 * | 'text'
6827 * | 'processing-instruction'
6828 * | 'node'
6829 *
6830 * Returns 1 if true 0 otherwise
6831 */
6832int
6833xmlXPathIsNodeType(const xmlChar *name) {
6834 if (name == NULL)
6835 return(0);
6836
6837 if (xmlStrEqual(name, BAD_CAST "comment"))
6838 return(1);
6839 if (xmlStrEqual(name, BAD_CAST "text"))
6840 return(1);
6841 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6842 return(1);
6843 if (xmlStrEqual(name, BAD_CAST "node"))
6844 return(1);
6845 return(0);
6846}
6847
6848/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006849 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006850 * @ctxt: the XPath Parser context
6851 *
6852 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6853 * [17] Argument ::= Expr
6854 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006855 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006856 * pushed on the stack
6857 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006858static void
6859xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006860 xmlChar *name;
6861 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006862 int nbargs = 0;
6863
6864 name = xmlXPathParseQName(ctxt, &prefix);
6865 if (name == NULL) {
6866 XP_ERROR(XPATH_EXPR_ERROR);
6867 }
6868 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006869#ifdef DEBUG_EXPR
6870 if (prefix == NULL)
6871 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6872 name);
6873 else
6874 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6875 prefix, name);
6876#endif
6877
Owen Taylor3473f882001-02-23 17:55:21 +00006878 if (CUR != '(') {
6879 XP_ERROR(XPATH_EXPR_ERROR);
6880 }
6881 NEXT;
6882 SKIP_BLANKS;
6883
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006884 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006885 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006886 int op1 = ctxt->comp->last;
6887 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006888 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006889 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006890 nbargs++;
6891 if (CUR == ')') break;
6892 if (CUR != ',') {
6893 XP_ERROR(XPATH_EXPR_ERROR);
6894 }
6895 NEXT;
6896 SKIP_BLANKS;
6897 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006898 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6899 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006900 NEXT;
6901 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006902}
6903
6904/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006905 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006906 * @ctxt: the XPath Parser context
6907 *
6908 * [15] PrimaryExpr ::= VariableReference
6909 * | '(' Expr ')'
6910 * | Literal
6911 * | Number
6912 * | FunctionCall
6913 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006914 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006915 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006916static void
6917xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006918 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006919 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006920 else if (CUR == '(') {
6921 NEXT;
6922 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006923 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006924 if (CUR != ')') {
6925 XP_ERROR(XPATH_EXPR_ERROR);
6926 }
6927 NEXT;
6928 SKIP_BLANKS;
6929 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006930 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006931 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006932 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006933 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006934 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006935 }
6936 SKIP_BLANKS;
6937}
6938
6939/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006940 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006941 * @ctxt: the XPath Parser context
6942 *
6943 * [20] FilterExpr ::= PrimaryExpr
6944 * | FilterExpr Predicate
6945 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006946 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006947 * Square brackets are used to filter expressions in the same way that
6948 * they are used in location paths. It is an error if the expression to
6949 * be filtered does not evaluate to a node-set. The context node list
6950 * used for evaluating the expression in square brackets is the node-set
6951 * to be filtered listed in document order.
6952 */
6953
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006954static void
6955xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6956 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006957 CHECK_ERROR;
6958 SKIP_BLANKS;
6959
6960 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006961 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006962 SKIP_BLANKS;
6963 }
6964
6965
6966}
6967
6968/**
6969 * xmlXPathScanName:
6970 * @ctxt: the XPath Parser context
6971 *
6972 * Trickery: parse an XML name but without consuming the input flow
6973 * Needed to avoid insanity in the parser state.
6974 *
6975 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6976 * CombiningChar | Extender
6977 *
6978 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6979 *
6980 * [6] Names ::= Name (S Name)*
6981 *
6982 * Returns the Name parsed or NULL
6983 */
6984
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006985static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006986xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6987 xmlChar buf[XML_MAX_NAMELEN];
6988 int len = 0;
6989
6990 SKIP_BLANKS;
6991 if (!IS_LETTER(CUR) && (CUR != '_') &&
6992 (CUR != ':')) {
6993 return(NULL);
6994 }
6995
6996 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6997 (NXT(len) == '.') || (NXT(len) == '-') ||
6998 (NXT(len) == '_') || (NXT(len) == ':') ||
6999 (IS_COMBINING(NXT(len))) ||
7000 (IS_EXTENDER(NXT(len)))) {
7001 buf[len] = NXT(len);
7002 len++;
7003 if (len >= XML_MAX_NAMELEN) {
7004 xmlGenericError(xmlGenericErrorContext,
7005 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7006 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7007 (NXT(len) == '.') || (NXT(len) == '-') ||
7008 (NXT(len) == '_') || (NXT(len) == ':') ||
7009 (IS_COMBINING(NXT(len))) ||
7010 (IS_EXTENDER(NXT(len))))
7011 len++;
7012 break;
7013 }
7014 }
7015 return(xmlStrndup(buf, len));
7016}
7017
7018/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007019 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007020 * @ctxt: the XPath Parser context
7021 *
7022 * [19] PathExpr ::= LocationPath
7023 * | FilterExpr
7024 * | FilterExpr '/' RelativeLocationPath
7025 * | FilterExpr '//' RelativeLocationPath
7026 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007027 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007028 * The / operator and // operators combine an arbitrary expression
7029 * and a relative location path. It is an error if the expression
7030 * does not evaluate to a node-set.
7031 * The / operator does composition in the same way as when / is
7032 * used in a location path. As in location paths, // is short for
7033 * /descendant-or-self::node()/.
7034 */
7035
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007036static void
7037xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007038 int lc = 1; /* Should we branch to LocationPath ? */
7039 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7040
7041 SKIP_BLANKS;
7042 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7043 (CUR == '\'') || (CUR == '"')) {
7044 lc = 0;
7045 } else if (CUR == '*') {
7046 /* relative or absolute location path */
7047 lc = 1;
7048 } else if (CUR == '/') {
7049 /* relative or absolute location path */
7050 lc = 1;
7051 } else if (CUR == '@') {
7052 /* relative abbreviated attribute location path */
7053 lc = 1;
7054 } else if (CUR == '.') {
7055 /* relative abbreviated attribute location path */
7056 lc = 1;
7057 } else {
7058 /*
7059 * Problem is finding if we have a name here whether it's:
7060 * - a nodetype
7061 * - a function call in which case it's followed by '('
7062 * - an axis in which case it's followed by ':'
7063 * - a element name
7064 * We do an a priori analysis here rather than having to
7065 * maintain parsed token content through the recursive function
7066 * calls. This looks uglier but makes the code quite easier to
7067 * read/write/debug.
7068 */
7069 SKIP_BLANKS;
7070 name = xmlXPathScanName(ctxt);
7071 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7072#ifdef DEBUG_STEP
7073 xmlGenericError(xmlGenericErrorContext,
7074 "PathExpr: Axis\n");
7075#endif
7076 lc = 1;
7077 xmlFree(name);
7078 } else if (name != NULL) {
7079 int len =xmlStrlen(name);
7080 int blank = 0;
7081
7082
7083 while (NXT(len) != 0) {
7084 if (NXT(len) == '/') {
7085 /* element name */
7086#ifdef DEBUG_STEP
7087 xmlGenericError(xmlGenericErrorContext,
7088 "PathExpr: AbbrRelLocation\n");
7089#endif
7090 lc = 1;
7091 break;
7092 } else if (IS_BLANK(NXT(len))) {
7093 /* skip to next */
7094 blank = 1;
7095 } else if (NXT(len) == ':') {
7096#ifdef DEBUG_STEP
7097 xmlGenericError(xmlGenericErrorContext,
7098 "PathExpr: AbbrRelLocation\n");
7099#endif
7100 lc = 1;
7101 break;
7102 } else if ((NXT(len) == '(')) {
7103 /* Note Type or Function */
7104 if (xmlXPathIsNodeType(name)) {
7105#ifdef DEBUG_STEP
7106 xmlGenericError(xmlGenericErrorContext,
7107 "PathExpr: Type search\n");
7108#endif
7109 lc = 1;
7110 } else {
7111#ifdef DEBUG_STEP
7112 xmlGenericError(xmlGenericErrorContext,
7113 "PathExpr: function call\n");
7114#endif
7115 lc = 0;
7116 }
7117 break;
7118 } else if ((NXT(len) == '[')) {
7119 /* element name */
7120#ifdef DEBUG_STEP
7121 xmlGenericError(xmlGenericErrorContext,
7122 "PathExpr: AbbrRelLocation\n");
7123#endif
7124 lc = 1;
7125 break;
7126 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7127 (NXT(len) == '=')) {
7128 lc = 1;
7129 break;
7130 } else {
7131 lc = 1;
7132 break;
7133 }
7134 len++;
7135 }
7136 if (NXT(len) == 0) {
7137#ifdef DEBUG_STEP
7138 xmlGenericError(xmlGenericErrorContext,
7139 "PathExpr: AbbrRelLocation\n");
7140#endif
7141 /* element name */
7142 lc = 1;
7143 }
7144 xmlFree(name);
7145 } else {
7146 /* make sure all cases are covered explicitely */
7147 XP_ERROR(XPATH_EXPR_ERROR);
7148 }
7149 }
7150
7151 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007152 if (CUR == '/') {
7153 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7154 } else {
7155 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007156 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007157 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007158 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007159 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007160 CHECK_ERROR;
7161 if ((CUR == '/') && (NXT(1) == '/')) {
7162 SKIP(2);
7163 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007164
7165 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7166 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7167 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7168
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007169 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007170 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007171 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007172 }
7173 }
7174 SKIP_BLANKS;
7175}
7176
7177/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007178 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007179 * @ctxt: the XPath Parser context
7180 *
7181 * [18] UnionExpr ::= PathExpr
7182 * | UnionExpr '|' PathExpr
7183 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007184 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007185 */
7186
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007187static void
7188xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7189 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007190 CHECK_ERROR;
7191 SKIP_BLANKS;
7192 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007193 int op1 = ctxt->comp->last;
7194 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007195
7196 NEXT;
7197 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007198 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007199
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007200 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7201
Owen Taylor3473f882001-02-23 17:55:21 +00007202 SKIP_BLANKS;
7203 }
Owen Taylor3473f882001-02-23 17:55:21 +00007204}
7205
7206/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007207 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007208 * @ctxt: the XPath Parser context
7209 *
7210 * [27] UnaryExpr ::= UnionExpr
7211 * | '-' UnaryExpr
7212 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007213 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007214 */
7215
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007216static void
7217xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007218 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007219 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007220
7221 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007222 while (CUR == '-') {
7223 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007224 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007225 NEXT;
7226 SKIP_BLANKS;
7227 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007228
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007229 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007230 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007231 if (found) {
7232 if (minus)
7233 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7234 else
7235 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007236 }
7237}
7238
7239/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007240 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007241 * @ctxt: the XPath Parser context
7242 *
7243 * [26] MultiplicativeExpr ::= UnaryExpr
7244 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7245 * | MultiplicativeExpr 'div' UnaryExpr
7246 * | MultiplicativeExpr 'mod' UnaryExpr
7247 * [34] MultiplyOperator ::= '*'
7248 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007249 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007250 */
7251
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007252static void
7253xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7254 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007255 CHECK_ERROR;
7256 SKIP_BLANKS;
7257 while ((CUR == '*') ||
7258 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7259 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7260 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007261 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007262
7263 if (CUR == '*') {
7264 op = 0;
7265 NEXT;
7266 } else if (CUR == 'd') {
7267 op = 1;
7268 SKIP(3);
7269 } else if (CUR == 'm') {
7270 op = 2;
7271 SKIP(3);
7272 }
7273 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007274 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007275 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007276 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007277 SKIP_BLANKS;
7278 }
7279}
7280
7281/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007282 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007283 * @ctxt: the XPath Parser context
7284 *
7285 * [25] AdditiveExpr ::= MultiplicativeExpr
7286 * | AdditiveExpr '+' MultiplicativeExpr
7287 * | AdditiveExpr '-' MultiplicativeExpr
7288 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007289 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007290 */
7291
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007292static void
7293xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007294
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007295 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007296 CHECK_ERROR;
7297 SKIP_BLANKS;
7298 while ((CUR == '+') || (CUR == '-')) {
7299 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007300 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007301
7302 if (CUR == '+') plus = 1;
7303 else plus = 0;
7304 NEXT;
7305 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007306 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007307 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007308 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007309 SKIP_BLANKS;
7310 }
7311}
7312
7313/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007314 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007315 * @ctxt: the XPath Parser context
7316 *
7317 * [24] RelationalExpr ::= AdditiveExpr
7318 * | RelationalExpr '<' AdditiveExpr
7319 * | RelationalExpr '>' AdditiveExpr
7320 * | RelationalExpr '<=' AdditiveExpr
7321 * | RelationalExpr '>=' AdditiveExpr
7322 *
7323 * A <= B > C is allowed ? Answer from James, yes with
7324 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7325 * which is basically what got implemented.
7326 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007327 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007328 * on the stack
7329 */
7330
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007331static void
7332xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7333 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007334 CHECK_ERROR;
7335 SKIP_BLANKS;
7336 while ((CUR == '<') ||
7337 (CUR == '>') ||
7338 ((CUR == '<') && (NXT(1) == '=')) ||
7339 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007340 int inf, strict;
7341 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007342
7343 if (CUR == '<') inf = 1;
7344 else inf = 0;
7345 if (NXT(1) == '=') strict = 0;
7346 else strict = 1;
7347 NEXT;
7348 if (!strict) NEXT;
7349 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007350 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007351 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007352 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007353 SKIP_BLANKS;
7354 }
7355}
7356
7357/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007358 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007359 * @ctxt: the XPath Parser context
7360 *
7361 * [23] EqualityExpr ::= RelationalExpr
7362 * | EqualityExpr '=' RelationalExpr
7363 * | EqualityExpr '!=' RelationalExpr
7364 *
7365 * A != B != C is allowed ? Answer from James, yes with
7366 * (RelationalExpr = RelationalExpr) = RelationalExpr
7367 * (RelationalExpr != RelationalExpr) != RelationalExpr
7368 * which is basically what got implemented.
7369 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007370 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007371 *
7372 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007373static void
7374xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7375 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007376 CHECK_ERROR;
7377 SKIP_BLANKS;
7378 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007379 int eq;
7380 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007381
7382 if (CUR == '=') eq = 1;
7383 else eq = 0;
7384 NEXT;
7385 if (!eq) NEXT;
7386 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007387 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007388 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007389 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007390 SKIP_BLANKS;
7391 }
7392}
7393
7394/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007395 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007396 * @ctxt: the XPath Parser context
7397 *
7398 * [22] AndExpr ::= EqualityExpr
7399 * | AndExpr 'and' EqualityExpr
7400 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007401 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007402 *
7403 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007404static void
7405xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7406 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007407 CHECK_ERROR;
7408 SKIP_BLANKS;
7409 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007410 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007411 SKIP(3);
7412 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007413 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007414 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007415 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007416 SKIP_BLANKS;
7417 }
7418}
7419
7420/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007421 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007422 * @ctxt: the XPath Parser context
7423 *
7424 * [14] Expr ::= OrExpr
7425 * [21] OrExpr ::= AndExpr
7426 * | OrExpr 'or' AndExpr
7427 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007428 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007429 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007430static void
7431xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7432 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007433 CHECK_ERROR;
7434 SKIP_BLANKS;
7435 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007436 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007437 SKIP(2);
7438 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007439 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007440 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007441 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7442 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007443 SKIP_BLANKS;
7444 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007445 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7446 /* more ops could be optimized too */
7447 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7448 }
Owen Taylor3473f882001-02-23 17:55:21 +00007449}
7450
7451/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007452 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007453 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007454 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007455 *
7456 * [8] Predicate ::= '[' PredicateExpr ']'
7457 * [9] PredicateExpr ::= Expr
7458 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007459 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007460 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007461static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007462xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007463 int op1 = ctxt->comp->last;
7464
7465 SKIP_BLANKS;
7466 if (CUR != '[') {
7467 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7468 }
7469 NEXT;
7470 SKIP_BLANKS;
7471
7472 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007473 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007474 CHECK_ERROR;
7475
7476 if (CUR != ']') {
7477 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7478 }
7479
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007480 if (filter)
7481 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7482 else
7483 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007484
7485 NEXT;
7486 SKIP_BLANKS;
7487}
7488
7489/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007490 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007491 * @ctxt: the XPath Parser context
7492 * @test: pointer to a xmlXPathTestVal
7493 * @type: pointer to a xmlXPathTypeVal
7494 * @prefix: placeholder for a possible name prefix
7495 *
7496 * [7] NodeTest ::= NameTest
7497 * | NodeType '(' ')'
7498 * | 'processing-instruction' '(' Literal ')'
7499 *
7500 * [37] NameTest ::= '*'
7501 * | NCName ':' '*'
7502 * | QName
7503 * [38] NodeType ::= 'comment'
7504 * | 'text'
7505 * | 'processing-instruction'
7506 * | 'node'
7507 *
7508 * Returns the name found and update @test, @type and @prefix appropriately
7509 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007510static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007511xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7512 xmlXPathTypeVal *type, const xmlChar **prefix,
7513 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007514 int blanks;
7515
7516 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7517 STRANGE;
7518 return(NULL);
7519 }
7520 *type = 0;
7521 *test = 0;
7522 *prefix = NULL;
7523 SKIP_BLANKS;
7524
7525 if ((name == NULL) && (CUR == '*')) {
7526 /*
7527 * All elements
7528 */
7529 NEXT;
7530 *test = NODE_TEST_ALL;
7531 return(NULL);
7532 }
7533
7534 if (name == NULL)
7535 name = xmlXPathParseNCName(ctxt);
7536 if (name == NULL) {
7537 XP_ERROR0(XPATH_EXPR_ERROR);
7538 }
7539
7540 blanks = IS_BLANK(CUR);
7541 SKIP_BLANKS;
7542 if (CUR == '(') {
7543 NEXT;
7544 /*
7545 * NodeType or PI search
7546 */
7547 if (xmlStrEqual(name, BAD_CAST "comment"))
7548 *type = NODE_TYPE_COMMENT;
7549 else if (xmlStrEqual(name, BAD_CAST "node"))
7550 *type = NODE_TYPE_NODE;
7551 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7552 *type = NODE_TYPE_PI;
7553 else if (xmlStrEqual(name, BAD_CAST "text"))
7554 *type = NODE_TYPE_TEXT;
7555 else {
7556 if (name != NULL)
7557 xmlFree(name);
7558 XP_ERROR0(XPATH_EXPR_ERROR);
7559 }
7560
7561 *test = NODE_TEST_TYPE;
7562
7563 SKIP_BLANKS;
7564 if (*type == NODE_TYPE_PI) {
7565 /*
7566 * Specific case: search a PI by name.
7567 */
Owen Taylor3473f882001-02-23 17:55:21 +00007568 if (name != NULL)
7569 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007570 name = NULL;
7571 if (CUR != ')') {
7572 name = xmlXPathParseLiteral(ctxt);
7573 CHECK_ERROR 0;
7574 SKIP_BLANKS;
7575 }
Owen Taylor3473f882001-02-23 17:55:21 +00007576 }
7577 if (CUR != ')') {
7578 if (name != NULL)
7579 xmlFree(name);
7580 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7581 }
7582 NEXT;
7583 return(name);
7584 }
7585 *test = NODE_TEST_NAME;
7586 if ((!blanks) && (CUR == ':')) {
7587 NEXT;
7588
7589 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007590 * Since currently the parser context don't have a
7591 * namespace list associated:
7592 * The namespace name for this prefix can be computed
7593 * only at evaluation time. The compilation is done
7594 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007595 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007596#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007597 *prefix = xmlXPathNsLookup(ctxt->context, name);
7598 if (name != NULL)
7599 xmlFree(name);
7600 if (*prefix == NULL) {
7601 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7602 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007603#else
7604 *prefix = name;
7605#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007606
7607 if (CUR == '*') {
7608 /*
7609 * All elements
7610 */
7611 NEXT;
7612 *test = NODE_TEST_ALL;
7613 return(NULL);
7614 }
7615
7616 name = xmlXPathParseNCName(ctxt);
7617 if (name == NULL) {
7618 XP_ERROR0(XPATH_EXPR_ERROR);
7619 }
7620 }
7621 return(name);
7622}
7623
7624/**
7625 * xmlXPathIsAxisName:
7626 * @name: a preparsed name token
7627 *
7628 * [6] AxisName ::= 'ancestor'
7629 * | 'ancestor-or-self'
7630 * | 'attribute'
7631 * | 'child'
7632 * | 'descendant'
7633 * | 'descendant-or-self'
7634 * | 'following'
7635 * | 'following-sibling'
7636 * | 'namespace'
7637 * | 'parent'
7638 * | 'preceding'
7639 * | 'preceding-sibling'
7640 * | 'self'
7641 *
7642 * Returns the axis or 0
7643 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007644static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007645xmlXPathIsAxisName(const xmlChar *name) {
7646 xmlXPathAxisVal ret = 0;
7647 switch (name[0]) {
7648 case 'a':
7649 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7650 ret = AXIS_ANCESTOR;
7651 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7652 ret = AXIS_ANCESTOR_OR_SELF;
7653 if (xmlStrEqual(name, BAD_CAST "attribute"))
7654 ret = AXIS_ATTRIBUTE;
7655 break;
7656 case 'c':
7657 if (xmlStrEqual(name, BAD_CAST "child"))
7658 ret = AXIS_CHILD;
7659 break;
7660 case 'd':
7661 if (xmlStrEqual(name, BAD_CAST "descendant"))
7662 ret = AXIS_DESCENDANT;
7663 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7664 ret = AXIS_DESCENDANT_OR_SELF;
7665 break;
7666 case 'f':
7667 if (xmlStrEqual(name, BAD_CAST "following"))
7668 ret = AXIS_FOLLOWING;
7669 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7670 ret = AXIS_FOLLOWING_SIBLING;
7671 break;
7672 case 'n':
7673 if (xmlStrEqual(name, BAD_CAST "namespace"))
7674 ret = AXIS_NAMESPACE;
7675 break;
7676 case 'p':
7677 if (xmlStrEqual(name, BAD_CAST "parent"))
7678 ret = AXIS_PARENT;
7679 if (xmlStrEqual(name, BAD_CAST "preceding"))
7680 ret = AXIS_PRECEDING;
7681 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7682 ret = AXIS_PRECEDING_SIBLING;
7683 break;
7684 case 's':
7685 if (xmlStrEqual(name, BAD_CAST "self"))
7686 ret = AXIS_SELF;
7687 break;
7688 }
7689 return(ret);
7690}
7691
7692/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007693 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007694 * @ctxt: the XPath Parser context
7695 *
7696 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7697 * | AbbreviatedStep
7698 *
7699 * [12] AbbreviatedStep ::= '.' | '..'
7700 *
7701 * [5] AxisSpecifier ::= AxisName '::'
7702 * | AbbreviatedAxisSpecifier
7703 *
7704 * [13] AbbreviatedAxisSpecifier ::= '@'?
7705 *
7706 * Modified for XPtr range support as:
7707 *
7708 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7709 * | AbbreviatedStep
7710 * | 'range-to' '(' Expr ')' Predicate*
7711 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007712 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007713 * A location step of . is short for self::node(). This is
7714 * particularly useful in conjunction with //. For example, the
7715 * location path .//para is short for
7716 * self::node()/descendant-or-self::node()/child::para
7717 * and so will select all para descendant elements of the context
7718 * node.
7719 * Similarly, a location step of .. is short for parent::node().
7720 * For example, ../title is short for parent::node()/child::title
7721 * and so will select the title children of the parent of the context
7722 * node.
7723 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007724static void
7725xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007726#ifdef LIBXML_XPTR_ENABLED
7727 int rangeto = 0;
7728 int op2 = -1;
7729#endif
7730
Owen Taylor3473f882001-02-23 17:55:21 +00007731 SKIP_BLANKS;
7732 if ((CUR == '.') && (NXT(1) == '.')) {
7733 SKIP(2);
7734 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007735 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7736 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007737 } else if (CUR == '.') {
7738 NEXT;
7739 SKIP_BLANKS;
7740 } else {
7741 xmlChar *name = NULL;
7742 const xmlChar *prefix = NULL;
7743 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007744 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007745 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007746 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007747
7748 /*
7749 * The modification needed for XPointer change to the production
7750 */
7751#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007752 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007753 name = xmlXPathParseNCName(ctxt);
7754 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007755 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007756 xmlFree(name);
7757 SKIP_BLANKS;
7758 if (CUR != '(') {
7759 XP_ERROR(XPATH_EXPR_ERROR);
7760 }
7761 NEXT;
7762 SKIP_BLANKS;
7763
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007764 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007765 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007766 CHECK_ERROR;
7767
7768 SKIP_BLANKS;
7769 if (CUR != ')') {
7770 XP_ERROR(XPATH_EXPR_ERROR);
7771 }
7772 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007773 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007774 goto eval_predicates;
7775 }
7776 }
7777#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007778 if (CUR == '*') {
7779 axis = AXIS_CHILD;
7780 } else {
7781 if (name == NULL)
7782 name = xmlXPathParseNCName(ctxt);
7783 if (name != NULL) {
7784 axis = xmlXPathIsAxisName(name);
7785 if (axis != 0) {
7786 SKIP_BLANKS;
7787 if ((CUR == ':') && (NXT(1) == ':')) {
7788 SKIP(2);
7789 xmlFree(name);
7790 name = NULL;
7791 } else {
7792 /* an element name can conflict with an axis one :-\ */
7793 axis = AXIS_CHILD;
7794 }
Owen Taylor3473f882001-02-23 17:55:21 +00007795 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007796 axis = AXIS_CHILD;
7797 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007798 } else if (CUR == '@') {
7799 NEXT;
7800 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007801 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007802 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007803 }
Owen Taylor3473f882001-02-23 17:55:21 +00007804 }
7805
7806 CHECK_ERROR;
7807
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007808 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007809 if (test == 0)
7810 return;
7811
7812#ifdef DEBUG_STEP
7813 xmlGenericError(xmlGenericErrorContext,
7814 "Basis : computing new set\n");
7815#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007816
Owen Taylor3473f882001-02-23 17:55:21 +00007817#ifdef DEBUG_STEP
7818 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007819 if (ctxt->value == NULL)
7820 xmlGenericError(xmlGenericErrorContext, "no value\n");
7821 else if (ctxt->value->nodesetval == NULL)
7822 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7823 else
7824 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007825#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007826
7827eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007828 op1 = ctxt->comp->last;
7829 ctxt->comp->last = -1;
7830
Owen Taylor3473f882001-02-23 17:55:21 +00007831 SKIP_BLANKS;
7832 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007833 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007834 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007835
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007836#ifdef LIBXML_XPTR_ENABLED
7837 if (rangeto) {
7838 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7839 } else
7840#endif
7841 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7842 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007843
Owen Taylor3473f882001-02-23 17:55:21 +00007844 }
7845#ifdef DEBUG_STEP
7846 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007847 if (ctxt->value == NULL)
7848 xmlGenericError(xmlGenericErrorContext, "no value\n");
7849 else if (ctxt->value->nodesetval == NULL)
7850 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7851 else
7852 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7853 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007854#endif
7855}
7856
7857/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007858 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007859 * @ctxt: the XPath Parser context
7860 *
7861 * [3] RelativeLocationPath ::= Step
7862 * | RelativeLocationPath '/' Step
7863 * | AbbreviatedRelativeLocationPath
7864 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7865 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007866 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007867 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007868static void
Owen Taylor3473f882001-02-23 17:55:21 +00007869#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007870xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007871#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007872xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007873#endif
7874(xmlXPathParserContextPtr ctxt) {
7875 SKIP_BLANKS;
7876 if ((CUR == '/') && (NXT(1) == '/')) {
7877 SKIP(2);
7878 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007879 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7880 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007881 } else if (CUR == '/') {
7882 NEXT;
7883 SKIP_BLANKS;
7884 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007885 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007886 SKIP_BLANKS;
7887 while (CUR == '/') {
7888 if ((CUR == '/') && (NXT(1) == '/')) {
7889 SKIP(2);
7890 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007891 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007892 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007893 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007894 } else if (CUR == '/') {
7895 NEXT;
7896 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007897 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007898 }
7899 SKIP_BLANKS;
7900 }
7901}
7902
7903/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007904 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007905 * @ctxt: the XPath Parser context
7906 *
7907 * [1] LocationPath ::= RelativeLocationPath
7908 * | AbsoluteLocationPath
7909 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7910 * | AbbreviatedAbsoluteLocationPath
7911 * [10] AbbreviatedAbsoluteLocationPath ::=
7912 * '//' RelativeLocationPath
7913 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007914 * Compile a location path
7915 *
Owen Taylor3473f882001-02-23 17:55:21 +00007916 * // is short for /descendant-or-self::node()/. For example,
7917 * //para is short for /descendant-or-self::node()/child::para and
7918 * so will select any para element in the document (even a para element
7919 * that is a document element will be selected by //para since the
7920 * document element node is a child of the root node); div//para is
7921 * short for div/descendant-or-self::node()/child::para and so will
7922 * select all para descendants of div children.
7923 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007924static void
7925xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007926 SKIP_BLANKS;
7927 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007928 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007929 } else {
7930 while (CUR == '/') {
7931 if ((CUR == '/') && (NXT(1) == '/')) {
7932 SKIP(2);
7933 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007934 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7935 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007936 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007937 } else if (CUR == '/') {
7938 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007939 SKIP_BLANKS;
7940 if ((CUR != 0 ) &&
7941 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7942 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007943 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007944 }
7945 }
7946 }
7947}
7948
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007949/************************************************************************
7950 * *
7951 * XPath precompiled expression evaluation *
7952 * *
7953 ************************************************************************/
7954
Daniel Veillardf06307e2001-07-03 10:35:50 +00007955static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007956xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7957
7958/**
7959 * xmlXPathNodeCollectAndTest:
7960 * @ctxt: the XPath Parser context
7961 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007962 * @first: pointer to the first element in document order
7963 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007964 *
7965 * This is the function implementing a step: based on the current list
7966 * of nodes, it builds up a new list, looking at all nodes under that
7967 * axis and selecting them it also do the predicate filtering
7968 *
7969 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007970 *
7971 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007972 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007973static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007974xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007975 xmlXPathStepOpPtr op,
7976 xmlNodePtr * first, xmlNodePtr * last)
7977{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007978 xmlXPathAxisVal axis = op->value;
7979 xmlXPathTestVal test = op->value2;
7980 xmlXPathTypeVal type = op->value3;
7981 const xmlChar *prefix = op->value4;
7982 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007983 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007984
7985#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007986 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007987#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007988 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007989 xmlNodeSetPtr ret, list;
7990 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007991 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007992 xmlNodePtr cur = NULL;
7993 xmlXPathObjectPtr obj;
7994 xmlNodeSetPtr nodelist;
7995 xmlNodePtr tmp;
7996
Daniel Veillardf06307e2001-07-03 10:35:50 +00007997 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007998 obj = valuePop(ctxt);
7999 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008000 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008001 URI = xmlXPathNsLookup(ctxt->context, prefix);
8002 if (URI == NULL)
8003 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008004 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008005#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008006 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008007#endif
8008 switch (axis) {
8009 case AXIS_ANCESTOR:
8010#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008011 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008012#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008013 first = NULL;
8014 next = xmlXPathNextAncestor;
8015 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008016 case AXIS_ANCESTOR_OR_SELF:
8017#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008018 xmlGenericError(xmlGenericErrorContext,
8019 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008020#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008021 first = NULL;
8022 next = xmlXPathNextAncestorOrSelf;
8023 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008024 case AXIS_ATTRIBUTE:
8025#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008026 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008027#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008028 first = NULL;
8029 last = NULL;
8030 next = xmlXPathNextAttribute;
8031 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008032 case AXIS_CHILD:
8033#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008034 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008035#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008036 last = NULL;
8037 next = xmlXPathNextChild;
8038 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008039 case AXIS_DESCENDANT:
8040#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008041 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008042#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008043 last = NULL;
8044 next = xmlXPathNextDescendant;
8045 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008046 case AXIS_DESCENDANT_OR_SELF:
8047#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008048 xmlGenericError(xmlGenericErrorContext,
8049 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008050#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008051 last = NULL;
8052 next = xmlXPathNextDescendantOrSelf;
8053 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008054 case AXIS_FOLLOWING:
8055#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008056 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008057#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008058 last = NULL;
8059 next = xmlXPathNextFollowing;
8060 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008061 case AXIS_FOLLOWING_SIBLING:
8062#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008063 xmlGenericError(xmlGenericErrorContext,
8064 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008065#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008066 last = NULL;
8067 next = xmlXPathNextFollowingSibling;
8068 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008069 case AXIS_NAMESPACE:
8070#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008071 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008072#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008073 first = NULL;
8074 last = NULL;
8075 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8076 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008077 case AXIS_PARENT:
8078#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008079 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008080#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008081 first = NULL;
8082 next = xmlXPathNextParent;
8083 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008084 case AXIS_PRECEDING:
8085#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008086 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008087#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008088 first = NULL;
8089 next = xmlXPathNextPrecedingInternal;
8090 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008091 case AXIS_PRECEDING_SIBLING:
8092#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008093 xmlGenericError(xmlGenericErrorContext,
8094 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008095#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008096 first = NULL;
8097 next = xmlXPathNextPrecedingSibling;
8098 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008099 case AXIS_SELF:
8100#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008101 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008102#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008103 first = NULL;
8104 last = NULL;
8105 next = xmlXPathNextSelf;
8106 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008107 }
8108 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008109 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008110
8111 nodelist = obj->nodesetval;
8112 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008113 xmlXPathFreeObject(obj);
8114 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8115 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008116 }
8117 addNode = xmlXPathNodeSetAddUnique;
8118 ret = NULL;
8119#ifdef DEBUG_STEP
8120 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008121 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008122 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008123 case NODE_TEST_NONE:
8124 xmlGenericError(xmlGenericErrorContext,
8125 " searching for none !!!\n");
8126 break;
8127 case NODE_TEST_TYPE:
8128 xmlGenericError(xmlGenericErrorContext,
8129 " searching for type %d\n", type);
8130 break;
8131 case NODE_TEST_PI:
8132 xmlGenericError(xmlGenericErrorContext,
8133 " searching for PI !!!\n");
8134 break;
8135 case NODE_TEST_ALL:
8136 xmlGenericError(xmlGenericErrorContext,
8137 " searching for *\n");
8138 break;
8139 case NODE_TEST_NS:
8140 xmlGenericError(xmlGenericErrorContext,
8141 " searching for namespace %s\n",
8142 prefix);
8143 break;
8144 case NODE_TEST_NAME:
8145 xmlGenericError(xmlGenericErrorContext,
8146 " searching for name %s\n", name);
8147 if (prefix != NULL)
8148 xmlGenericError(xmlGenericErrorContext,
8149 " with namespace %s\n", prefix);
8150 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008151 }
8152 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8153#endif
8154 /*
8155 * 2.3 Node Tests
8156 * - For the attribute axis, the principal node type is attribute.
8157 * - For the namespace axis, the principal node type is namespace.
8158 * - For other axes, the principal node type is element.
8159 *
8160 * A node test * is true for any node of the
8161 * principal node type. For example, child::* willi
8162 * select all element children of the context node
8163 */
8164 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008165 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008166 ctxt->context->node = nodelist->nodeTab[i];
8167
Daniel Veillardf06307e2001-07-03 10:35:50 +00008168 cur = NULL;
8169 list = xmlXPathNodeSetCreate(NULL);
8170 do {
8171 cur = next(ctxt, cur);
8172 if (cur == NULL)
8173 break;
8174 if ((first != NULL) && (*first == cur))
8175 break;
8176 if (((t % 256) == 0) &&
8177 (first != NULL) && (*first != NULL) &&
8178 (xmlXPathCmpNodes(*first, cur) >= 0))
8179 break;
8180 if ((last != NULL) && (*last == cur))
8181 break;
8182 if (((t % 256) == 0) &&
8183 (last != NULL) && (*last != NULL) &&
8184 (xmlXPathCmpNodes(cur, *last) >= 0))
8185 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008186 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008187#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008188 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8189#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008190 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008191 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008192 ctxt->context->node = tmp;
8193 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008194 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008195 if ((cur->type == type) ||
8196 ((type == NODE_TYPE_NODE) &&
8197 ((cur->type == XML_DOCUMENT_NODE) ||
8198 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8199 (cur->type == XML_ELEMENT_NODE) ||
8200 (cur->type == XML_PI_NODE) ||
8201 (cur->type == XML_COMMENT_NODE) ||
8202 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008203 (cur->type == XML_TEXT_NODE))) ||
8204 ((type == NODE_TYPE_TEXT) &&
8205 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008206#ifdef DEBUG_STEP
8207 n++;
8208#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008209 addNode(list, cur);
8210 }
8211 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008212 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008213 if (cur->type == XML_PI_NODE) {
8214 if ((name != NULL) &&
8215 (!xmlStrEqual(name, cur->name)))
8216 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008217#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008218 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008219#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008220 addNode(list, cur);
8221 }
8222 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008223 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008224 if (axis == AXIS_ATTRIBUTE) {
8225 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008226#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008227 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008228#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008229 addNode(list, cur);
8230 }
8231 } else if (axis == AXIS_NAMESPACE) {
8232 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008233#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008234 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008235#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008236 addNode(list, cur);
8237 }
8238 } else {
8239 if (cur->type == XML_ELEMENT_NODE) {
8240 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008241#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008242 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008243#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008244 addNode(list, cur);
8245 } else if ((cur->ns != NULL) &&
8246 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008247#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008248 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008249#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008250 addNode(list, cur);
8251 }
8252 }
8253 }
8254 break;
8255 case NODE_TEST_NS:{
8256 TODO;
8257 break;
8258 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008259 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008260 switch (cur->type) {
8261 case XML_ELEMENT_NODE:
8262 if (xmlStrEqual(name, cur->name)) {
8263 if (prefix == NULL) {
8264 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008265#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008266 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008267#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008268 addNode(list, cur);
8269 }
8270 } else {
8271 if ((cur->ns != NULL) &&
8272 (xmlStrEqual(URI,
8273 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008274#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008275 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008276#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008277 addNode(list, cur);
8278 }
8279 }
8280 }
8281 break;
8282 case XML_ATTRIBUTE_NODE:{
8283 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008284
Daniel Veillardf06307e2001-07-03 10:35:50 +00008285 if (xmlStrEqual(name, attr->name)) {
8286 if (prefix == NULL) {
8287 if ((attr->ns == NULL) ||
8288 (attr->ns->prefix == NULL)) {
8289#ifdef DEBUG_STEP
8290 n++;
8291#endif
8292 addNode(list,
8293 (xmlNodePtr) attr);
8294 }
8295 } else {
8296 if ((attr->ns != NULL) &&
8297 (xmlStrEqual(URI,
8298 attr->ns->
8299 href))) {
8300#ifdef DEBUG_STEP
8301 n++;
8302#endif
8303 addNode(list,
8304 (xmlNodePtr) attr);
8305 }
8306 }
8307 }
8308 break;
8309 }
8310 case XML_NAMESPACE_DECL:
8311 if (cur->type == XML_NAMESPACE_DECL) {
8312 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008313
Daniel Veillardf06307e2001-07-03 10:35:50 +00008314 if ((ns->prefix != NULL) && (name != NULL)
8315 && (xmlStrEqual(ns->prefix, name))) {
8316#ifdef DEBUG_STEP
8317 n++;
8318#endif
8319 addNode(list, cur);
8320 }
8321 }
8322 break;
8323 default:
8324 break;
8325 }
8326 break;
8327 break;
8328 }
8329 } while (cur != NULL);
8330
8331 /*
8332 * If there is some predicate filtering do it now
8333 */
8334 if (op->ch2 != -1) {
8335 xmlXPathObjectPtr obj2;
8336
8337 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8338 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8339 CHECK_TYPE0(XPATH_NODESET);
8340 obj2 = valuePop(ctxt);
8341 list = obj2->nodesetval;
8342 obj2->nodesetval = NULL;
8343 xmlXPathFreeObject(obj2);
8344 }
8345 if (ret == NULL) {
8346 ret = list;
8347 } else {
8348 ret = xmlXPathNodeSetMerge(ret, list);
8349 xmlXPathFreeNodeSet(list);
8350 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008351 }
8352 ctxt->context->node = tmp;
8353#ifdef DEBUG_STEP
8354 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008355 "\nExamined %d nodes, found %d nodes at that step\n",
8356 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008357#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008358 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008359 if ((obj->boolval) && (obj->user != NULL)) {
8360 ctxt->value->boolval = 1;
8361 ctxt->value->user = obj->user;
8362 obj->user = NULL;
8363 obj->boolval = 0;
8364 }
8365 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008366 return(t);
8367}
8368
8369/**
8370 * xmlXPathNodeCollectAndTestNth:
8371 * @ctxt: the XPath Parser context
8372 * @op: the XPath precompiled step operation
8373 * @indx: the index to collect
8374 * @first: pointer to the first element in document order
8375 * @last: pointer to the last element in document order
8376 *
8377 * This is the function implementing a step: based on the current list
8378 * of nodes, it builds up a new list, looking at all nodes under that
8379 * axis and selecting them it also do the predicate filtering
8380 *
8381 * Pushes the new NodeSet resulting from the search.
8382 * Returns the number of node traversed
8383 */
8384static int
8385xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8386 xmlXPathStepOpPtr op, int indx,
8387 xmlNodePtr * first, xmlNodePtr * last)
8388{
8389 xmlXPathAxisVal axis = op->value;
8390 xmlXPathTestVal test = op->value2;
8391 xmlXPathTypeVal type = op->value3;
8392 const xmlChar *prefix = op->value4;
8393 const xmlChar *name = op->value5;
8394 const xmlChar *URI = NULL;
8395 int n = 0, t = 0;
8396
8397 int i;
8398 xmlNodeSetPtr list;
8399 xmlXPathTraversalFunction next = NULL;
8400 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8401 xmlNodePtr cur = NULL;
8402 xmlXPathObjectPtr obj;
8403 xmlNodeSetPtr nodelist;
8404 xmlNodePtr tmp;
8405
8406 CHECK_TYPE0(XPATH_NODESET);
8407 obj = valuePop(ctxt);
8408 addNode = xmlXPathNodeSetAdd;
8409 if (prefix != NULL) {
8410 URI = xmlXPathNsLookup(ctxt->context, prefix);
8411 if (URI == NULL)
8412 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8413 }
8414#ifdef DEBUG_STEP_NTH
8415 xmlGenericError(xmlGenericErrorContext, "new step : ");
8416 if (first != NULL) {
8417 if (*first != NULL)
8418 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8419 (*first)->name);
8420 else
8421 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8422 }
8423 if (last != NULL) {
8424 if (*last != NULL)
8425 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8426 (*last)->name);
8427 else
8428 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8429 }
8430#endif
8431 switch (axis) {
8432 case AXIS_ANCESTOR:
8433#ifdef DEBUG_STEP_NTH
8434 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8435#endif
8436 first = NULL;
8437 next = xmlXPathNextAncestor;
8438 break;
8439 case AXIS_ANCESTOR_OR_SELF:
8440#ifdef DEBUG_STEP_NTH
8441 xmlGenericError(xmlGenericErrorContext,
8442 "axis 'ancestors-or-self' ");
8443#endif
8444 first = NULL;
8445 next = xmlXPathNextAncestorOrSelf;
8446 break;
8447 case AXIS_ATTRIBUTE:
8448#ifdef DEBUG_STEP_NTH
8449 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8450#endif
8451 first = NULL;
8452 last = NULL;
8453 next = xmlXPathNextAttribute;
8454 break;
8455 case AXIS_CHILD:
8456#ifdef DEBUG_STEP_NTH
8457 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8458#endif
8459 last = NULL;
8460 next = xmlXPathNextChild;
8461 break;
8462 case AXIS_DESCENDANT:
8463#ifdef DEBUG_STEP_NTH
8464 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8465#endif
8466 last = NULL;
8467 next = xmlXPathNextDescendant;
8468 break;
8469 case AXIS_DESCENDANT_OR_SELF:
8470#ifdef DEBUG_STEP_NTH
8471 xmlGenericError(xmlGenericErrorContext,
8472 "axis 'descendant-or-self' ");
8473#endif
8474 last = NULL;
8475 next = xmlXPathNextDescendantOrSelf;
8476 break;
8477 case AXIS_FOLLOWING:
8478#ifdef DEBUG_STEP_NTH
8479 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8480#endif
8481 last = NULL;
8482 next = xmlXPathNextFollowing;
8483 break;
8484 case AXIS_FOLLOWING_SIBLING:
8485#ifdef DEBUG_STEP_NTH
8486 xmlGenericError(xmlGenericErrorContext,
8487 "axis 'following-siblings' ");
8488#endif
8489 last = NULL;
8490 next = xmlXPathNextFollowingSibling;
8491 break;
8492 case AXIS_NAMESPACE:
8493#ifdef DEBUG_STEP_NTH
8494 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8495#endif
8496 last = NULL;
8497 first = NULL;
8498 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8499 break;
8500 case AXIS_PARENT:
8501#ifdef DEBUG_STEP_NTH
8502 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8503#endif
8504 first = NULL;
8505 next = xmlXPathNextParent;
8506 break;
8507 case AXIS_PRECEDING:
8508#ifdef DEBUG_STEP_NTH
8509 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8510#endif
8511 first = NULL;
8512 next = xmlXPathNextPrecedingInternal;
8513 break;
8514 case AXIS_PRECEDING_SIBLING:
8515#ifdef DEBUG_STEP_NTH
8516 xmlGenericError(xmlGenericErrorContext,
8517 "axis 'preceding-sibling' ");
8518#endif
8519 first = NULL;
8520 next = xmlXPathNextPrecedingSibling;
8521 break;
8522 case AXIS_SELF:
8523#ifdef DEBUG_STEP_NTH
8524 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8525#endif
8526 first = NULL;
8527 last = NULL;
8528 next = xmlXPathNextSelf;
8529 break;
8530 }
8531 if (next == NULL)
8532 return(0);
8533
8534 nodelist = obj->nodesetval;
8535 if (nodelist == NULL) {
8536 xmlXPathFreeObject(obj);
8537 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8538 return(0);
8539 }
8540 addNode = xmlXPathNodeSetAddUnique;
8541#ifdef DEBUG_STEP_NTH
8542 xmlGenericError(xmlGenericErrorContext,
8543 " context contains %d nodes\n", nodelist->nodeNr);
8544 switch (test) {
8545 case NODE_TEST_NONE:
8546 xmlGenericError(xmlGenericErrorContext,
8547 " searching for none !!!\n");
8548 break;
8549 case NODE_TEST_TYPE:
8550 xmlGenericError(xmlGenericErrorContext,
8551 " searching for type %d\n", type);
8552 break;
8553 case NODE_TEST_PI:
8554 xmlGenericError(xmlGenericErrorContext,
8555 " searching for PI !!!\n");
8556 break;
8557 case NODE_TEST_ALL:
8558 xmlGenericError(xmlGenericErrorContext,
8559 " searching for *\n");
8560 break;
8561 case NODE_TEST_NS:
8562 xmlGenericError(xmlGenericErrorContext,
8563 " searching for namespace %s\n",
8564 prefix);
8565 break;
8566 case NODE_TEST_NAME:
8567 xmlGenericError(xmlGenericErrorContext,
8568 " searching for name %s\n", name);
8569 if (prefix != NULL)
8570 xmlGenericError(xmlGenericErrorContext,
8571 " with namespace %s\n", prefix);
8572 break;
8573 }
8574 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8575#endif
8576 /*
8577 * 2.3 Node Tests
8578 * - For the attribute axis, the principal node type is attribute.
8579 * - For the namespace axis, the principal node type is namespace.
8580 * - For other axes, the principal node type is element.
8581 *
8582 * A node test * is true for any node of the
8583 * principal node type. For example, child::* willi
8584 * select all element children of the context node
8585 */
8586 tmp = ctxt->context->node;
8587 list = xmlXPathNodeSetCreate(NULL);
8588 for (i = 0; i < nodelist->nodeNr; i++) {
8589 ctxt->context->node = nodelist->nodeTab[i];
8590
8591 cur = NULL;
8592 n = 0;
8593 do {
8594 cur = next(ctxt, cur);
8595 if (cur == NULL)
8596 break;
8597 if ((first != NULL) && (*first == cur))
8598 break;
8599 if (((t % 256) == 0) &&
8600 (first != NULL) && (*first != NULL) &&
8601 (xmlXPathCmpNodes(*first, cur) >= 0))
8602 break;
8603 if ((last != NULL) && (*last == cur))
8604 break;
8605 if (((t % 256) == 0) &&
8606 (last != NULL) && (*last != NULL) &&
8607 (xmlXPathCmpNodes(cur, *last) >= 0))
8608 break;
8609 t++;
8610 switch (test) {
8611 case NODE_TEST_NONE:
8612 ctxt->context->node = tmp;
8613 STRANGE return(0);
8614 case NODE_TEST_TYPE:
8615 if ((cur->type == type) ||
8616 ((type == NODE_TYPE_NODE) &&
8617 ((cur->type == XML_DOCUMENT_NODE) ||
8618 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8619 (cur->type == XML_ELEMENT_NODE) ||
8620 (cur->type == XML_PI_NODE) ||
8621 (cur->type == XML_COMMENT_NODE) ||
8622 (cur->type == XML_CDATA_SECTION_NODE) ||
8623 (cur->type == XML_TEXT_NODE)))) {
8624 n++;
8625 if (n == indx)
8626 addNode(list, cur);
8627 }
8628 break;
8629 case NODE_TEST_PI:
8630 if (cur->type == XML_PI_NODE) {
8631 if ((name != NULL) &&
8632 (!xmlStrEqual(name, cur->name)))
8633 break;
8634 n++;
8635 if (n == indx)
8636 addNode(list, cur);
8637 }
8638 break;
8639 case NODE_TEST_ALL:
8640 if (axis == AXIS_ATTRIBUTE) {
8641 if (cur->type == XML_ATTRIBUTE_NODE) {
8642 n++;
8643 if (n == indx)
8644 addNode(list, cur);
8645 }
8646 } else if (axis == AXIS_NAMESPACE) {
8647 if (cur->type == XML_NAMESPACE_DECL) {
8648 n++;
8649 if (n == indx)
8650 addNode(list, cur);
8651 }
8652 } else {
8653 if (cur->type == XML_ELEMENT_NODE) {
8654 if (prefix == NULL) {
8655 n++;
8656 if (n == indx)
8657 addNode(list, cur);
8658 } else if ((cur->ns != NULL) &&
8659 (xmlStrEqual(URI, cur->ns->href))) {
8660 n++;
8661 if (n == indx)
8662 addNode(list, cur);
8663 }
8664 }
8665 }
8666 break;
8667 case NODE_TEST_NS:{
8668 TODO;
8669 break;
8670 }
8671 case NODE_TEST_NAME:
8672 switch (cur->type) {
8673 case XML_ELEMENT_NODE:
8674 if (xmlStrEqual(name, cur->name)) {
8675 if (prefix == NULL) {
8676 if (cur->ns == NULL) {
8677 n++;
8678 if (n == indx)
8679 addNode(list, cur);
8680 }
8681 } else {
8682 if ((cur->ns != NULL) &&
8683 (xmlStrEqual(URI,
8684 cur->ns->href))) {
8685 n++;
8686 if (n == indx)
8687 addNode(list, cur);
8688 }
8689 }
8690 }
8691 break;
8692 case XML_ATTRIBUTE_NODE:{
8693 xmlAttrPtr attr = (xmlAttrPtr) cur;
8694
8695 if (xmlStrEqual(name, attr->name)) {
8696 if (prefix == NULL) {
8697 if ((attr->ns == NULL) ||
8698 (attr->ns->prefix == NULL)) {
8699 n++;
8700 if (n == indx)
8701 addNode(list, cur);
8702 }
8703 } else {
8704 if ((attr->ns != NULL) &&
8705 (xmlStrEqual(URI,
8706 attr->ns->
8707 href))) {
8708 n++;
8709 if (n == indx)
8710 addNode(list, cur);
8711 }
8712 }
8713 }
8714 break;
8715 }
8716 case XML_NAMESPACE_DECL:
8717 if (cur->type == XML_NAMESPACE_DECL) {
8718 xmlNsPtr ns = (xmlNsPtr) cur;
8719
8720 if ((ns->prefix != NULL) && (name != NULL)
8721 && (xmlStrEqual(ns->prefix, name))) {
8722 n++;
8723 if (n == indx)
8724 addNode(list, cur);
8725 }
8726 }
8727 break;
8728 default:
8729 break;
8730 }
8731 break;
8732 break;
8733 }
8734 } while (n < indx);
8735 }
8736 ctxt->context->node = tmp;
8737#ifdef DEBUG_STEP_NTH
8738 xmlGenericError(xmlGenericErrorContext,
8739 "\nExamined %d nodes, found %d nodes at that step\n",
8740 t, list->nodeNr);
8741#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008742 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008743 if ((obj->boolval) && (obj->user != NULL)) {
8744 ctxt->value->boolval = 1;
8745 ctxt->value->user = obj->user;
8746 obj->user = NULL;
8747 obj->boolval = 0;
8748 }
8749 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008750 return(t);
8751}
8752
8753/**
8754 * xmlXPathCompOpEvalFirst:
8755 * @ctxt: the XPath parser context with the compiled expression
8756 * @op: an XPath compiled operation
8757 * @first: the first elem found so far
8758 *
8759 * Evaluate the Precompiled XPath operation searching only the first
8760 * element in document order
8761 *
8762 * Returns the number of examined objects.
8763 */
8764static int
8765xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8766 xmlXPathStepOpPtr op, xmlNodePtr * first)
8767{
8768 int total = 0, cur;
8769 xmlXPathCompExprPtr comp;
8770 xmlXPathObjectPtr arg1, arg2;
8771
8772 comp = ctxt->comp;
8773 switch (op->op) {
8774 case XPATH_OP_END:
8775 return (0);
8776 case XPATH_OP_UNION:
8777 total =
8778 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8779 first);
8780 if ((ctxt->value != NULL)
8781 && (ctxt->value->type == XPATH_NODESET)
8782 && (ctxt->value->nodesetval != NULL)
8783 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8784 /*
8785 * limit tree traversing to first node in the result
8786 */
8787 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8788 *first = ctxt->value->nodesetval->nodeTab[0];
8789 }
8790 cur =
8791 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8792 first);
8793 CHECK_TYPE0(XPATH_NODESET);
8794 arg2 = valuePop(ctxt);
8795
8796 CHECK_TYPE0(XPATH_NODESET);
8797 arg1 = valuePop(ctxt);
8798
8799 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8800 arg2->nodesetval);
8801 valuePush(ctxt, arg1);
8802 xmlXPathFreeObject(arg2);
8803 /* optimizer */
8804 if (total > cur)
8805 xmlXPathCompSwap(op);
8806 return (total + cur);
8807 case XPATH_OP_ROOT:
8808 xmlXPathRoot(ctxt);
8809 return (0);
8810 case XPATH_OP_NODE:
8811 if (op->ch1 != -1)
8812 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8813 if (op->ch2 != -1)
8814 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8815 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8816 return (total);
8817 case XPATH_OP_RESET:
8818 if (op->ch1 != -1)
8819 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8820 if (op->ch2 != -1)
8821 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8822 ctxt->context->node = NULL;
8823 return (total);
8824 case XPATH_OP_COLLECT:{
8825 if (op->ch1 == -1)
8826 return (total);
8827
8828 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8829
8830 /*
8831 * Optimization for [n] selection where n is a number
8832 */
8833 if ((op->ch2 != -1) &&
8834 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8835 (comp->steps[op->ch2].ch1 == -1) &&
8836 (comp->steps[op->ch2].ch2 != -1) &&
8837 (comp->steps[comp->steps[op->ch2].ch2].op ==
8838 XPATH_OP_VALUE)) {
8839 xmlXPathObjectPtr val;
8840
8841 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8842 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8843 int indx = (int) val->floatval;
8844
8845 if (val->floatval == (float) indx) {
8846 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8847 first, NULL);
8848 return (total);
8849 }
8850 }
8851 }
8852 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8853 return (total);
8854 }
8855 case XPATH_OP_VALUE:
8856 valuePush(ctxt,
8857 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8858 return (0);
8859 case XPATH_OP_SORT:
8860 if (op->ch1 != -1)
8861 total +=
8862 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8863 first);
8864 if ((ctxt->value != NULL)
8865 && (ctxt->value->type == XPATH_NODESET)
8866 && (ctxt->value->nodesetval != NULL))
8867 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8868 return (total);
8869 default:
8870 return (xmlXPathCompOpEval(ctxt, op));
8871 }
8872}
8873
8874/**
8875 * xmlXPathCompOpEvalLast:
8876 * @ctxt: the XPath parser context with the compiled expression
8877 * @op: an XPath compiled operation
8878 * @last: the last elem found so far
8879 *
8880 * Evaluate the Precompiled XPath operation searching only the last
8881 * element in document order
8882 *
8883 * Returns the number of node traversed
8884 */
8885static int
8886xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8887 xmlNodePtr * last)
8888{
8889 int total = 0, cur;
8890 xmlXPathCompExprPtr comp;
8891 xmlXPathObjectPtr arg1, arg2;
8892
8893 comp = ctxt->comp;
8894 switch (op->op) {
8895 case XPATH_OP_END:
8896 return (0);
8897 case XPATH_OP_UNION:
8898 total =
8899 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8900 if ((ctxt->value != NULL)
8901 && (ctxt->value->type == XPATH_NODESET)
8902 && (ctxt->value->nodesetval != NULL)
8903 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8904 /*
8905 * limit tree traversing to first node in the result
8906 */
8907 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8908 *last =
8909 ctxt->value->nodesetval->nodeTab[ctxt->value->
8910 nodesetval->nodeNr -
8911 1];
8912 }
8913 cur =
8914 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8915 if ((ctxt->value != NULL)
8916 && (ctxt->value->type == XPATH_NODESET)
8917 && (ctxt->value->nodesetval != NULL)
8918 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8919 }
8920 CHECK_TYPE0(XPATH_NODESET);
8921 arg2 = valuePop(ctxt);
8922
8923 CHECK_TYPE0(XPATH_NODESET);
8924 arg1 = valuePop(ctxt);
8925
8926 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8927 arg2->nodesetval);
8928 valuePush(ctxt, arg1);
8929 xmlXPathFreeObject(arg2);
8930 /* optimizer */
8931 if (total > cur)
8932 xmlXPathCompSwap(op);
8933 return (total + cur);
8934 case XPATH_OP_ROOT:
8935 xmlXPathRoot(ctxt);
8936 return (0);
8937 case XPATH_OP_NODE:
8938 if (op->ch1 != -1)
8939 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8940 if (op->ch2 != -1)
8941 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8942 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8943 return (total);
8944 case XPATH_OP_RESET:
8945 if (op->ch1 != -1)
8946 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8947 if (op->ch2 != -1)
8948 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8949 ctxt->context->node = NULL;
8950 return (total);
8951 case XPATH_OP_COLLECT:{
8952 if (op->ch1 == -1)
8953 return (0);
8954
8955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8956
8957 /*
8958 * Optimization for [n] selection where n is a number
8959 */
8960 if ((op->ch2 != -1) &&
8961 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8962 (comp->steps[op->ch2].ch1 == -1) &&
8963 (comp->steps[op->ch2].ch2 != -1) &&
8964 (comp->steps[comp->steps[op->ch2].ch2].op ==
8965 XPATH_OP_VALUE)) {
8966 xmlXPathObjectPtr val;
8967
8968 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8969 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8970 int indx = (int) val->floatval;
8971
8972 if (val->floatval == (float) indx) {
8973 total +=
8974 xmlXPathNodeCollectAndTestNth(ctxt, op,
8975 indx, NULL,
8976 last);
8977 return (total);
8978 }
8979 }
8980 }
8981 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8982 return (total);
8983 }
8984 case XPATH_OP_VALUE:
8985 valuePush(ctxt,
8986 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8987 return (0);
8988 case XPATH_OP_SORT:
8989 if (op->ch1 != -1)
8990 total +=
8991 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8992 last);
8993 if ((ctxt->value != NULL)
8994 && (ctxt->value->type == XPATH_NODESET)
8995 && (ctxt->value->nodesetval != NULL))
8996 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8997 return (total);
8998 default:
8999 return (xmlXPathCompOpEval(ctxt, op));
9000 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009001}
9002
Owen Taylor3473f882001-02-23 17:55:21 +00009003/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009004 * xmlXPathCompOpEval:
9005 * @ctxt: the XPath parser context with the compiled expression
9006 * @op: an XPath compiled operation
9007 *
9008 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009009 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009010 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011static int
9012xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9013{
9014 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009015 int equal, ret;
9016 xmlXPathCompExprPtr comp;
9017 xmlXPathObjectPtr arg1, arg2;
9018
9019 comp = ctxt->comp;
9020 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009021 case XPATH_OP_END:
9022 return (0);
9023 case XPATH_OP_AND:
9024 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9025 xmlXPathBooleanFunction(ctxt, 1);
9026 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9027 return (total);
9028 arg2 = valuePop(ctxt);
9029 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9030 xmlXPathBooleanFunction(ctxt, 1);
9031 arg1 = valuePop(ctxt);
9032 arg1->boolval &= arg2->boolval;
9033 valuePush(ctxt, arg1);
9034 xmlXPathFreeObject(arg2);
9035 return (total);
9036 case XPATH_OP_OR:
9037 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9038 xmlXPathBooleanFunction(ctxt, 1);
9039 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9040 return (total);
9041 arg2 = valuePop(ctxt);
9042 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9043 xmlXPathBooleanFunction(ctxt, 1);
9044 arg1 = valuePop(ctxt);
9045 arg1->boolval |= arg2->boolval;
9046 valuePush(ctxt, arg1);
9047 xmlXPathFreeObject(arg2);
9048 return (total);
9049 case XPATH_OP_EQUAL:
9050 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9052 equal = xmlXPathEqualValues(ctxt);
9053 if (op->value)
9054 valuePush(ctxt, xmlXPathNewBoolean(equal));
9055 else
9056 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9057 return (total);
9058 case XPATH_OP_CMP:
9059 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9060 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9061 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9062 valuePush(ctxt, xmlXPathNewBoolean(ret));
9063 return (total);
9064 case XPATH_OP_PLUS:
9065 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9066 if (op->ch2 != -1)
9067 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9068 if (op->value == 0)
9069 xmlXPathSubValues(ctxt);
9070 else if (op->value == 1)
9071 xmlXPathAddValues(ctxt);
9072 else if (op->value == 2)
9073 xmlXPathValueFlipSign(ctxt);
9074 else if (op->value == 3) {
9075 CAST_TO_NUMBER;
9076 CHECK_TYPE0(XPATH_NUMBER);
9077 }
9078 return (total);
9079 case XPATH_OP_MULT:
9080 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9081 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9082 if (op->value == 0)
9083 xmlXPathMultValues(ctxt);
9084 else if (op->value == 1)
9085 xmlXPathDivValues(ctxt);
9086 else if (op->value == 2)
9087 xmlXPathModValues(ctxt);
9088 return (total);
9089 case XPATH_OP_UNION:
9090 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9091 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9092 CHECK_TYPE0(XPATH_NODESET);
9093 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009094
Daniel Veillardf06307e2001-07-03 10:35:50 +00009095 CHECK_TYPE0(XPATH_NODESET);
9096 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009097
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9099 arg2->nodesetval);
9100 valuePush(ctxt, arg1);
9101 xmlXPathFreeObject(arg2);
9102 return (total);
9103 case XPATH_OP_ROOT:
9104 xmlXPathRoot(ctxt);
9105 return (total);
9106 case XPATH_OP_NODE:
9107 if (op->ch1 != -1)
9108 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9109 if (op->ch2 != -1)
9110 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9111 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9112 return (total);
9113 case XPATH_OP_RESET:
9114 if (op->ch1 != -1)
9115 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9116 if (op->ch2 != -1)
9117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9118 ctxt->context->node = NULL;
9119 return (total);
9120 case XPATH_OP_COLLECT:{
9121 if (op->ch1 == -1)
9122 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009123
Daniel Veillardf06307e2001-07-03 10:35:50 +00009124 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009125
Daniel Veillardf06307e2001-07-03 10:35:50 +00009126 /*
9127 * Optimization for [n] selection where n is a number
9128 */
9129 if ((op->ch2 != -1) &&
9130 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9131 (comp->steps[op->ch2].ch1 == -1) &&
9132 (comp->steps[op->ch2].ch2 != -1) &&
9133 (comp->steps[comp->steps[op->ch2].ch2].op ==
9134 XPATH_OP_VALUE)) {
9135 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009136
Daniel Veillardf06307e2001-07-03 10:35:50 +00009137 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9138 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9139 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009140
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 if (val->floatval == (float) indx) {
9142 total +=
9143 xmlXPathNodeCollectAndTestNth(ctxt, op,
9144 indx, NULL,
9145 NULL);
9146 return (total);
9147 }
9148 }
9149 }
9150 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9151 return (total);
9152 }
9153 case XPATH_OP_VALUE:
9154 valuePush(ctxt,
9155 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9156 return (total);
9157 case XPATH_OP_VARIABLE:{
9158 if (op->ch1 != -1)
9159 total +=
9160 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9161 if (op->value5 == NULL)
9162 valuePush(ctxt,
9163 xmlXPathVariableLookup(ctxt->context,
9164 op->value4));
9165 else {
9166 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009167
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9169 if (URI == NULL) {
9170 xmlGenericError(xmlGenericErrorContext,
9171 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
9172 op->value4, op->value5);
9173 return (total);
9174 }
9175 valuePush(ctxt,
9176 xmlXPathVariableLookupNS(ctxt->context,
9177 op->value4, URI));
9178 }
9179 return (total);
9180 }
9181 case XPATH_OP_FUNCTION:{
9182 xmlXPathFunction func;
9183 const xmlChar *oldFunc, *oldFuncURI;
9184
9185 if (op->ch1 != -1)
9186 total +=
9187 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9188 if (op->cache != NULL)
9189 func = (xmlXPathFunction) op->cache;
9190 else {
9191 const xmlChar *URI = NULL;
9192
9193 if (op->value5 == NULL)
9194 func =
9195 xmlXPathFunctionLookup(ctxt->context,
9196 op->value4);
9197 else {
9198 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9199 if (URI == NULL) {
9200 xmlGenericError(xmlGenericErrorContext,
9201 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
9202 op->value4, op->value5);
9203 return (total);
9204 }
9205 func = xmlXPathFunctionLookupNS(ctxt->context,
9206 op->value4, URI);
9207 }
9208 if (func == NULL) {
9209 xmlGenericError(xmlGenericErrorContext,
9210 "xmlXPathRunEval: function %s not found\n",
9211 op->value4);
9212 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
9213 return (total);
9214 }
9215 op->cache = (void *) func;
9216 op->cacheURI = (void *) URI;
9217 }
9218 oldFunc = ctxt->context->function;
9219 oldFuncURI = ctxt->context->functionURI;
9220 ctxt->context->function = op->value4;
9221 ctxt->context->functionURI = op->cacheURI;
9222 func(ctxt, op->value);
9223 ctxt->context->function = oldFunc;
9224 ctxt->context->functionURI = oldFuncURI;
9225 return (total);
9226 }
9227 case XPATH_OP_ARG:
9228 if (op->ch1 != -1)
9229 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9230 if (op->ch2 != -1)
9231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9232 return (total);
9233 case XPATH_OP_PREDICATE:
9234 case XPATH_OP_FILTER:{
9235 xmlXPathObjectPtr res;
9236 xmlXPathObjectPtr obj, tmp;
9237 xmlNodeSetPtr newset = NULL;
9238 xmlNodeSetPtr oldset;
9239 xmlNodePtr oldnode;
9240 int i;
9241
9242 /*
9243 * Optimization for ()[1] selection i.e. the first elem
9244 */
9245 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9246 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9247 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9248 xmlXPathObjectPtr val;
9249
9250 val = comp->steps[op->ch2].value4;
9251 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9252 (val->floatval == 1.0)) {
9253 xmlNodePtr first = NULL;
9254
9255 total +=
9256 xmlXPathCompOpEvalFirst(ctxt,
9257 &comp->steps[op->ch1],
9258 &first);
9259 /*
9260 * The nodeset should be in document order,
9261 * Keep only the first value
9262 */
9263 if ((ctxt->value != NULL) &&
9264 (ctxt->value->type == XPATH_NODESET) &&
9265 (ctxt->value->nodesetval != NULL) &&
9266 (ctxt->value->nodesetval->nodeNr > 1))
9267 ctxt->value->nodesetval->nodeNr = 1;
9268 return (total);
9269 }
9270 }
9271 /*
9272 * Optimization for ()[last()] selection i.e. the last elem
9273 */
9274 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9275 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9276 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9277 int f = comp->steps[op->ch2].ch1;
9278
9279 if ((f != -1) &&
9280 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9281 (comp->steps[f].value5 == NULL) &&
9282 (comp->steps[f].value == 0) &&
9283 (comp->steps[f].value4 != NULL) &&
9284 (xmlStrEqual
9285 (comp->steps[f].value4, BAD_CAST "last"))) {
9286 xmlNodePtr last = NULL;
9287
9288 total +=
9289 xmlXPathCompOpEvalLast(ctxt,
9290 &comp->steps[op->ch1],
9291 &last);
9292 /*
9293 * The nodeset should be in document order,
9294 * Keep only the last value
9295 */
9296 if ((ctxt->value != NULL) &&
9297 (ctxt->value->type == XPATH_NODESET) &&
9298 (ctxt->value->nodesetval != NULL) &&
9299 (ctxt->value->nodesetval->nodeTab != NULL) &&
9300 (ctxt->value->nodesetval->nodeNr > 1)) {
9301 ctxt->value->nodesetval->nodeTab[0] =
9302 ctxt->value->nodesetval->nodeTab[ctxt->
9303 value->
9304 nodesetval->
9305 nodeNr -
9306 1];
9307 ctxt->value->nodesetval->nodeNr = 1;
9308 }
9309 return (total);
9310 }
9311 }
9312
9313 if (op->ch1 != -1)
9314 total +=
9315 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9316 if (op->ch2 == -1)
9317 return (total);
9318 if (ctxt->value == NULL)
9319 return (total);
9320
9321 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009322
9323#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009324 /*
9325 * Hum are we filtering the result of an XPointer expression
9326 */
9327 if (ctxt->value->type == XPATH_LOCATIONSET) {
9328 xmlLocationSetPtr newlocset = NULL;
9329 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009330
Daniel Veillardf06307e2001-07-03 10:35:50 +00009331 /*
9332 * Extract the old locset, and then evaluate the result of the
9333 * expression for all the element in the locset. use it to grow
9334 * up a new locset.
9335 */
9336 CHECK_TYPE0(XPATH_LOCATIONSET);
9337 obj = valuePop(ctxt);
9338 oldlocset = obj->user;
9339 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009340
Daniel Veillardf06307e2001-07-03 10:35:50 +00009341 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9342 ctxt->context->contextSize = 0;
9343 ctxt->context->proximityPosition = 0;
9344 if (op->ch2 != -1)
9345 total +=
9346 xmlXPathCompOpEval(ctxt,
9347 &comp->steps[op->ch2]);
9348 res = valuePop(ctxt);
9349 if (res != NULL)
9350 xmlXPathFreeObject(res);
9351 valuePush(ctxt, obj);
9352 CHECK_ERROR0;
9353 return (total);
9354 }
9355 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009356
Daniel Veillardf06307e2001-07-03 10:35:50 +00009357 for (i = 0; i < oldlocset->locNr; i++) {
9358 /*
9359 * Run the evaluation with a node list made of a
9360 * single item in the nodelocset.
9361 */
9362 ctxt->context->node = oldlocset->locTab[i]->user;
9363 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9364 valuePush(ctxt, tmp);
9365 ctxt->context->contextSize = oldlocset->locNr;
9366 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009367
Daniel Veillardf06307e2001-07-03 10:35:50 +00009368 if (op->ch2 != -1)
9369 total +=
9370 xmlXPathCompOpEval(ctxt,
9371 &comp->steps[op->ch2]);
9372 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009373
Daniel Veillardf06307e2001-07-03 10:35:50 +00009374 /*
9375 * The result of the evaluation need to be tested to
9376 * decided whether the filter succeeded or not
9377 */
9378 res = valuePop(ctxt);
9379 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9380 xmlXPtrLocationSetAdd(newlocset,
9381 xmlXPathObjectCopy
9382 (oldlocset->locTab[i]));
9383 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009384
Daniel Veillardf06307e2001-07-03 10:35:50 +00009385 /*
9386 * Cleanup
9387 */
9388 if (res != NULL)
9389 xmlXPathFreeObject(res);
9390 if (ctxt->value == tmp) {
9391 res = valuePop(ctxt);
9392 xmlXPathFreeObject(res);
9393 }
9394
9395 ctxt->context->node = NULL;
9396 }
9397
9398 /*
9399 * The result is used as the new evaluation locset.
9400 */
9401 xmlXPathFreeObject(obj);
9402 ctxt->context->node = NULL;
9403 ctxt->context->contextSize = -1;
9404 ctxt->context->proximityPosition = -1;
9405 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9406 ctxt->context->node = oldnode;
9407 return (total);
9408 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009409#endif /* LIBXML_XPTR_ENABLED */
9410
Daniel Veillardf06307e2001-07-03 10:35:50 +00009411 /*
9412 * Extract the old set, and then evaluate the result of the
9413 * expression for all the element in the set. use it to grow
9414 * up a new set.
9415 */
9416 CHECK_TYPE0(XPATH_NODESET);
9417 obj = valuePop(ctxt);
9418 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009419
Daniel Veillardf06307e2001-07-03 10:35:50 +00009420 oldnode = ctxt->context->node;
9421 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009422
Daniel Veillardf06307e2001-07-03 10:35:50 +00009423 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9424 ctxt->context->contextSize = 0;
9425 ctxt->context->proximityPosition = 0;
9426 if (op->ch2 != -1)
9427 total +=
9428 xmlXPathCompOpEval(ctxt,
9429 &comp->steps[op->ch2]);
9430 res = valuePop(ctxt);
9431 if (res != NULL)
9432 xmlXPathFreeObject(res);
9433 valuePush(ctxt, obj);
9434 ctxt->context->node = oldnode;
9435 CHECK_ERROR0;
9436 } else {
9437 /*
9438 * Initialize the new set.
9439 */
9440 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009441
Daniel Veillardf06307e2001-07-03 10:35:50 +00009442 for (i = 0; i < oldset->nodeNr; i++) {
9443 /*
9444 * Run the evaluation with a node list made of
9445 * a single item in the nodeset.
9446 */
9447 ctxt->context->node = oldset->nodeTab[i];
9448 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9449 valuePush(ctxt, tmp);
9450 ctxt->context->contextSize = oldset->nodeNr;
9451 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009452
Daniel Veillardf06307e2001-07-03 10:35:50 +00009453 if (op->ch2 != -1)
9454 total +=
9455 xmlXPathCompOpEval(ctxt,
9456 &comp->steps[op->ch2]);
9457 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009458
Daniel Veillardf06307e2001-07-03 10:35:50 +00009459 /*
9460 * The result of the evaluation need to be tested to
9461 * decided whether the filter succeeded or not
9462 */
9463 res = valuePop(ctxt);
9464 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9465 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9466 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009467
Daniel Veillardf06307e2001-07-03 10:35:50 +00009468 /*
9469 * Cleanup
9470 */
9471 if (res != NULL)
9472 xmlXPathFreeObject(res);
9473 if (ctxt->value == tmp) {
9474 res = valuePop(ctxt);
9475 xmlXPathFreeObject(res);
9476 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009477
Daniel Veillardf06307e2001-07-03 10:35:50 +00009478 ctxt->context->node = NULL;
9479 }
9480
9481 /*
9482 * The result is used as the new evaluation set.
9483 */
9484 xmlXPathFreeObject(obj);
9485 ctxt->context->node = NULL;
9486 ctxt->context->contextSize = -1;
9487 ctxt->context->proximityPosition = -1;
9488 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9489 }
9490 ctxt->context->node = oldnode;
9491 return (total);
9492 }
9493 case XPATH_OP_SORT:
9494 if (op->ch1 != -1)
9495 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9496 if ((ctxt->value != NULL) &&
9497 (ctxt->value->type == XPATH_NODESET) &&
9498 (ctxt->value->nodesetval != NULL))
9499 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9500 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009501#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009502 case XPATH_OP_RANGETO:{
9503 xmlXPathObjectPtr range;
9504 xmlXPathObjectPtr res, obj;
9505 xmlXPathObjectPtr tmp;
9506 xmlLocationSetPtr newset = NULL;
9507 xmlNodeSetPtr oldset;
9508 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009509
Daniel Veillardf06307e2001-07-03 10:35:50 +00009510 if (op->ch1 != -1)
9511 total +=
9512 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9513 if (op->ch2 == -1)
9514 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009515
Daniel Veillardf06307e2001-07-03 10:35:50 +00009516 CHECK_TYPE0(XPATH_NODESET);
9517 obj = valuePop(ctxt);
9518 oldset = obj->nodesetval;
9519 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009520
Daniel Veillardf06307e2001-07-03 10:35:50 +00009521 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009522
Daniel Veillardf06307e2001-07-03 10:35:50 +00009523 if (oldset != NULL) {
9524 for (i = 0; i < oldset->nodeNr; i++) {
9525 /*
9526 * Run the evaluation with a node list made of a single item
9527 * in the nodeset.
9528 */
9529 ctxt->context->node = oldset->nodeTab[i];
9530 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9531 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009532
Daniel Veillardf06307e2001-07-03 10:35:50 +00009533 if (op->ch2 != -1)
9534 total +=
9535 xmlXPathCompOpEval(ctxt,
9536 &comp->steps[op->ch2]);
9537 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009538
Daniel Veillardf06307e2001-07-03 10:35:50 +00009539 /*
9540 * The result of the evaluation need to be tested to
9541 * decided whether the filter succeeded or not
9542 */
9543 res = valuePop(ctxt);
9544 range =
9545 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9546 res);
9547 if (range != NULL) {
9548 xmlXPtrLocationSetAdd(newset, range);
9549 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009550
Daniel Veillardf06307e2001-07-03 10:35:50 +00009551 /*
9552 * Cleanup
9553 */
9554 if (res != NULL)
9555 xmlXPathFreeObject(res);
9556 if (ctxt->value == tmp) {
9557 res = valuePop(ctxt);
9558 xmlXPathFreeObject(res);
9559 }
9560
9561 ctxt->context->node = NULL;
9562 }
9563 }
9564
9565 /*
9566 * The result is used as the new evaluation set.
9567 */
9568 xmlXPathFreeObject(obj);
9569 ctxt->context->node = NULL;
9570 ctxt->context->contextSize = -1;
9571 ctxt->context->proximityPosition = -1;
9572 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9573 return (total);
9574 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009575#endif /* LIBXML_XPTR_ENABLED */
9576 }
9577 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009578 "XPath: unknown precompiled operation %d\n", op->op);
9579 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009580}
9581
9582/**
9583 * xmlXPathRunEval:
9584 * @ctxt: the XPath parser context with the compiled expression
9585 *
9586 * Evaluate the Precompiled XPath expression in the given context.
9587 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009588static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009589xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9590 xmlXPathCompExprPtr comp;
9591
9592 if ((ctxt == NULL) || (ctxt->comp == NULL))
9593 return;
9594
9595 if (ctxt->valueTab == NULL) {
9596 /* Allocate the value stack */
9597 ctxt->valueTab = (xmlXPathObjectPtr *)
9598 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9599 if (ctxt->valueTab == NULL) {
9600 xmlFree(ctxt);
9601 xmlGenericError(xmlGenericErrorContext,
9602 "xmlXPathRunEval: out of memory\n");
9603 return;
9604 }
9605 ctxt->valueNr = 0;
9606 ctxt->valueMax = 10;
9607 ctxt->value = NULL;
9608 }
9609 comp = ctxt->comp;
9610 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9611}
9612
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009613/************************************************************************
9614 * *
9615 * Public interfaces *
9616 * *
9617 ************************************************************************/
9618
9619/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009620 * xmlXPathEvalPredicate:
9621 * @ctxt: the XPath context
9622 * @res: the Predicate Expression evaluation result
9623 *
9624 * Evaluate a predicate result for the current node.
9625 * A PredicateExpr is evaluated by evaluating the Expr and converting
9626 * the result to a boolean. If the result is a number, the result will
9627 * be converted to true if the number is equal to the position of the
9628 * context node in the context node list (as returned by the position
9629 * function) and will be converted to false otherwise; if the result
9630 * is not a number, then the result will be converted as if by a call
9631 * to the boolean function.
9632 *
9633 * Return 1 if predicate is true, 0 otherwise
9634 */
9635int
9636xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9637 if (res == NULL) return(0);
9638 switch (res->type) {
9639 case XPATH_BOOLEAN:
9640 return(res->boolval);
9641 case XPATH_NUMBER:
9642 return(res->floatval == ctxt->proximityPosition);
9643 case XPATH_NODESET:
9644 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009645 if (res->nodesetval == NULL)
9646 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009647 return(res->nodesetval->nodeNr != 0);
9648 case XPATH_STRING:
9649 return((res->stringval != NULL) &&
9650 (xmlStrlen(res->stringval) != 0));
9651 default:
9652 STRANGE
9653 }
9654 return(0);
9655}
9656
9657/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009658 * xmlXPathEvaluatePredicateResult:
9659 * @ctxt: the XPath Parser context
9660 * @res: the Predicate Expression evaluation result
9661 *
9662 * Evaluate a predicate result for the current node.
9663 * A PredicateExpr is evaluated by evaluating the Expr and converting
9664 * the result to a boolean. If the result is a number, the result will
9665 * be converted to true if the number is equal to the position of the
9666 * context node in the context node list (as returned by the position
9667 * function) and will be converted to false otherwise; if the result
9668 * is not a number, then the result will be converted as if by a call
9669 * to the boolean function.
9670 *
9671 * Return 1 if predicate is true, 0 otherwise
9672 */
9673int
9674xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9675 xmlXPathObjectPtr res) {
9676 if (res == NULL) return(0);
9677 switch (res->type) {
9678 case XPATH_BOOLEAN:
9679 return(res->boolval);
9680 case XPATH_NUMBER:
9681 return(res->floatval == ctxt->context->proximityPosition);
9682 case XPATH_NODESET:
9683 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009684 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009685 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009686 return(res->nodesetval->nodeNr != 0);
9687 case XPATH_STRING:
9688 return((res->stringval != NULL) &&
9689 (xmlStrlen(res->stringval) != 0));
9690 default:
9691 STRANGE
9692 }
9693 return(0);
9694}
9695
9696/**
9697 * xmlXPathCompile:
9698 * @str: the XPath expression
9699 *
9700 * Compile an XPath expression
9701 *
9702 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9703 * the caller has to free the object.
9704 */
9705xmlXPathCompExprPtr
9706xmlXPathCompile(const xmlChar *str) {
9707 xmlXPathParserContextPtr ctxt;
9708 xmlXPathCompExprPtr comp;
9709
9710 xmlXPathInit();
9711
9712 ctxt = xmlXPathNewParserContext(str, NULL);
9713 xmlXPathCompileExpr(ctxt);
9714
Daniel Veillard40af6492001-04-22 08:50:55 +00009715 if (*ctxt->cur != 0) {
9716 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9717 comp = NULL;
9718 } else {
9719 comp = ctxt->comp;
9720 ctxt->comp = NULL;
9721 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009722 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009723#ifdef DEBUG_EVAL_COUNTS
9724 if (comp != NULL) {
9725 comp->string = xmlStrdup(str);
9726 comp->nb = 0;
9727 }
9728#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009729 return(comp);
9730}
9731
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009732/**
9733 * xmlXPathCompiledEval:
9734 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009735 * @ctx: the XPath context
9736 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009737 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009738 *
9739 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9740 * the caller has to free the object.
9741 */
9742xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009743xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009744 xmlXPathParserContextPtr ctxt;
9745 xmlXPathObjectPtr res, tmp, init = NULL;
9746 int stack = 0;
9747
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009748 if ((comp == NULL) || (ctx == NULL))
9749 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009750 xmlXPathInit();
9751
9752 CHECK_CONTEXT(ctx)
9753
Daniel Veillardf06307e2001-07-03 10:35:50 +00009754#ifdef DEBUG_EVAL_COUNTS
9755 comp->nb++;
9756 if ((comp->string != NULL) && (comp->nb > 100)) {
9757 fprintf(stderr, "100 x %s\n", comp->string);
9758 comp->nb = 0;
9759 }
9760#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009761 ctxt = xmlXPathCompParserContext(comp, ctx);
9762 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009763
9764 if (ctxt->value == NULL) {
9765 xmlGenericError(xmlGenericErrorContext,
9766 "xmlXPathEval: evaluation failed\n");
9767 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009768 } else {
9769 res = valuePop(ctxt);
9770 }
9771
Daniel Veillardf06307e2001-07-03 10:35:50 +00009772
Owen Taylor3473f882001-02-23 17:55:21 +00009773 do {
9774 tmp = valuePop(ctxt);
9775 if (tmp != NULL) {
9776 if (tmp != init)
9777 stack++;
9778 xmlXPathFreeObject(tmp);
9779 }
9780 } while (tmp != NULL);
9781 if ((stack != 0) && (res != NULL)) {
9782 xmlGenericError(xmlGenericErrorContext,
9783 "xmlXPathEval: %d object left on the stack\n",
9784 stack);
9785 }
9786 if (ctxt->error != XPATH_EXPRESSION_OK) {
9787 xmlXPathFreeObject(res);
9788 res = NULL;
9789 }
9790
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009791
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009792 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009793 xmlXPathFreeParserContext(ctxt);
9794 return(res);
9795}
9796
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009797/**
9798 * xmlXPathEvalExpr:
9799 * @ctxt: the XPath Parser context
9800 *
9801 * Parse and evaluate an XPath expression in the given context,
9802 * then push the result on the context stack
9803 */
9804void
9805xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9806 xmlXPathCompileExpr(ctxt);
9807 xmlXPathRunEval(ctxt);
9808}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009809
9810/**
9811 * xmlXPathEval:
9812 * @str: the XPath expression
9813 * @ctx: the XPath context
9814 *
9815 * Evaluate the XPath Location Path in the given context.
9816 *
9817 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9818 * the caller has to free the object.
9819 */
9820xmlXPathObjectPtr
9821xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9822 xmlXPathParserContextPtr ctxt;
9823 xmlXPathObjectPtr res, tmp, init = NULL;
9824 int stack = 0;
9825
9826 xmlXPathInit();
9827
9828 CHECK_CONTEXT(ctx)
9829
9830 ctxt = xmlXPathNewParserContext(str, ctx);
9831 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009832
9833 if (ctxt->value == NULL) {
9834 xmlGenericError(xmlGenericErrorContext,
9835 "xmlXPathEval: evaluation failed\n");
9836 res = NULL;
9837 } else if (*ctxt->cur != 0) {
9838 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9839 res = NULL;
9840 } else {
9841 res = valuePop(ctxt);
9842 }
9843
9844 do {
9845 tmp = valuePop(ctxt);
9846 if (tmp != NULL) {
9847 if (tmp != init)
9848 stack++;
9849 xmlXPathFreeObject(tmp);
9850 }
9851 } while (tmp != NULL);
9852 if ((stack != 0) && (res != NULL)) {
9853 xmlGenericError(xmlGenericErrorContext,
9854 "xmlXPathEval: %d object left on the stack\n",
9855 stack);
9856 }
9857 if (ctxt->error != XPATH_EXPRESSION_OK) {
9858 xmlXPathFreeObject(res);
9859 res = NULL;
9860 }
9861
Owen Taylor3473f882001-02-23 17:55:21 +00009862 xmlXPathFreeParserContext(ctxt);
9863 return(res);
9864}
9865
9866/**
9867 * xmlXPathEvalExpression:
9868 * @str: the XPath expression
9869 * @ctxt: the XPath context
9870 *
9871 * Evaluate the XPath expression in the given context.
9872 *
9873 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9874 * the caller has to free the object.
9875 */
9876xmlXPathObjectPtr
9877xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9878 xmlXPathParserContextPtr pctxt;
9879 xmlXPathObjectPtr res, tmp;
9880 int stack = 0;
9881
9882 xmlXPathInit();
9883
9884 CHECK_CONTEXT(ctxt)
9885
9886 pctxt = xmlXPathNewParserContext(str, ctxt);
9887 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009888
9889 if (*pctxt->cur != 0) {
9890 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9891 res = NULL;
9892 } else {
9893 res = valuePop(pctxt);
9894 }
9895 do {
9896 tmp = valuePop(pctxt);
9897 if (tmp != NULL) {
9898 xmlXPathFreeObject(tmp);
9899 stack++;
9900 }
9901 } while (tmp != NULL);
9902 if ((stack != 0) && (res != NULL)) {
9903 xmlGenericError(xmlGenericErrorContext,
9904 "xmlXPathEvalExpression: %d object left on the stack\n",
9905 stack);
9906 }
9907 xmlXPathFreeParserContext(pctxt);
9908 return(res);
9909}
9910
9911/**
9912 * xmlXPathRegisterAllFunctions:
9913 * @ctxt: the XPath context
9914 *
9915 * Registers all default XPath functions in this context
9916 */
9917void
9918xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9919{
9920 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9921 xmlXPathBooleanFunction);
9922 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9923 xmlXPathCeilingFunction);
9924 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9925 xmlXPathCountFunction);
9926 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9927 xmlXPathConcatFunction);
9928 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9929 xmlXPathContainsFunction);
9930 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9931 xmlXPathIdFunction);
9932 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9933 xmlXPathFalseFunction);
9934 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9935 xmlXPathFloorFunction);
9936 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9937 xmlXPathLastFunction);
9938 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9939 xmlXPathLangFunction);
9940 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9941 xmlXPathLocalNameFunction);
9942 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9943 xmlXPathNotFunction);
9944 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9945 xmlXPathNameFunction);
9946 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9947 xmlXPathNamespaceURIFunction);
9948 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9949 xmlXPathNormalizeFunction);
9950 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9951 xmlXPathNumberFunction);
9952 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9953 xmlXPathPositionFunction);
9954 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9955 xmlXPathRoundFunction);
9956 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9957 xmlXPathStringFunction);
9958 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9959 xmlXPathStringLengthFunction);
9960 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9961 xmlXPathStartsWithFunction);
9962 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9963 xmlXPathSubstringFunction);
9964 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9965 xmlXPathSubstringBeforeFunction);
9966 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9967 xmlXPathSubstringAfterFunction);
9968 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9969 xmlXPathSumFunction);
9970 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9971 xmlXPathTrueFunction);
9972 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9973 xmlXPathTranslateFunction);
9974}
9975
9976#endif /* LIBXML_XPATH_ENABLED */