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