blob: 16681b2b489b2d678468cd3a513339aba4fb09b7 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000054
Daniel Veillard9e7160d2001-03-18 23:17:47 +000055/************************************************************************
56 * *
57 * Floating point stuff *
58 * *
59 ************************************************************************/
60
Daniel Veillardc0631a62001-09-20 13:56:06 +000061#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000062#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000063#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000064#include "trionan.c"
65
Owen Taylor3473f882001-02-23 17:55:21 +000066/*
Owen Taylor3473f882001-02-23 17:55:21 +000067 * The lack of portability of this section of the libc is annoying !
68 */
69double xmlXPathNAN = 0;
70double xmlXPathPINF = 1;
71double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000072double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000073static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000074
Owen Taylor3473f882001-02-23 17:55:21 +000075/**
76 * xmlXPathInit:
77 *
78 * Initialize the XPath environment
79 */
80void
81xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000082 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000083
Bjorn Reese45029602001-08-21 09:23:53 +000084 xmlXPathPINF = trio_pinf();
85 xmlXPathNINF = trio_ninf();
86 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +000087 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +000088
Daniel Veillard20ee8c02001-10-05 09:18:14 +000089 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000090}
91
Daniel Veillardcda96922001-08-21 10:56:31 +000092/**
93 * xmlXPathIsNaN:
94 * @val: a double value
95 *
96 * Provides a portable isnan() function to detect whether a double
97 * is a NotaNumber. Based on trio code
98 * http://sourceforge.net/projects/ctrio/
99 *
100 * Returns 1 if the value is a NaN, 0 otherwise
101 */
102int
103xmlXPathIsNaN(double val) {
104 return(trio_isnan(val));
105}
106
107/**
108 * xmlXPathIsInf:
109 * @val: a double value
110 *
111 * Provides a portable isinf() function to detect whether a double
112 * is a +Infinite or -Infinite. Based on trio code
113 * http://sourceforge.net/projects/ctrio/
114 *
115 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
116 */
117int
118xmlXPathIsInf(double val) {
119 return(trio_isinf(val));
120}
121
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000122/**
123 * xmlXPathGetSign:
124 * @val: a double value
125 *
126 * Provides a portable function to detect the sign of a double
127 * Modified from trio code
128 * http://sourceforge.net/projects/ctrio/
129 *
130 * Returns 1 if the value is Negative, 0 if positive
131 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000132static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000133xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000134 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000135}
136
137
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000138#ifdef LIBXML_XPATH_ENABLED
139/*
140 * TODO: when compatibility allows remove all "fake node libxslt" strings
141 * the test should just be name[0] = ' '
142 */
143/* #define DEBUG */
144/* #define DEBUG_STEP */
145/* #define DEBUG_STEP_NTH */
146/* #define DEBUG_EXPR */
147/* #define DEBUG_EVAL_COUNTS */
148
149static xmlNs xmlXPathXMLNamespaceStruct = {
150 NULL,
151 XML_NAMESPACE_DECL,
152 XML_XML_NAMESPACE,
153 BAD_CAST "xml",
154 NULL
155};
156static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
157#ifndef LIBXML_THREAD_ENABLED
158/*
159 * Optimizer is disabled only when threaded apps are detected while
160 * the library ain't compiled for thread safety.
161 */
162static int xmlXPathDisableOptimizer = 0;
163#endif
164
Owen Taylor3473f882001-02-23 17:55:21 +0000165/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000166 * *
167 * Parser Types *
168 * *
169 ************************************************************************/
170
171/*
172 * Types are private:
173 */
174
175typedef enum {
176 XPATH_OP_END=0,
177 XPATH_OP_AND,
178 XPATH_OP_OR,
179 XPATH_OP_EQUAL,
180 XPATH_OP_CMP,
181 XPATH_OP_PLUS,
182 XPATH_OP_MULT,
183 XPATH_OP_UNION,
184 XPATH_OP_ROOT,
185 XPATH_OP_NODE,
186 XPATH_OP_RESET,
187 XPATH_OP_COLLECT,
188 XPATH_OP_VALUE,
189 XPATH_OP_VARIABLE,
190 XPATH_OP_FUNCTION,
191 XPATH_OP_ARG,
192 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000193 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000194 XPATH_OP_SORT
195#ifdef LIBXML_XPTR_ENABLED
196 ,XPATH_OP_RANGETO
197#endif
198} xmlXPathOp;
199
200typedef enum {
201 AXIS_ANCESTOR = 1,
202 AXIS_ANCESTOR_OR_SELF,
203 AXIS_ATTRIBUTE,
204 AXIS_CHILD,
205 AXIS_DESCENDANT,
206 AXIS_DESCENDANT_OR_SELF,
207 AXIS_FOLLOWING,
208 AXIS_FOLLOWING_SIBLING,
209 AXIS_NAMESPACE,
210 AXIS_PARENT,
211 AXIS_PRECEDING,
212 AXIS_PRECEDING_SIBLING,
213 AXIS_SELF
214} xmlXPathAxisVal;
215
216typedef enum {
217 NODE_TEST_NONE = 0,
218 NODE_TEST_TYPE = 1,
219 NODE_TEST_PI = 2,
220 NODE_TEST_ALL = 3,
221 NODE_TEST_NS = 4,
222 NODE_TEST_NAME = 5
223} xmlXPathTestVal;
224
225typedef enum {
226 NODE_TYPE_NODE = 0,
227 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
228 NODE_TYPE_TEXT = XML_TEXT_NODE,
229 NODE_TYPE_PI = XML_PI_NODE
230} xmlXPathTypeVal;
231
232
233typedef struct _xmlXPathStepOp xmlXPathStepOp;
234typedef xmlXPathStepOp *xmlXPathStepOpPtr;
235struct _xmlXPathStepOp {
236 xmlXPathOp op;
237 int ch1;
238 int ch2;
239 int value;
240 int value2;
241 int value3;
242 void *value4;
243 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000244 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000245 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000246};
247
248struct _xmlXPathCompExpr {
249 int nbStep;
250 int maxStep;
251 xmlXPathStepOp *steps; /* ops for computation */
252 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000253 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000254#ifdef DEBUG_EVAL_COUNTS
255 int nb;
256 xmlChar *string;
257#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000258};
259
260/************************************************************************
261 * *
262 * Parser Type functions *
263 * *
264 ************************************************************************/
265
266/**
267 * xmlXPathNewCompExpr:
268 *
269 * Create a new Xpath component
270 *
271 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
272 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000273static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000274xmlXPathNewCompExpr(void) {
275 xmlXPathCompExprPtr cur;
276
277 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
278 if (cur == NULL) {
279 xmlGenericError(xmlGenericErrorContext,
280 "xmlXPathNewCompExpr : malloc failed\n");
281 return(NULL);
282 }
283 memset(cur, 0, sizeof(xmlXPathCompExpr));
284 cur->maxStep = 10;
285 cur->nbStep = 0;
286 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
287 sizeof(xmlXPathStepOp));
288 if (cur->steps == NULL) {
289 xmlGenericError(xmlGenericErrorContext,
290 "xmlXPathNewCompExpr : malloc failed\n");
291 xmlFree(cur);
292 return(NULL);
293 }
294 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
295 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000296#ifdef DEBUG_EVAL_COUNTS
297 cur->nb = 0;
298#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000299 return(cur);
300}
301
302/**
303 * xmlXPathFreeCompExpr:
304 * @comp: an XPATH comp
305 *
306 * Free up the memory allocated by @comp
307 */
308void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000309xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
310{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000311 xmlXPathStepOpPtr op;
312 int i;
313
314 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000315 return;
316 for (i = 0; i < comp->nbStep; i++) {
317 op = &comp->steps[i];
318 if (op->value4 != NULL) {
319 if (op->op == XPATH_OP_VALUE)
320 xmlXPathFreeObject(op->value4);
321 else
322 xmlFree(op->value4);
323 }
324 if (op->value5 != NULL)
325 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000326 }
327 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000328 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000329 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000330#ifdef DEBUG_EVAL_COUNTS
331 if (comp->string != NULL) {
332 xmlFree(comp->string);
333 }
334#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000335 if (comp->expr != NULL) {
336 xmlFree(comp->expr);
337 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000338
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000339 xmlFree(comp);
340}
341
342/**
343 * xmlXPathCompExprAdd:
344 * @comp: the compiled expression
345 * @ch1: first child index
346 * @ch2: second child index
347 * @op: an op
348 * @value: the first int value
349 * @value2: the second int value
350 * @value3: the third int value
351 * @value4: the first string value
352 * @value5: the second string value
353 *
354 * Add an step to an XPath Compiled Expression
355 *
356 * Returns -1 in case of failure, the index otherwise
357 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000358static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000359xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
360 xmlXPathOp op, int value,
361 int value2, int value3, void *value4, void *value5) {
362 if (comp->nbStep >= comp->maxStep) {
363 xmlXPathStepOp *real;
364
365 comp->maxStep *= 2;
366 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
367 comp->maxStep * sizeof(xmlXPathStepOp));
368 if (real == NULL) {
369 comp->maxStep /= 2;
370 xmlGenericError(xmlGenericErrorContext,
371 "xmlXPathCompExprAdd : realloc failed\n");
372 return(-1);
373 }
374 comp->steps = real;
375 }
376 comp->last = comp->nbStep;
377 comp->steps[comp->nbStep].ch1 = ch1;
378 comp->steps[comp->nbStep].ch2 = ch2;
379 comp->steps[comp->nbStep].op = op;
380 comp->steps[comp->nbStep].value = value;
381 comp->steps[comp->nbStep].value2 = value2;
382 comp->steps[comp->nbStep].value3 = value3;
383 comp->steps[comp->nbStep].value4 = value4;
384 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000385 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000386 return(comp->nbStep++);
387}
388
Daniel Veillardf06307e2001-07-03 10:35:50 +0000389/**
390 * xmlXPathCompSwap:
391 * @comp: the compiled expression
392 * @op: operation index
393 *
394 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000395 */
396static void
397xmlXPathCompSwap(xmlXPathStepOpPtr op) {
398 int tmp;
399
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000400#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000401 /*
402 * Since this manipulates possibly shared variables, this is
403 * disable if one detects that the library is used in a multithreaded
404 * application
405 */
406 if (xmlXPathDisableOptimizer)
407 return;
408#endif
409
Daniel Veillardf06307e2001-07-03 10:35:50 +0000410 tmp = op->ch1;
411 op->ch1 = op->ch2;
412 op->ch2 = tmp;
413}
414
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000415#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
416 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
417 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000418#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
419 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
420 (op), (val), (val2), (val3), (val4), (val5))
421
422#define PUSH_LEAVE_EXPR(op, val, val2) \
423xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
424
425#define PUSH_UNARY_EXPR(op, ch, val, val2) \
426xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
427
428#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
429xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
430
431/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000432 * *
433 * Debugging related functions *
434 * *
435 ************************************************************************/
436
437#define TODO \
438 xmlGenericError(xmlGenericErrorContext, \
439 "Unimplemented block at %s:%d\n", \
440 __FILE__, __LINE__);
441
442#define STRANGE \
443 xmlGenericError(xmlGenericErrorContext, \
444 "Internal error at %s:%d\n", \
445 __FILE__, __LINE__);
446
447#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000448static void
449xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000450 int i;
451 char shift[100];
452
453 for (i = 0;((i < depth) && (i < 25));i++)
454 shift[2 * i] = shift[2 * i + 1] = ' ';
455 shift[2 * i] = shift[2 * i + 1] = 0;
456 if (cur == NULL) {
457 fprintf(output, shift);
458 fprintf(output, "Node is NULL !\n");
459 return;
460
461 }
462
463 if ((cur->type == XML_DOCUMENT_NODE) ||
464 (cur->type == XML_HTML_DOCUMENT_NODE)) {
465 fprintf(output, shift);
466 fprintf(output, " /\n");
467 } else if (cur->type == XML_ATTRIBUTE_NODE)
468 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
469 else
470 xmlDebugDumpOneNode(output, cur, depth);
471}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000472static void
473xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000474 xmlNodePtr tmp;
475 int i;
476 char shift[100];
477
478 for (i = 0;((i < depth) && (i < 25));i++)
479 shift[2 * i] = shift[2 * i + 1] = ' ';
480 shift[2 * i] = shift[2 * i + 1] = 0;
481 if (cur == NULL) {
482 fprintf(output, shift);
483 fprintf(output, "Node is NULL !\n");
484 return;
485
486 }
487
488 while (cur != NULL) {
489 tmp = cur;
490 cur = cur->next;
491 xmlDebugDumpOneNode(output, tmp, depth);
492 }
493}
Owen Taylor3473f882001-02-23 17:55:21 +0000494
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000495static void
496xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000497 int i;
498 char shift[100];
499
500 for (i = 0;((i < depth) && (i < 25));i++)
501 shift[2 * i] = shift[2 * i + 1] = ' ';
502 shift[2 * i] = shift[2 * i + 1] = 0;
503
504 if (cur == NULL) {
505 fprintf(output, shift);
506 fprintf(output, "NodeSet is NULL !\n");
507 return;
508
509 }
510
Daniel Veillard911f49a2001-04-07 15:39:35 +0000511 if (cur != NULL) {
512 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
513 for (i = 0;i < cur->nodeNr;i++) {
514 fprintf(output, shift);
515 fprintf(output, "%d", i + 1);
516 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
517 }
Owen Taylor3473f882001-02-23 17:55:21 +0000518 }
519}
520
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000521static void
522xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000523 int i;
524 char shift[100];
525
526 for (i = 0;((i < depth) && (i < 25));i++)
527 shift[2 * i] = shift[2 * i + 1] = ' ';
528 shift[2 * i] = shift[2 * i + 1] = 0;
529
530 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
531 fprintf(output, shift);
532 fprintf(output, "Value Tree is NULL !\n");
533 return;
534
535 }
536
537 fprintf(output, shift);
538 fprintf(output, "%d", i + 1);
539 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
540}
Owen Taylor3473f882001-02-23 17:55:21 +0000541#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000542static void
543xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000544 int i;
545 char shift[100];
546
547 for (i = 0;((i < depth) && (i < 25));i++)
548 shift[2 * i] = shift[2 * i + 1] = ' ';
549 shift[2 * i] = shift[2 * i + 1] = 0;
550
551 if (cur == NULL) {
552 fprintf(output, shift);
553 fprintf(output, "LocationSet is NULL !\n");
554 return;
555
556 }
557
558 for (i = 0;i < cur->locNr;i++) {
559 fprintf(output, shift);
560 fprintf(output, "%d : ", i + 1);
561 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
562 }
563}
Daniel Veillard017b1082001-06-21 11:20:21 +0000564#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000565
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000566/**
567 * xmlXPathDebugDumpObject:
568 * @output: the FILE * to dump the output
569 * @cur: the object to inspect
570 * @depth: indentation level
571 *
572 * Dump the content of the object for debugging purposes
573 */
574void
575xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000576 int i;
577 char shift[100];
578
579 for (i = 0;((i < depth) && (i < 25));i++)
580 shift[2 * i] = shift[2 * i + 1] = ' ';
581 shift[2 * i] = shift[2 * i + 1] = 0;
582
583 fprintf(output, shift);
584
585 if (cur == NULL) {
586 fprintf(output, "Object is empty (NULL)\n");
587 return;
588 }
589 switch(cur->type) {
590 case XPATH_UNDEFINED:
591 fprintf(output, "Object is uninitialized\n");
592 break;
593 case XPATH_NODESET:
594 fprintf(output, "Object is a Node Set :\n");
595 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
596 break;
597 case XPATH_XSLT_TREE:
598 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000599 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000600 break;
601 case XPATH_BOOLEAN:
602 fprintf(output, "Object is a Boolean : ");
603 if (cur->boolval) fprintf(output, "true\n");
604 else fprintf(output, "false\n");
605 break;
606 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000607 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000608 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000609 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000610 break;
611 case -1:
612 fprintf(output, "Object is a number : -Infinity\n");
613 break;
614 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000615 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000616 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000617 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
618 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000619 } else {
620 fprintf(output, "Object is a number : %0g\n", cur->floatval);
621 }
622 }
Owen Taylor3473f882001-02-23 17:55:21 +0000623 break;
624 case XPATH_STRING:
625 fprintf(output, "Object is a string : ");
626 xmlDebugDumpString(output, cur->stringval);
627 fprintf(output, "\n");
628 break;
629 case XPATH_POINT:
630 fprintf(output, "Object is a point : index %d in node", cur->index);
631 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
632 fprintf(output, "\n");
633 break;
634 case XPATH_RANGE:
635 if ((cur->user2 == NULL) ||
636 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
637 fprintf(output, "Object is a collapsed range :\n");
638 fprintf(output, shift);
639 if (cur->index >= 0)
640 fprintf(output, "index %d in ", cur->index);
641 fprintf(output, "node\n");
642 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
643 depth + 1);
644 } else {
645 fprintf(output, "Object is a range :\n");
646 fprintf(output, shift);
647 fprintf(output, "From ");
648 if (cur->index >= 0)
649 fprintf(output, "index %d in ", cur->index);
650 fprintf(output, "node\n");
651 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
652 depth + 1);
653 fprintf(output, shift);
654 fprintf(output, "To ");
655 if (cur->index2 >= 0)
656 fprintf(output, "index %d in ", cur->index2);
657 fprintf(output, "node\n");
658 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
659 depth + 1);
660 fprintf(output, "\n");
661 }
662 break;
663 case XPATH_LOCATIONSET:
664#if defined(LIBXML_XPTR_ENABLED)
665 fprintf(output, "Object is a Location Set:\n");
666 xmlXPathDebugDumpLocationSet(output,
667 (xmlLocationSetPtr) cur->user, depth);
668#endif
669 break;
670 case XPATH_USERS:
671 fprintf(output, "Object is user defined\n");
672 break;
673 }
674}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000675
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000676static void
677xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000678 xmlXPathStepOpPtr op, int depth) {
679 int i;
680 char shift[100];
681
682 for (i = 0;((i < depth) && (i < 25));i++)
683 shift[2 * i] = shift[2 * i + 1] = ' ';
684 shift[2 * i] = shift[2 * i + 1] = 0;
685
686 fprintf(output, shift);
687 if (op == NULL) {
688 fprintf(output, "Step is NULL\n");
689 return;
690 }
691 switch (op->op) {
692 case XPATH_OP_END:
693 fprintf(output, "END"); break;
694 case XPATH_OP_AND:
695 fprintf(output, "AND"); break;
696 case XPATH_OP_OR:
697 fprintf(output, "OR"); break;
698 case XPATH_OP_EQUAL:
699 if (op->value)
700 fprintf(output, "EQUAL =");
701 else
702 fprintf(output, "EQUAL !=");
703 break;
704 case XPATH_OP_CMP:
705 if (op->value)
706 fprintf(output, "CMP <");
707 else
708 fprintf(output, "CMP >");
709 if (!op->value2)
710 fprintf(output, "=");
711 break;
712 case XPATH_OP_PLUS:
713 if (op->value == 0)
714 fprintf(output, "PLUS -");
715 else if (op->value == 1)
716 fprintf(output, "PLUS +");
717 else if (op->value == 2)
718 fprintf(output, "PLUS unary -");
719 else if (op->value == 3)
720 fprintf(output, "PLUS unary - -");
721 break;
722 case XPATH_OP_MULT:
723 if (op->value == 0)
724 fprintf(output, "MULT *");
725 else if (op->value == 1)
726 fprintf(output, "MULT div");
727 else
728 fprintf(output, "MULT mod");
729 break;
730 case XPATH_OP_UNION:
731 fprintf(output, "UNION"); break;
732 case XPATH_OP_ROOT:
733 fprintf(output, "ROOT"); break;
734 case XPATH_OP_NODE:
735 fprintf(output, "NODE"); break;
736 case XPATH_OP_RESET:
737 fprintf(output, "RESET"); break;
738 case XPATH_OP_SORT:
739 fprintf(output, "SORT"); break;
740 case XPATH_OP_COLLECT: {
741 xmlXPathAxisVal axis = op->value;
742 xmlXPathTestVal test = op->value2;
743 xmlXPathTypeVal type = op->value3;
744 const xmlChar *prefix = op->value4;
745 const xmlChar *name = op->value5;
746
747 fprintf(output, "COLLECT ");
748 switch (axis) {
749 case AXIS_ANCESTOR:
750 fprintf(output, " 'ancestors' "); break;
751 case AXIS_ANCESTOR_OR_SELF:
752 fprintf(output, " 'ancestors-or-self' "); break;
753 case AXIS_ATTRIBUTE:
754 fprintf(output, " 'attributes' "); break;
755 case AXIS_CHILD:
756 fprintf(output, " 'child' "); break;
757 case AXIS_DESCENDANT:
758 fprintf(output, " 'descendant' "); break;
759 case AXIS_DESCENDANT_OR_SELF:
760 fprintf(output, " 'descendant-or-self' "); break;
761 case AXIS_FOLLOWING:
762 fprintf(output, " 'following' "); break;
763 case AXIS_FOLLOWING_SIBLING:
764 fprintf(output, " 'following-siblings' "); break;
765 case AXIS_NAMESPACE:
766 fprintf(output, " 'namespace' "); break;
767 case AXIS_PARENT:
768 fprintf(output, " 'parent' "); break;
769 case AXIS_PRECEDING:
770 fprintf(output, " 'preceding' "); break;
771 case AXIS_PRECEDING_SIBLING:
772 fprintf(output, " 'preceding-sibling' "); break;
773 case AXIS_SELF:
774 fprintf(output, " 'self' "); break;
775 }
776 switch (test) {
777 case NODE_TEST_NONE:
778 fprintf(output, "'none' "); break;
779 case NODE_TEST_TYPE:
780 fprintf(output, "'type' "); break;
781 case NODE_TEST_PI:
782 fprintf(output, "'PI' "); break;
783 case NODE_TEST_ALL:
784 fprintf(output, "'all' "); break;
785 case NODE_TEST_NS:
786 fprintf(output, "'namespace' "); break;
787 case NODE_TEST_NAME:
788 fprintf(output, "'name' "); break;
789 }
790 switch (type) {
791 case NODE_TYPE_NODE:
792 fprintf(output, "'node' "); break;
793 case NODE_TYPE_COMMENT:
794 fprintf(output, "'comment' "); break;
795 case NODE_TYPE_TEXT:
796 fprintf(output, "'text' "); break;
797 case NODE_TYPE_PI:
798 fprintf(output, "'PI' "); break;
799 }
800 if (prefix != NULL)
801 fprintf(output, "%s:", prefix);
802 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000803 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000804 break;
805
806 }
807 case XPATH_OP_VALUE: {
808 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
809
810 fprintf(output, "ELEM ");
811 xmlXPathDebugDumpObject(output, object, 0);
812 goto finish;
813 }
814 case XPATH_OP_VARIABLE: {
815 const xmlChar *prefix = op->value5;
816 const xmlChar *name = op->value4;
817
818 if (prefix != NULL)
819 fprintf(output, "VARIABLE %s:%s", prefix, name);
820 else
821 fprintf(output, "VARIABLE %s", name);
822 break;
823 }
824 case XPATH_OP_FUNCTION: {
825 int nbargs = op->value;
826 const xmlChar *prefix = op->value5;
827 const xmlChar *name = op->value4;
828
829 if (prefix != NULL)
830 fprintf(output, "FUNCTION %s:%s(%d args)",
831 prefix, name, nbargs);
832 else
833 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
834 break;
835 }
836 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
837 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000838 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000839#ifdef LIBXML_XPTR_ENABLED
840 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
841#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000842 default:
843 fprintf(output, "UNKNOWN %d\n", op->op); return;
844 }
845 fprintf(output, "\n");
846finish:
847 if (op->ch1 >= 0)
848 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
849 if (op->ch2 >= 0)
850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
851}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000852
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000853/**
854 * xmlXPathDebugDumpCompExpr:
855 * @output: the FILE * for the output
856 * @comp: the precompiled XPath expression
857 * @depth: the indentation level.
858 *
859 * Dumps the tree of the compiled XPath expression.
860 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000861void
862xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
863 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000864 int i;
865 char shift[100];
866
867 for (i = 0;((i < depth) && (i < 25));i++)
868 shift[2 * i] = shift[2 * i + 1] = ' ';
869 shift[2 * i] = shift[2 * i + 1] = 0;
870
871 fprintf(output, shift);
872
873 if (comp == NULL) {
874 fprintf(output, "Compiled Expression is NULL\n");
875 return;
876 }
877 fprintf(output, "Compiled Expression : %d elements\n",
878 comp->nbStep);
879 i = comp->last;
880 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
881}
Daniel Veillard017b1082001-06-21 11:20:21 +0000882#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000883
884/************************************************************************
885 * *
886 * Parser stacks related functions and macros *
887 * *
888 ************************************************************************/
889
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000890/**
891 * valuePop:
892 * @ctxt: an XPath evaluation context
893 *
894 * Pops the top XPath object from the value stack
895 *
896 * Returns the XPath object just removed
897 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000898extern xmlXPathObjectPtr
899valuePop(xmlXPathParserContextPtr ctxt)
900{
901 xmlXPathObjectPtr ret;
902
903 if (ctxt->valueNr <= 0)
904 return (0);
905 ctxt->valueNr--;
906 if (ctxt->valueNr > 0)
907 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
908 else
909 ctxt->value = NULL;
910 ret = ctxt->valueTab[ctxt->valueNr];
911 ctxt->valueTab[ctxt->valueNr] = 0;
912 return (ret);
913}
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000914/**
915 * valuePush:
916 * @ctxt: an XPath evaluation context
917 * @value: the XPath object
918 *
919 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000920 *
921 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000922 */
Daniel Veillard1c732d22002-11-30 11:22:59 +0000923extern int
924valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
925{
926 if (ctxt->valueNr >= ctxt->valueMax) {
927 ctxt->valueMax *= 2;
928 ctxt->valueTab =
929 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
930 ctxt->valueMax *
931 sizeof(ctxt->valueTab[0]));
932 if (ctxt->valueTab == NULL) {
933 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
934 return (0);
935 }
936 }
937 ctxt->valueTab[ctxt->valueNr] = value;
938 ctxt->value = value;
939 return (ctxt->valueNr++);
940}
Owen Taylor3473f882001-02-23 17:55:21 +0000941
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000942/**
943 * xmlXPathPopBoolean:
944 * @ctxt: an XPath parser context
945 *
946 * Pops a boolean from the stack, handling conversion if needed.
947 * Check error with #xmlXPathCheckError.
948 *
949 * Returns the boolean
950 */
951int
952xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
953 xmlXPathObjectPtr obj;
954 int ret;
955
956 obj = valuePop(ctxt);
957 if (obj == NULL) {
958 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
959 return(0);
960 }
961 ret = xmlXPathCastToBoolean(obj);
962 xmlXPathFreeObject(obj);
963 return(ret);
964}
965
966/**
967 * xmlXPathPopNumber:
968 * @ctxt: an XPath parser context
969 *
970 * Pops a number from the stack, handling conversion if needed.
971 * Check error with #xmlXPathCheckError.
972 *
973 * Returns the number
974 */
975double
976xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
977 xmlXPathObjectPtr obj;
978 double ret;
979
980 obj = valuePop(ctxt);
981 if (obj == NULL) {
982 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
983 return(0);
984 }
985 ret = xmlXPathCastToNumber(obj);
986 xmlXPathFreeObject(obj);
987 return(ret);
988}
989
990/**
991 * xmlXPathPopString:
992 * @ctxt: an XPath parser context
993 *
994 * Pops a string from the stack, handling conversion if needed.
995 * Check error with #xmlXPathCheckError.
996 *
997 * Returns the string
998 */
999xmlChar *
1000xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1001 xmlXPathObjectPtr obj;
1002 xmlChar * ret;
1003
1004 obj = valuePop(ctxt);
1005 if (obj == NULL) {
1006 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1007 return(NULL);
1008 }
1009 ret = xmlXPathCastToString(obj);
1010 /* TODO: needs refactoring somewhere else */
1011 if (obj->stringval == ret)
1012 obj->stringval = NULL;
1013 xmlXPathFreeObject(obj);
1014 return(ret);
1015}
1016
1017/**
1018 * xmlXPathPopNodeSet:
1019 * @ctxt: an XPath parser context
1020 *
1021 * Pops a node-set from the stack, handling conversion if needed.
1022 * Check error with #xmlXPathCheckError.
1023 *
1024 * Returns the node-set
1025 */
1026xmlNodeSetPtr
1027xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1028 xmlXPathObjectPtr obj;
1029 xmlNodeSetPtr ret;
1030
1031 if (ctxt->value == NULL) {
1032 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1033 return(NULL);
1034 }
1035 if (!xmlXPathStackIsNodeSet(ctxt)) {
1036 xmlXPathSetTypeError(ctxt);
1037 return(NULL);
1038 }
1039 obj = valuePop(ctxt);
1040 ret = obj->nodesetval;
Daniel Veillard9deb2422003-07-28 20:40:59 +00001041 /* to fix memory leak of not clearing obj->user */
1042 if (obj->boolval && obj->user != NULL)
1043 xmlFreeNodeList((xmlNodePtr) obj->user);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001044 xmlXPathFreeNodeSetList(obj);
1045 return(ret);
1046}
1047
1048/**
1049 * xmlXPathPopExternal:
1050 * @ctxt: an XPath parser context
1051 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001052 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001053 * Check error with #xmlXPathCheckError.
1054 *
1055 * Returns the object
1056 */
1057void *
1058xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1059 xmlXPathObjectPtr obj;
1060 void * ret;
1061
1062 if (ctxt->value == NULL) {
1063 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1064 return(NULL);
1065 }
1066 if (ctxt->value->type != XPATH_USERS) {
1067 xmlXPathSetTypeError(ctxt);
1068 return(NULL);
1069 }
1070 obj = valuePop(ctxt);
1071 ret = obj->user;
1072 xmlXPathFreeObject(obj);
1073 return(ret);
1074}
1075
Owen Taylor3473f882001-02-23 17:55:21 +00001076/*
1077 * Macros for accessing the content. Those should be used only by the parser,
1078 * and not exported.
1079 *
1080 * Dirty macros, i.e. one need to make assumption on the context to use them
1081 *
1082 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1083 * CUR returns the current xmlChar value, i.e. a 8 bit value
1084 * in ISO-Latin or UTF-8.
1085 * This should be used internally by the parser
1086 * only to compare to ASCII values otherwise it would break when
1087 * running with UTF-8 encoding.
1088 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1089 * to compare on ASCII based substring.
1090 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1091 * strings within the parser.
1092 * CURRENT Returns the current char value, with the full decoding of
1093 * UTF-8 if we are using this mode. It returns an int.
1094 * NEXT Skip to the next character, this does the proper decoding
1095 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1096 * It returns the pointer to the current xmlChar.
1097 */
1098
1099#define CUR (*ctxt->cur)
1100#define SKIP(val) ctxt->cur += (val)
1101#define NXT(val) ctxt->cur[(val)]
1102#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001103#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1104
1105#define COPY_BUF(l,b,i,v) \
1106 if (l == 1) b[i++] = (xmlChar) v; \
1107 else i += xmlCopyChar(l,&b[i],v)
1108
1109#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001110
1111#define SKIP_BLANKS \
1112 while (IS_BLANK(*(ctxt->cur))) NEXT
1113
1114#define CURRENT (*ctxt->cur)
1115#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1116
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001117
1118#ifndef DBL_DIG
1119#define DBL_DIG 16
1120#endif
1121#ifndef DBL_EPSILON
1122#define DBL_EPSILON 1E-9
1123#endif
1124
1125#define UPPER_DOUBLE 1E9
1126#define LOWER_DOUBLE 1E-5
1127
1128#define INTEGER_DIGITS DBL_DIG
1129#define FRACTION_DIGITS (DBL_DIG + 1)
1130#define EXPONENT_DIGITS (3 + 2)
1131
1132/**
1133 * xmlXPathFormatNumber:
1134 * @number: number to format
1135 * @buffer: output buffer
1136 * @buffersize: size of output buffer
1137 *
1138 * Convert the number into a string representation.
1139 */
1140static void
1141xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1142{
Daniel Veillardcda96922001-08-21 10:56:31 +00001143 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001144 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001145 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001146 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001147 break;
1148 case -1:
1149 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001150 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001151 break;
1152 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001153 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001154 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001155 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001156 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001157 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001158 } else if (number == ((int) number)) {
1159 char work[30];
1160 char *ptr, *cur;
1161 int res, value = (int) number;
1162
1163 ptr = &buffer[0];
1164 if (value < 0) {
1165 *ptr++ = '-';
1166 value = -value;
1167 }
1168 if (value == 0) {
1169 *ptr++ = '0';
1170 } else {
1171 cur = &work[0];
1172 while (value != 0) {
1173 res = value % 10;
1174 value = value / 10;
1175 *cur++ = '0' + res;
1176 }
1177 cur--;
1178 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1179 *ptr++ = *cur--;
1180 }
1181 }
1182 if (ptr - buffer < buffersize) {
1183 *ptr = 0;
1184 } else if (buffersize > 0) {
1185 ptr--;
1186 *ptr = 0;
1187 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001188 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001189 /* 3 is sign, decimal point, and terminating zero */
1190 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1191 int integer_place, fraction_place;
1192 char *ptr;
1193 char *after_fraction;
1194 double absolute_value;
1195 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001196
Bjorn Reese70a9da52001-04-21 16:57:29 +00001197 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001198
Bjorn Reese70a9da52001-04-21 16:57:29 +00001199 /*
1200 * First choose format - scientific or regular floating point.
1201 * In either case, result is in work, and after_fraction points
1202 * just past the fractional part.
1203 */
1204 if ( ((absolute_value > UPPER_DOUBLE) ||
1205 (absolute_value < LOWER_DOUBLE)) &&
1206 (absolute_value != 0.0) ) {
1207 /* Use scientific notation */
1208 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1209 fraction_place = DBL_DIG - 1;
1210 snprintf(work, sizeof(work),"%*.*e",
1211 integer_place, fraction_place, number);
1212 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001213 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001214 else {
1215 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001216 if (absolute_value > 0.0)
1217 integer_place = 1 + (int)log10(absolute_value);
1218 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001219 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001220 fraction_place = (integer_place > 0)
1221 ? DBL_DIG - integer_place
1222 : DBL_DIG;
1223 size = snprintf(work, sizeof(work), "%0.*f",
1224 fraction_place, number);
1225 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001226 }
1227
Bjorn Reese70a9da52001-04-21 16:57:29 +00001228 /* Remove fractional trailing zeroes */
1229 ptr = after_fraction;
1230 while (*(--ptr) == '0')
1231 ;
1232 if (*ptr != '.')
1233 ptr++;
1234 strcpy(ptr, after_fraction);
1235
1236 /* Finally copy result back to caller */
1237 size = strlen(work) + 1;
1238 if (size > buffersize) {
1239 work[buffersize - 1] = 0;
1240 size = buffersize;
1241 }
1242 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001243 }
1244 break;
1245 }
1246}
1247
Owen Taylor3473f882001-02-23 17:55:21 +00001248/************************************************************************
1249 * *
1250 * Error handling routines *
1251 * *
1252 ************************************************************************/
1253
1254
Daniel Veillardb44025c2001-10-11 22:55:55 +00001255static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001256 "Ok",
1257 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001258 "Unfinished literal",
1259 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001260 "Expected $ for variable reference",
1261 "Undefined variable",
1262 "Invalid predicate",
1263 "Invalid expression",
1264 "Missing closing curly brace",
1265 "Unregistered function",
1266 "Invalid operand",
1267 "Invalid type",
1268 "Invalid number of arguments",
1269 "Invalid context size",
1270 "Invalid context position",
1271 "Memory allocation error",
1272 "Syntax error",
1273 "Resource error",
1274 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001275 "Undefined namespace prefix",
1276 "Encoding error",
1277 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001278};
1279
1280/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001281 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001282 * @ctxt: the XPath Parser context
1283 * @file: the file name
1284 * @line: the line number
1285 * @no: the error number
1286 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001287 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001288 */
1289void
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001290xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1291 int line ATTRIBUTE_UNUSED, int no) {
Owen Taylor3473f882001-02-23 17:55:21 +00001292 int n;
1293 const xmlChar *cur;
1294 const xmlChar *base;
1295
Owen Taylor3473f882001-02-23 17:55:21 +00001296 cur = ctxt->cur;
1297 base = ctxt->base;
Daniel Veillard118aed72002-09-24 14:13:13 +00001298 if ((cur == NULL) || (base == NULL)) {
1299 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1300 xmlGenericError(xmlGenericErrorContext,
1301 "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1302 ctxt->comp->expr);
1303 } else {
1304 xmlGenericError(xmlGenericErrorContext,
1305 "XPath error %s\n", xmlXPathErrorMessages[no]);
1306 }
1307
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001308 return;
Daniel Veillard118aed72002-09-24 14:13:13 +00001309 }
1310 xmlGenericError(xmlGenericErrorContext,
1311 "XPath error %s\n", xmlXPathErrorMessages[no]);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001312
Owen Taylor3473f882001-02-23 17:55:21 +00001313 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1314 cur--;
1315 }
1316 n = 0;
1317 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1318 cur--;
1319 if ((*cur == '\n') || (*cur == '\r')) cur++;
1320 base = cur;
1321 n = 0;
1322 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1323 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1324 n++;
1325 }
1326 xmlGenericError(xmlGenericErrorContext, "\n");
1327 cur = ctxt->cur;
1328 while ((*cur == '\n') || (*cur == '\r'))
1329 cur--;
1330 n = 0;
1331 while ((cur != base) && (n++ < 80)) {
1332 xmlGenericError(xmlGenericErrorContext, " ");
1333 base++;
1334 }
1335 xmlGenericError(xmlGenericErrorContext,"^\n");
1336}
1337
1338
1339/************************************************************************
1340 * *
1341 * Routines to handle NodeSets *
1342 * *
1343 ************************************************************************/
1344
1345/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001346 * xmlXPathOrderDocElems:
1347 * @doc: an input document
1348 *
1349 * Call this routine to speed up XPath computation on static documents.
1350 * This stamps all the element nodes with the document order
1351 * Like for line information, the order is kept in the element->content
1352 * field, the value stored is actually - the node number (startting at -1)
1353 * to be able to differenciate from line numbers.
1354 *
1355 * Returns the number of element found in the document or -1 in case
1356 * of error.
1357 */
1358long
1359xmlXPathOrderDocElems(xmlDocPtr doc) {
1360 long count = 0;
1361 xmlNodePtr cur;
1362
1363 if (doc == NULL)
1364 return(-1);
1365 cur = doc->children;
1366 while (cur != NULL) {
1367 if (cur->type == XML_ELEMENT_NODE) {
1368 cur->content = (void *) (-(++count));
1369 if (cur->children != NULL) {
1370 cur = cur->children;
1371 continue;
1372 }
1373 }
1374 if (cur->next != NULL) {
1375 cur = cur->next;
1376 continue;
1377 }
1378 do {
1379 cur = cur->parent;
1380 if (cur == NULL)
1381 break;
1382 if (cur == (xmlNodePtr) doc) {
1383 cur = NULL;
1384 break;
1385 }
1386 if (cur->next != NULL) {
1387 cur = cur->next;
1388 break;
1389 }
1390 } while (cur != NULL);
1391 }
1392 return(count);
1393}
1394
1395/**
Owen Taylor3473f882001-02-23 17:55:21 +00001396 * xmlXPathCmpNodes:
1397 * @node1: the first node
1398 * @node2: the second node
1399 *
1400 * Compare two nodes w.r.t document order
1401 *
1402 * Returns -2 in case of error 1 if first point < second point, 0 if
1403 * that's the same node, -1 otherwise
1404 */
1405int
1406xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1407 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001408 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001409 xmlNodePtr cur, root;
1410
1411 if ((node1 == NULL) || (node2 == NULL))
1412 return(-2);
1413 /*
1414 * a couple of optimizations which will avoid computations in most cases
1415 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001416 if (node1->type == XML_ATTRIBUTE_NODE) {
1417 attr1 = 1;
1418 node1 = node1->parent;
1419 }
1420 if (node2->type == XML_ATTRIBUTE_NODE) {
1421 attr2 = 1;
1422 node2 = node2->parent;
1423 }
1424 if (node1 == node2) {
1425 if (attr1 == attr2)
1426 return(0);
1427 if (attr2 == 1)
1428 return(1);
1429 return(-1);
1430 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001431 if ((node1->type == XML_NAMESPACE_DECL) ||
1432 (node2->type == XML_NAMESPACE_DECL))
1433 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001434 if (node1 == node2->prev)
1435 return(1);
1436 if (node1 == node2->next)
1437 return(-1);
1438
1439 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001440 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001441 */
1442 if ((node1->type == XML_ELEMENT_NODE) &&
1443 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001444 (0 > (long) node1->content) &&
1445 (0 > (long) node2->content) &&
1446 (node1->doc == node2->doc)) {
1447 long l1, l2;
1448
1449 l1 = -((long) node1->content);
1450 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001451 if (l1 < l2)
1452 return(1);
1453 if (l1 > l2)
1454 return(-1);
1455 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001456
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001457 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001458 * compute depth to root
1459 */
1460 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1461 if (cur == node1)
1462 return(1);
1463 depth2++;
1464 }
1465 root = cur;
1466 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1467 if (cur == node2)
1468 return(-1);
1469 depth1++;
1470 }
1471 /*
1472 * Distinct document (or distinct entities :-( ) case.
1473 */
1474 if (root != cur) {
1475 return(-2);
1476 }
1477 /*
1478 * get the nearest common ancestor.
1479 */
1480 while (depth1 > depth2) {
1481 depth1--;
1482 node1 = node1->parent;
1483 }
1484 while (depth2 > depth1) {
1485 depth2--;
1486 node2 = node2->parent;
1487 }
1488 while (node1->parent != node2->parent) {
1489 node1 = node1->parent;
1490 node2 = node2->parent;
1491 /* should not happen but just in case ... */
1492 if ((node1 == NULL) || (node2 == NULL))
1493 return(-2);
1494 }
1495 /*
1496 * Find who's first.
1497 */
1498 if (node1 == node2->next)
1499 return(-1);
1500 for (cur = node1->next;cur != NULL;cur = cur->next)
1501 if (cur == node2)
1502 return(1);
1503 return(-1); /* assume there is no sibling list corruption */
1504}
1505
1506/**
1507 * xmlXPathNodeSetSort:
1508 * @set: the node set
1509 *
1510 * Sort the node set in document order
1511 */
1512void
1513xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001514 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001515 xmlNodePtr tmp;
1516
1517 if (set == NULL)
1518 return;
1519
1520 /* Use Shell's sort to sort the node-set */
1521 len = set->nodeNr;
1522 for (incr = len / 2; incr > 0; incr /= 2) {
1523 for (i = incr; i < len; i++) {
1524 j = i - incr;
1525 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001526 if (xmlXPathCmpNodes(set->nodeTab[j],
1527 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001528 tmp = set->nodeTab[j];
1529 set->nodeTab[j] = set->nodeTab[j + incr];
1530 set->nodeTab[j + incr] = tmp;
1531 j -= incr;
1532 } else
1533 break;
1534 }
1535 }
1536 }
1537}
1538
1539#define XML_NODESET_DEFAULT 10
1540/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001541 * xmlXPathNodeSetDupNs:
1542 * @node: the parent node of the namespace XPath node
1543 * @ns: the libxml namespace declaration node.
1544 *
1545 * Namespace node in libxml don't match the XPath semantic. In a node set
1546 * the namespace nodes are duplicated and the next pointer is set to the
1547 * parent node in the XPath semantic.
1548 *
1549 * Returns the newly created object.
1550 */
1551static xmlNodePtr
1552xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1553 xmlNsPtr cur;
1554
1555 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1556 return(NULL);
1557 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1558 return((xmlNodePtr) ns);
1559
1560 /*
1561 * Allocate a new Namespace and fill the fields.
1562 */
1563 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1564 if (cur == NULL) {
1565 xmlGenericError(xmlGenericErrorContext,
1566 "xmlXPathNodeSetDupNs : malloc failed\n");
1567 return(NULL);
1568 }
1569 memset(cur, 0, sizeof(xmlNs));
1570 cur->type = XML_NAMESPACE_DECL;
1571 if (ns->href != NULL)
1572 cur->href = xmlStrdup(ns->href);
1573 if (ns->prefix != NULL)
1574 cur->prefix = xmlStrdup(ns->prefix);
1575 cur->next = (xmlNsPtr) node;
1576 return((xmlNodePtr) cur);
1577}
1578
1579/**
1580 * xmlXPathNodeSetFreeNs:
1581 * @ns: the XPath namespace node found in a nodeset.
1582 *
1583 * Namespace node in libxml don't match the XPath semantic. In a node set
1584 * the namespace nodes are duplicated and the next pointer is set to the
1585 * parent node in the XPath semantic. Check if such a node need to be freed
1586 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001587void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001588xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1589 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1590 return;
1591
1592 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1593 if (ns->href != NULL)
1594 xmlFree((xmlChar *)ns->href);
1595 if (ns->prefix != NULL)
1596 xmlFree((xmlChar *)ns->prefix);
1597 xmlFree(ns);
1598 }
1599}
1600
1601/**
Owen Taylor3473f882001-02-23 17:55:21 +00001602 * xmlXPathNodeSetCreate:
1603 * @val: an initial xmlNodePtr, or NULL
1604 *
1605 * Create a new xmlNodeSetPtr of type double and of value @val
1606 *
1607 * Returns the newly created object.
1608 */
1609xmlNodeSetPtr
1610xmlXPathNodeSetCreate(xmlNodePtr val) {
1611 xmlNodeSetPtr ret;
1612
1613 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1614 if (ret == NULL) {
1615 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001616 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001617 return(NULL);
1618 }
1619 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1620 if (val != NULL) {
1621 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1622 sizeof(xmlNodePtr));
1623 if (ret->nodeTab == NULL) {
1624 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001625 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001626 return(NULL);
1627 }
1628 memset(ret->nodeTab, 0 ,
1629 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1630 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001631 if (val->type == XML_NAMESPACE_DECL) {
1632 xmlNsPtr ns = (xmlNsPtr) val;
1633
1634 ret->nodeTab[ret->nodeNr++] =
1635 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1636 } else
1637 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001638 }
1639 return(ret);
1640}
1641
1642/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001643 * xmlXPathNodeSetContains:
1644 * @cur: the node-set
1645 * @val: the node
1646 *
1647 * checks whether @cur contains @val
1648 *
1649 * Returns true (1) if @cur contains @val, false (0) otherwise
1650 */
1651int
1652xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1653 int i;
1654
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001655 if (val->type == XML_NAMESPACE_DECL) {
1656 for (i = 0; i < cur->nodeNr; i++) {
1657 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1658 xmlNsPtr ns1, ns2;
1659
1660 ns1 = (xmlNsPtr) val;
1661 ns2 = (xmlNsPtr) cur->nodeTab[i];
1662 if (ns1 == ns2)
1663 return(1);
1664 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1665 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1666 return(1);
1667 }
1668 }
1669 } else {
1670 for (i = 0; i < cur->nodeNr; i++) {
1671 if (cur->nodeTab[i] == val)
1672 return(1);
1673 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001674 }
1675 return(0);
1676}
1677
1678/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001679 * xmlXPathNodeSetAddNs:
1680 * @cur: the initial node set
1681 * @node: the hosting node
1682 * @ns: a the namespace node
1683 *
1684 * add a new namespace node to an existing NodeSet
1685 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001686void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001687xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1688 int i;
1689
1690 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1691 (node->type != XML_ELEMENT_NODE))
1692 return;
1693
1694 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1695 /*
1696 * check against doublons
1697 */
1698 for (i = 0;i < cur->nodeNr;i++) {
1699 if ((cur->nodeTab[i] != NULL) &&
1700 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001701 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001702 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1703 return;
1704 }
1705
1706 /*
1707 * grow the nodeTab if needed
1708 */
1709 if (cur->nodeMax == 0) {
1710 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1711 sizeof(xmlNodePtr));
1712 if (cur->nodeTab == NULL) {
1713 xmlGenericError(xmlGenericErrorContext,
1714 "xmlXPathNodeSetAdd: out of memory\n");
1715 return;
1716 }
1717 memset(cur->nodeTab, 0 ,
1718 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1719 cur->nodeMax = XML_NODESET_DEFAULT;
1720 } else if (cur->nodeNr == cur->nodeMax) {
1721 xmlNodePtr *temp;
1722
1723 cur->nodeMax *= 2;
1724 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1725 sizeof(xmlNodePtr));
1726 if (temp == NULL) {
1727 xmlGenericError(xmlGenericErrorContext,
1728 "xmlXPathNodeSetAdd: out of memory\n");
1729 return;
1730 }
1731 cur->nodeTab = temp;
1732 }
1733 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1734}
1735
1736/**
Owen Taylor3473f882001-02-23 17:55:21 +00001737 * xmlXPathNodeSetAdd:
1738 * @cur: the initial node set
1739 * @val: a new xmlNodePtr
1740 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001741 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001742 */
1743void
1744xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1745 int i;
1746
1747 if (val == NULL) return;
1748
Daniel Veillardef0b4502003-03-24 13:57:34 +00001749#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001750 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1751 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001752#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001753
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001754 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001755 /*
1756 * check against doublons
1757 */
1758 for (i = 0;i < cur->nodeNr;i++)
1759 if (cur->nodeTab[i] == val) return;
1760
1761 /*
1762 * grow the nodeTab if needed
1763 */
1764 if (cur->nodeMax == 0) {
1765 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1766 sizeof(xmlNodePtr));
1767 if (cur->nodeTab == NULL) {
1768 xmlGenericError(xmlGenericErrorContext,
1769 "xmlXPathNodeSetAdd: out of memory\n");
1770 return;
1771 }
1772 memset(cur->nodeTab, 0 ,
1773 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1774 cur->nodeMax = XML_NODESET_DEFAULT;
1775 } else if (cur->nodeNr == cur->nodeMax) {
1776 xmlNodePtr *temp;
1777
1778 cur->nodeMax *= 2;
1779 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1780 sizeof(xmlNodePtr));
1781 if (temp == NULL) {
1782 xmlGenericError(xmlGenericErrorContext,
1783 "xmlXPathNodeSetAdd: out of memory\n");
1784 return;
1785 }
1786 cur->nodeTab = temp;
1787 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001788 if (val->type == XML_NAMESPACE_DECL) {
1789 xmlNsPtr ns = (xmlNsPtr) val;
1790
1791 cur->nodeTab[cur->nodeNr++] =
1792 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1793 } else
1794 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001795}
1796
1797/**
1798 * xmlXPathNodeSetAddUnique:
1799 * @cur: the initial node set
1800 * @val: a new xmlNodePtr
1801 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001802 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001803 * when we are sure the node is not already in the set.
1804 */
1805void
1806xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1807 if (val == NULL) return;
1808
Daniel Veillardef0b4502003-03-24 13:57:34 +00001809#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001810 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1811 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001812#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001813
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001814 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001815 /*
1816 * grow the nodeTab if needed
1817 */
1818 if (cur->nodeMax == 0) {
1819 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1820 sizeof(xmlNodePtr));
1821 if (cur->nodeTab == NULL) {
1822 xmlGenericError(xmlGenericErrorContext,
1823 "xmlXPathNodeSetAddUnique: out of memory\n");
1824 return;
1825 }
1826 memset(cur->nodeTab, 0 ,
1827 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1828 cur->nodeMax = XML_NODESET_DEFAULT;
1829 } else if (cur->nodeNr == cur->nodeMax) {
1830 xmlNodePtr *temp;
1831
1832 cur->nodeMax *= 2;
1833 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1834 sizeof(xmlNodePtr));
1835 if (temp == NULL) {
1836 xmlGenericError(xmlGenericErrorContext,
1837 "xmlXPathNodeSetAddUnique: out of memory\n");
1838 return;
1839 }
1840 cur->nodeTab = temp;
1841 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001842 if (val->type == XML_NAMESPACE_DECL) {
1843 xmlNsPtr ns = (xmlNsPtr) val;
1844
1845 cur->nodeTab[cur->nodeNr++] =
1846 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1847 } else
1848 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001849}
1850
1851/**
1852 * xmlXPathNodeSetMerge:
1853 * @val1: the first NodeSet or NULL
1854 * @val2: the second NodeSet
1855 *
1856 * Merges two nodesets, all nodes from @val2 are added to @val1
1857 * if @val1 is NULL, a new set is created and copied from @val2
1858 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001859 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001860 */
1861xmlNodeSetPtr
1862xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001863 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001864
1865 if (val2 == NULL) return(val1);
1866 if (val1 == NULL) {
1867 val1 = xmlXPathNodeSetCreate(NULL);
1868 }
1869
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001870 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001871 initNr = val1->nodeNr;
1872
1873 for (i = 0;i < val2->nodeNr;i++) {
1874 /*
1875 * check against doublons
1876 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001877 skip = 0;
1878 for (j = 0; j < initNr; j++) {
1879 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1880 skip = 1;
1881 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001882 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1883 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1884 xmlNsPtr ns1, ns2;
1885 ns1 = (xmlNsPtr) val1->nodeTab[j];
1886 ns2 = (xmlNsPtr) val2->nodeTab[i];
1887 if ((ns1->next == ns2->next) &&
1888 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1889 skip = 1;
1890 break;
1891 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001892 }
1893 }
1894 if (skip)
1895 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001896
1897 /*
1898 * grow the nodeTab if needed
1899 */
1900 if (val1->nodeMax == 0) {
1901 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1902 sizeof(xmlNodePtr));
1903 if (val1->nodeTab == NULL) {
1904 xmlGenericError(xmlGenericErrorContext,
1905 "xmlXPathNodeSetMerge: out of memory\n");
1906 return(NULL);
1907 }
1908 memset(val1->nodeTab, 0 ,
1909 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1910 val1->nodeMax = XML_NODESET_DEFAULT;
1911 } else if (val1->nodeNr == val1->nodeMax) {
1912 xmlNodePtr *temp;
1913
1914 val1->nodeMax *= 2;
1915 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1916 sizeof(xmlNodePtr));
1917 if (temp == NULL) {
1918 xmlGenericError(xmlGenericErrorContext,
1919 "xmlXPathNodeSetMerge: out of memory\n");
1920 return(NULL);
1921 }
1922 val1->nodeTab = temp;
1923 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001924 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1925 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1926
1927 val1->nodeTab[val1->nodeNr++] =
1928 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1929 } else
1930 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001931 }
1932
1933 return(val1);
1934}
1935
1936/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001937 * xmlXPathNodeSetMergeUnique:
1938 * @val1: the first NodeSet or NULL
1939 * @val2: the second NodeSet
1940 *
1941 * Merges two nodesets, all nodes from @val2 are added to @val1
1942 * if @val1 is NULL, a new set is created and copied from @val2
1943 *
1944 * Returns @val1 once extended or NULL in case of error.
1945 */
1946static xmlNodeSetPtr
1947xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1948 int i, initNr;
1949
1950 if (val2 == NULL) return(val1);
1951 if (val1 == NULL) {
1952 val1 = xmlXPathNodeSetCreate(NULL);
1953 }
1954
1955 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1956 initNr = val1->nodeNr;
1957
1958 for (i = 0;i < val2->nodeNr;i++) {
1959 /*
1960 * grow the nodeTab if needed
1961 */
1962 if (val1->nodeMax == 0) {
1963 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1964 sizeof(xmlNodePtr));
1965 if (val1->nodeTab == NULL) {
1966 xmlGenericError(xmlGenericErrorContext,
1967 "xmlXPathNodeSetMerge: out of memory\n");
1968 return(NULL);
1969 }
1970 memset(val1->nodeTab, 0 ,
1971 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1972 val1->nodeMax = XML_NODESET_DEFAULT;
1973 } else if (val1->nodeNr == val1->nodeMax) {
1974 xmlNodePtr *temp;
1975
1976 val1->nodeMax *= 2;
1977 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1978 sizeof(xmlNodePtr));
1979 if (temp == NULL) {
1980 xmlGenericError(xmlGenericErrorContext,
1981 "xmlXPathNodeSetMerge: out of memory\n");
1982 return(NULL);
1983 }
1984 val1->nodeTab = temp;
1985 }
1986 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1987 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1988
1989 val1->nodeTab[val1->nodeNr++] =
1990 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1991 } else
1992 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1993 }
1994
1995 return(val1);
1996}
1997
1998/**
Owen Taylor3473f882001-02-23 17:55:21 +00001999 * xmlXPathNodeSetDel:
2000 * @cur: the initial node set
2001 * @val: an xmlNodePtr
2002 *
2003 * Removes an xmlNodePtr from an existing NodeSet
2004 */
2005void
2006xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2007 int i;
2008
2009 if (cur == NULL) return;
2010 if (val == NULL) return;
2011
2012 /*
2013 * check against doublons
2014 */
2015 for (i = 0;i < cur->nodeNr;i++)
2016 if (cur->nodeTab[i] == val) break;
2017
2018 if (i >= cur->nodeNr) {
2019#ifdef DEBUG
2020 xmlGenericError(xmlGenericErrorContext,
2021 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2022 val->name);
2023#endif
2024 return;
2025 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002026 if ((cur->nodeTab[i] != NULL) &&
2027 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2028 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002029 cur->nodeNr--;
2030 for (;i < cur->nodeNr;i++)
2031 cur->nodeTab[i] = cur->nodeTab[i + 1];
2032 cur->nodeTab[cur->nodeNr] = NULL;
2033}
2034
2035/**
2036 * xmlXPathNodeSetRemove:
2037 * @cur: the initial node set
2038 * @val: the index to remove
2039 *
2040 * Removes an entry from an existing NodeSet list.
2041 */
2042void
2043xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2044 if (cur == NULL) return;
2045 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002046 if ((cur->nodeTab[val] != NULL) &&
2047 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2048 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002049 cur->nodeNr--;
2050 for (;val < cur->nodeNr;val++)
2051 cur->nodeTab[val] = cur->nodeTab[val + 1];
2052 cur->nodeTab[cur->nodeNr] = NULL;
2053}
2054
2055/**
2056 * xmlXPathFreeNodeSet:
2057 * @obj: the xmlNodeSetPtr to free
2058 *
2059 * Free the NodeSet compound (not the actual nodes !).
2060 */
2061void
2062xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2063 if (obj == NULL) return;
2064 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002065 int i;
2066
2067 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2068 for (i = 0;i < obj->nodeNr;i++)
2069 if ((obj->nodeTab[i] != NULL) &&
2070 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2071 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002072 xmlFree(obj->nodeTab);
2073 }
Owen Taylor3473f882001-02-23 17:55:21 +00002074 xmlFree(obj);
2075}
2076
2077/**
2078 * xmlXPathFreeValueTree:
2079 * @obj: the xmlNodeSetPtr to free
2080 *
2081 * Free the NodeSet compound and the actual tree, this is different
2082 * from xmlXPathFreeNodeSet()
2083 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002084static void
Owen Taylor3473f882001-02-23 17:55:21 +00002085xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2086 int i;
2087
2088 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002089
2090 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002091 for (i = 0;i < obj->nodeNr;i++) {
2092 if (obj->nodeTab[i] != NULL) {
2093 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2094 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2095 } else {
2096 xmlFreeNodeList(obj->nodeTab[i]);
2097 }
2098 }
2099 }
Owen Taylor3473f882001-02-23 17:55:21 +00002100 xmlFree(obj->nodeTab);
2101 }
Owen Taylor3473f882001-02-23 17:55:21 +00002102 xmlFree(obj);
2103}
2104
2105#if defined(DEBUG) || defined(DEBUG_STEP)
2106/**
2107 * xmlGenericErrorContextNodeSet:
2108 * @output: a FILE * for the output
2109 * @obj: the xmlNodeSetPtr to free
2110 *
2111 * Quick display of a NodeSet
2112 */
2113void
2114xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2115 int i;
2116
2117 if (output == NULL) output = xmlGenericErrorContext;
2118 if (obj == NULL) {
2119 fprintf(output, "NodeSet == NULL !\n");
2120 return;
2121 }
2122 if (obj->nodeNr == 0) {
2123 fprintf(output, "NodeSet is empty\n");
2124 return;
2125 }
2126 if (obj->nodeTab == NULL) {
2127 fprintf(output, " nodeTab == NULL !\n");
2128 return;
2129 }
2130 for (i = 0; i < obj->nodeNr; i++) {
2131 if (obj->nodeTab[i] == NULL) {
2132 fprintf(output, " NULL !\n");
2133 return;
2134 }
2135 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2136 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2137 fprintf(output, " /");
2138 else if (obj->nodeTab[i]->name == NULL)
2139 fprintf(output, " noname!");
2140 else fprintf(output, " %s", obj->nodeTab[i]->name);
2141 }
2142 fprintf(output, "\n");
2143}
2144#endif
2145
2146/**
2147 * xmlXPathNewNodeSet:
2148 * @val: the NodePtr value
2149 *
2150 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2151 * it with the single Node @val
2152 *
2153 * Returns the newly created object.
2154 */
2155xmlXPathObjectPtr
2156xmlXPathNewNodeSet(xmlNodePtr val) {
2157 xmlXPathObjectPtr ret;
2158
2159 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2160 if (ret == NULL) {
2161 xmlGenericError(xmlGenericErrorContext,
2162 "xmlXPathNewNodeSet: out of memory\n");
2163 return(NULL);
2164 }
2165 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2166 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002167 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002168 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002169 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002170 return(ret);
2171}
2172
2173/**
2174 * xmlXPathNewValueTree:
2175 * @val: the NodePtr value
2176 *
2177 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2178 * it with the tree root @val
2179 *
2180 * Returns the newly created object.
2181 */
2182xmlXPathObjectPtr
2183xmlXPathNewValueTree(xmlNodePtr val) {
2184 xmlXPathObjectPtr ret;
2185
2186 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2187 if (ret == NULL) {
2188 xmlGenericError(xmlGenericErrorContext,
2189 "xmlXPathNewNodeSet: out of memory\n");
2190 return(NULL);
2191 }
2192 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2193 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002194 ret->boolval = 1;
2195 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002196 ret->nodesetval = xmlXPathNodeSetCreate(val);
2197 return(ret);
2198}
2199
2200/**
2201 * xmlXPathNewNodeSetList:
2202 * @val: an existing NodeSet
2203 *
2204 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2205 * it with the Nodeset @val
2206 *
2207 * Returns the newly created object.
2208 */
2209xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002210xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2211{
Owen Taylor3473f882001-02-23 17:55:21 +00002212 xmlXPathObjectPtr ret;
2213 int i;
2214
2215 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002216 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002217 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002218 ret = xmlXPathNewNodeSet(NULL);
2219 else {
2220 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2221 for (i = 1; i < val->nodeNr; ++i)
2222 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2223 }
Owen Taylor3473f882001-02-23 17:55:21 +00002224
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002225 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002226}
2227
2228/**
2229 * xmlXPathWrapNodeSet:
2230 * @val: the NodePtr value
2231 *
2232 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2233 *
2234 * Returns the newly created object.
2235 */
2236xmlXPathObjectPtr
2237xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2238 xmlXPathObjectPtr ret;
2239
2240 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2241 if (ret == NULL) {
2242 xmlGenericError(xmlGenericErrorContext,
2243 "xmlXPathWrapNodeSet: out of memory\n");
2244 return(NULL);
2245 }
2246 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2247 ret->type = XPATH_NODESET;
2248 ret->nodesetval = val;
2249 return(ret);
2250}
2251
2252/**
2253 * xmlXPathFreeNodeSetList:
2254 * @obj: an existing NodeSetList object
2255 *
2256 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2257 * the list contrary to xmlXPathFreeObject().
2258 */
2259void
2260xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2261 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002262 xmlFree(obj);
2263}
2264
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002265/**
2266 * xmlXPathDifference:
2267 * @nodes1: a node-set
2268 * @nodes2: a node-set
2269 *
2270 * Implements the EXSLT - Sets difference() function:
2271 * node-set set:difference (node-set, node-set)
2272 *
2273 * Returns the difference between the two node sets, or nodes1 if
2274 * nodes2 is empty
2275 */
2276xmlNodeSetPtr
2277xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2278 xmlNodeSetPtr ret;
2279 int i, l1;
2280 xmlNodePtr cur;
2281
2282 if (xmlXPathNodeSetIsEmpty(nodes2))
2283 return(nodes1);
2284
2285 ret = xmlXPathNodeSetCreate(NULL);
2286 if (xmlXPathNodeSetIsEmpty(nodes1))
2287 return(ret);
2288
2289 l1 = xmlXPathNodeSetGetLength(nodes1);
2290
2291 for (i = 0; i < l1; i++) {
2292 cur = xmlXPathNodeSetItem(nodes1, i);
2293 if (!xmlXPathNodeSetContains(nodes2, cur))
2294 xmlXPathNodeSetAddUnique(ret, cur);
2295 }
2296 return(ret);
2297}
2298
2299/**
2300 * xmlXPathIntersection:
2301 * @nodes1: a node-set
2302 * @nodes2: a node-set
2303 *
2304 * Implements the EXSLT - Sets intersection() function:
2305 * node-set set:intersection (node-set, node-set)
2306 *
2307 * Returns a node set comprising the nodes that are within both the
2308 * node sets passed as arguments
2309 */
2310xmlNodeSetPtr
2311xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2312 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2313 int i, l1;
2314 xmlNodePtr cur;
2315
2316 if (xmlXPathNodeSetIsEmpty(nodes1))
2317 return(ret);
2318 if (xmlXPathNodeSetIsEmpty(nodes2))
2319 return(ret);
2320
2321 l1 = xmlXPathNodeSetGetLength(nodes1);
2322
2323 for (i = 0; i < l1; i++) {
2324 cur = xmlXPathNodeSetItem(nodes1, i);
2325 if (xmlXPathNodeSetContains(nodes2, cur))
2326 xmlXPathNodeSetAddUnique(ret, cur);
2327 }
2328 return(ret);
2329}
2330
2331/**
2332 * xmlXPathDistinctSorted:
2333 * @nodes: a node-set, sorted by document order
2334 *
2335 * Implements the EXSLT - Sets distinct() function:
2336 * node-set set:distinct (node-set)
2337 *
2338 * Returns a subset of the nodes contained in @nodes, or @nodes if
2339 * it is empty
2340 */
2341xmlNodeSetPtr
2342xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2343 xmlNodeSetPtr ret;
2344 xmlHashTablePtr hash;
2345 int i, l;
2346 xmlChar * strval;
2347 xmlNodePtr cur;
2348
2349 if (xmlXPathNodeSetIsEmpty(nodes))
2350 return(nodes);
2351
2352 ret = xmlXPathNodeSetCreate(NULL);
2353 l = xmlXPathNodeSetGetLength(nodes);
2354 hash = xmlHashCreate (l);
2355 for (i = 0; i < l; i++) {
2356 cur = xmlXPathNodeSetItem(nodes, i);
2357 strval = xmlXPathCastNodeToString(cur);
2358 if (xmlHashLookup(hash, strval) == NULL) {
2359 xmlHashAddEntry(hash, strval, strval);
2360 xmlXPathNodeSetAddUnique(ret, cur);
2361 } else {
2362 xmlFree(strval);
2363 }
2364 }
2365 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2366 return(ret);
2367}
2368
2369/**
2370 * xmlXPathDistinct:
2371 * @nodes: a node-set
2372 *
2373 * Implements the EXSLT - Sets distinct() function:
2374 * node-set set:distinct (node-set)
2375 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2376 * is called with the sorted node-set
2377 *
2378 * Returns a subset of the nodes contained in @nodes, or @nodes if
2379 * it is empty
2380 */
2381xmlNodeSetPtr
2382xmlXPathDistinct (xmlNodeSetPtr nodes) {
2383 if (xmlXPathNodeSetIsEmpty(nodes))
2384 return(nodes);
2385
2386 xmlXPathNodeSetSort(nodes);
2387 return(xmlXPathDistinctSorted(nodes));
2388}
2389
2390/**
2391 * xmlXPathHasSameNodes:
2392 * @nodes1: a node-set
2393 * @nodes2: a node-set
2394 *
2395 * Implements the EXSLT - Sets has-same-nodes function:
2396 * boolean set:has-same-node(node-set, node-set)
2397 *
2398 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2399 * otherwise
2400 */
2401int
2402xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2403 int i, l;
2404 xmlNodePtr cur;
2405
2406 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2407 xmlXPathNodeSetIsEmpty(nodes2))
2408 return(0);
2409
2410 l = xmlXPathNodeSetGetLength(nodes1);
2411 for (i = 0; i < l; i++) {
2412 cur = xmlXPathNodeSetItem(nodes1, i);
2413 if (xmlXPathNodeSetContains(nodes2, cur))
2414 return(1);
2415 }
2416 return(0);
2417}
2418
2419/**
2420 * xmlXPathNodeLeadingSorted:
2421 * @nodes: a node-set, sorted by document order
2422 * @node: a node
2423 *
2424 * Implements the EXSLT - Sets leading() function:
2425 * node-set set:leading (node-set, node-set)
2426 *
2427 * Returns the nodes in @nodes that precede @node in document order,
2428 * @nodes if @node is NULL or an empty node-set if @nodes
2429 * doesn't contain @node
2430 */
2431xmlNodeSetPtr
2432xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2433 int i, l;
2434 xmlNodePtr cur;
2435 xmlNodeSetPtr ret;
2436
2437 if (node == NULL)
2438 return(nodes);
2439
2440 ret = xmlXPathNodeSetCreate(NULL);
2441 if (xmlXPathNodeSetIsEmpty(nodes) ||
2442 (!xmlXPathNodeSetContains(nodes, node)))
2443 return(ret);
2444
2445 l = xmlXPathNodeSetGetLength(nodes);
2446 for (i = 0; i < l; i++) {
2447 cur = xmlXPathNodeSetItem(nodes, i);
2448 if (cur == node)
2449 break;
2450 xmlXPathNodeSetAddUnique(ret, cur);
2451 }
2452 return(ret);
2453}
2454
2455/**
2456 * xmlXPathNodeLeading:
2457 * @nodes: a node-set
2458 * @node: a node
2459 *
2460 * Implements the EXSLT - Sets leading() function:
2461 * node-set set:leading (node-set, node-set)
2462 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2463 * is called.
2464 *
2465 * Returns the nodes in @nodes that precede @node in document order,
2466 * @nodes if @node is NULL or an empty node-set if @nodes
2467 * doesn't contain @node
2468 */
2469xmlNodeSetPtr
2470xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2471 xmlXPathNodeSetSort(nodes);
2472 return(xmlXPathNodeLeadingSorted(nodes, node));
2473}
2474
2475/**
2476 * xmlXPathLeadingSorted:
2477 * @nodes1: a node-set, sorted by document order
2478 * @nodes2: a node-set, sorted by document order
2479 *
2480 * Implements the EXSLT - Sets leading() function:
2481 * node-set set:leading (node-set, node-set)
2482 *
2483 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2484 * in document order, @nodes1 if @nodes2 is NULL or empty or
2485 * an empty node-set if @nodes1 doesn't contain @nodes2
2486 */
2487xmlNodeSetPtr
2488xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2489 if (xmlXPathNodeSetIsEmpty(nodes2))
2490 return(nodes1);
2491 return(xmlXPathNodeLeadingSorted(nodes1,
2492 xmlXPathNodeSetItem(nodes2, 1)));
2493}
2494
2495/**
2496 * xmlXPathLeading:
2497 * @nodes1: a node-set
2498 * @nodes2: a node-set
2499 *
2500 * Implements the EXSLT - Sets leading() function:
2501 * node-set set:leading (node-set, node-set)
2502 * @nodes1 and @nodes2 are sorted by document order, then
2503 * #exslSetsLeadingSorted is called.
2504 *
2505 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2506 * in document order, @nodes1 if @nodes2 is NULL or empty or
2507 * an empty node-set if @nodes1 doesn't contain @nodes2
2508 */
2509xmlNodeSetPtr
2510xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2511 if (xmlXPathNodeSetIsEmpty(nodes2))
2512 return(nodes1);
2513 if (xmlXPathNodeSetIsEmpty(nodes1))
2514 return(xmlXPathNodeSetCreate(NULL));
2515 xmlXPathNodeSetSort(nodes1);
2516 xmlXPathNodeSetSort(nodes2);
2517 return(xmlXPathNodeLeadingSorted(nodes1,
2518 xmlXPathNodeSetItem(nodes2, 1)));
2519}
2520
2521/**
2522 * xmlXPathNodeTrailingSorted:
2523 * @nodes: a node-set, sorted by document order
2524 * @node: a node
2525 *
2526 * Implements the EXSLT - Sets trailing() function:
2527 * node-set set:trailing (node-set, node-set)
2528 *
2529 * Returns the nodes in @nodes that follow @node in document order,
2530 * @nodes if @node is NULL or an empty node-set if @nodes
2531 * doesn't contain @node
2532 */
2533xmlNodeSetPtr
2534xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2535 int i, l;
2536 xmlNodePtr cur;
2537 xmlNodeSetPtr ret;
2538
2539 if (node == NULL)
2540 return(nodes);
2541
2542 ret = xmlXPathNodeSetCreate(NULL);
2543 if (xmlXPathNodeSetIsEmpty(nodes) ||
2544 (!xmlXPathNodeSetContains(nodes, node)))
2545 return(ret);
2546
2547 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002548 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002549 cur = xmlXPathNodeSetItem(nodes, i);
2550 if (cur == node)
2551 break;
2552 xmlXPathNodeSetAddUnique(ret, cur);
2553 }
2554 return(ret);
2555}
2556
2557/**
2558 * xmlXPathNodeTrailing:
2559 * @nodes: a node-set
2560 * @node: a node
2561 *
2562 * Implements the EXSLT - Sets trailing() function:
2563 * node-set set:trailing (node-set, node-set)
2564 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2565 * is called.
2566 *
2567 * Returns the nodes in @nodes that follow @node in document order,
2568 * @nodes if @node is NULL or an empty node-set if @nodes
2569 * doesn't contain @node
2570 */
2571xmlNodeSetPtr
2572xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2573 xmlXPathNodeSetSort(nodes);
2574 return(xmlXPathNodeTrailingSorted(nodes, node));
2575}
2576
2577/**
2578 * xmlXPathTrailingSorted:
2579 * @nodes1: a node-set, sorted by document order
2580 * @nodes2: a node-set, sorted by document order
2581 *
2582 * Implements the EXSLT - Sets trailing() function:
2583 * node-set set:trailing (node-set, node-set)
2584 *
2585 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2586 * in document order, @nodes1 if @nodes2 is NULL or empty or
2587 * an empty node-set if @nodes1 doesn't contain @nodes2
2588 */
2589xmlNodeSetPtr
2590xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2591 if (xmlXPathNodeSetIsEmpty(nodes2))
2592 return(nodes1);
2593 return(xmlXPathNodeTrailingSorted(nodes1,
2594 xmlXPathNodeSetItem(nodes2, 0)));
2595}
2596
2597/**
2598 * xmlXPathTrailing:
2599 * @nodes1: a node-set
2600 * @nodes2: a node-set
2601 *
2602 * Implements the EXSLT - Sets trailing() function:
2603 * node-set set:trailing (node-set, node-set)
2604 * @nodes1 and @nodes2 are sorted by document order, then
2605 * #xmlXPathTrailingSorted is called.
2606 *
2607 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2608 * in document order, @nodes1 if @nodes2 is NULL or empty or
2609 * an empty node-set if @nodes1 doesn't contain @nodes2
2610 */
2611xmlNodeSetPtr
2612xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2613 if (xmlXPathNodeSetIsEmpty(nodes2))
2614 return(nodes1);
2615 if (xmlXPathNodeSetIsEmpty(nodes1))
2616 return(xmlXPathNodeSetCreate(NULL));
2617 xmlXPathNodeSetSort(nodes1);
2618 xmlXPathNodeSetSort(nodes2);
2619 return(xmlXPathNodeTrailingSorted(nodes1,
2620 xmlXPathNodeSetItem(nodes2, 0)));
2621}
2622
Owen Taylor3473f882001-02-23 17:55:21 +00002623/************************************************************************
2624 * *
2625 * Routines to handle extra functions *
2626 * *
2627 ************************************************************************/
2628
2629/**
2630 * xmlXPathRegisterFunc:
2631 * @ctxt: the XPath context
2632 * @name: the function name
2633 * @f: the function implementation or NULL
2634 *
2635 * Register a new function. If @f is NULL it unregisters the function
2636 *
2637 * Returns 0 in case of success, -1 in case of error
2638 */
2639int
2640xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2641 xmlXPathFunction f) {
2642 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2643}
2644
2645/**
2646 * xmlXPathRegisterFuncNS:
2647 * @ctxt: the XPath context
2648 * @name: the function name
2649 * @ns_uri: the function namespace URI
2650 * @f: the function implementation or NULL
2651 *
2652 * Register a new function. If @f is NULL it unregisters the function
2653 *
2654 * Returns 0 in case of success, -1 in case of error
2655 */
2656int
2657xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2658 const xmlChar *ns_uri, xmlXPathFunction f) {
2659 if (ctxt == NULL)
2660 return(-1);
2661 if (name == NULL)
2662 return(-1);
2663
2664 if (ctxt->funcHash == NULL)
2665 ctxt->funcHash = xmlHashCreate(0);
2666 if (ctxt->funcHash == NULL)
2667 return(-1);
2668 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2669}
2670
2671/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002672 * xmlXPathRegisterFuncLookup:
2673 * @ctxt: the XPath context
2674 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002675 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002676 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002677 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002678 */
2679void
2680xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2681 xmlXPathFuncLookupFunc f,
2682 void *funcCtxt) {
2683 if (ctxt == NULL)
2684 return;
2685 ctxt->funcLookupFunc = (void *) f;
2686 ctxt->funcLookupData = funcCtxt;
2687}
2688
2689/**
Owen Taylor3473f882001-02-23 17:55:21 +00002690 * xmlXPathFunctionLookup:
2691 * @ctxt: the XPath context
2692 * @name: the function name
2693 *
2694 * Search in the Function array of the context for the given
2695 * function.
2696 *
2697 * Returns the xmlXPathFunction or NULL if not found
2698 */
2699xmlXPathFunction
2700xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002701 if (ctxt == NULL)
2702 return (NULL);
2703
2704 if (ctxt->funcLookupFunc != NULL) {
2705 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002706 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002707
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002708 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002709 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002710 if (ret != NULL)
2711 return(ret);
2712 }
Owen Taylor3473f882001-02-23 17:55:21 +00002713 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2714}
2715
2716/**
2717 * xmlXPathFunctionLookupNS:
2718 * @ctxt: the XPath context
2719 * @name: the function name
2720 * @ns_uri: the function namespace URI
2721 *
2722 * Search in the Function array of the context for the given
2723 * function.
2724 *
2725 * Returns the xmlXPathFunction or NULL if not found
2726 */
2727xmlXPathFunction
2728xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2729 const xmlChar *ns_uri) {
2730 if (ctxt == NULL)
2731 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002732 if (name == NULL)
2733 return(NULL);
2734
Thomas Broyerba4ad322001-07-26 16:55:21 +00002735 if (ctxt->funcLookupFunc != NULL) {
2736 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002737 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002738
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002739 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002740 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002741 if (ret != NULL)
2742 return(ret);
2743 }
2744
2745 if (ctxt->funcHash == NULL)
2746 return(NULL);
2747
Owen Taylor3473f882001-02-23 17:55:21 +00002748 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2749}
2750
2751/**
2752 * xmlXPathRegisteredFuncsCleanup:
2753 * @ctxt: the XPath context
2754 *
2755 * Cleanup the XPath context data associated to registered functions
2756 */
2757void
2758xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2759 if (ctxt == NULL)
2760 return;
2761
2762 xmlHashFree(ctxt->funcHash, NULL);
2763 ctxt->funcHash = NULL;
2764}
2765
2766/************************************************************************
2767 * *
2768 * Routines to handle Variable *
2769 * *
2770 ************************************************************************/
2771
2772/**
2773 * xmlXPathRegisterVariable:
2774 * @ctxt: the XPath context
2775 * @name: the variable name
2776 * @value: the variable value or NULL
2777 *
2778 * Register a new variable value. If @value is NULL it unregisters
2779 * the variable
2780 *
2781 * Returns 0 in case of success, -1 in case of error
2782 */
2783int
2784xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2785 xmlXPathObjectPtr value) {
2786 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2787}
2788
2789/**
2790 * xmlXPathRegisterVariableNS:
2791 * @ctxt: the XPath context
2792 * @name: the variable name
2793 * @ns_uri: the variable namespace URI
2794 * @value: the variable value or NULL
2795 *
2796 * Register a new variable value. If @value is NULL it unregisters
2797 * the variable
2798 *
2799 * Returns 0 in case of success, -1 in case of error
2800 */
2801int
2802xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2803 const xmlChar *ns_uri,
2804 xmlXPathObjectPtr value) {
2805 if (ctxt == NULL)
2806 return(-1);
2807 if (name == NULL)
2808 return(-1);
2809
2810 if (ctxt->varHash == NULL)
2811 ctxt->varHash = xmlHashCreate(0);
2812 if (ctxt->varHash == NULL)
2813 return(-1);
2814 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2815 (void *) value,
2816 (xmlHashDeallocator)xmlXPathFreeObject));
2817}
2818
2819/**
2820 * xmlXPathRegisterVariableLookup:
2821 * @ctxt: the XPath context
2822 * @f: the lookup function
2823 * @data: the lookup data
2824 *
2825 * register an external mechanism to do variable lookup
2826 */
2827void
2828xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2829 xmlXPathVariableLookupFunc f, void *data) {
2830 if (ctxt == NULL)
2831 return;
2832 ctxt->varLookupFunc = (void *) f;
2833 ctxt->varLookupData = data;
2834}
2835
2836/**
2837 * xmlXPathVariableLookup:
2838 * @ctxt: the XPath context
2839 * @name: the variable name
2840 *
2841 * Search in the Variable array of the context for the given
2842 * variable value.
2843 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002844 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002845 */
2846xmlXPathObjectPtr
2847xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2848 if (ctxt == NULL)
2849 return(NULL);
2850
2851 if (ctxt->varLookupFunc != NULL) {
2852 xmlXPathObjectPtr ret;
2853
2854 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2855 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002856 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002857 }
2858 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2859}
2860
2861/**
2862 * xmlXPathVariableLookupNS:
2863 * @ctxt: the XPath context
2864 * @name: the variable name
2865 * @ns_uri: the variable namespace URI
2866 *
2867 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002868 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002869 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002870 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002871 */
2872xmlXPathObjectPtr
2873xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2874 const xmlChar *ns_uri) {
2875 if (ctxt == NULL)
2876 return(NULL);
2877
2878 if (ctxt->varLookupFunc != NULL) {
2879 xmlXPathObjectPtr ret;
2880
2881 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2882 (ctxt->varLookupData, name, ns_uri);
2883 if (ret != NULL) return(ret);
2884 }
2885
2886 if (ctxt->varHash == NULL)
2887 return(NULL);
2888 if (name == NULL)
2889 return(NULL);
2890
Daniel Veillard8c357d52001-07-03 23:43:33 +00002891 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2892 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002893}
2894
2895/**
2896 * xmlXPathRegisteredVariablesCleanup:
2897 * @ctxt: the XPath context
2898 *
2899 * Cleanup the XPath context data associated to registered variables
2900 */
2901void
2902xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2903 if (ctxt == NULL)
2904 return;
2905
Daniel Veillard76d66f42001-05-16 21:05:17 +00002906 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002907 ctxt->varHash = NULL;
2908}
2909
2910/**
2911 * xmlXPathRegisterNs:
2912 * @ctxt: the XPath context
2913 * @prefix: the namespace prefix
2914 * @ns_uri: the namespace name
2915 *
2916 * Register a new namespace. If @ns_uri is NULL it unregisters
2917 * the namespace
2918 *
2919 * Returns 0 in case of success, -1 in case of error
2920 */
2921int
2922xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2923 const xmlChar *ns_uri) {
2924 if (ctxt == NULL)
2925 return(-1);
2926 if (prefix == NULL)
2927 return(-1);
2928
2929 if (ctxt->nsHash == NULL)
2930 ctxt->nsHash = xmlHashCreate(10);
2931 if (ctxt->nsHash == NULL)
2932 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002933 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002934 (xmlHashDeallocator)xmlFree));
2935}
2936
2937/**
2938 * xmlXPathNsLookup:
2939 * @ctxt: the XPath context
2940 * @prefix: the namespace prefix value
2941 *
2942 * Search in the namespace declaration array of the context for the given
2943 * namespace name associated to the given prefix
2944 *
2945 * Returns the value or NULL if not found
2946 */
2947const xmlChar *
2948xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2949 if (ctxt == NULL)
2950 return(NULL);
2951 if (prefix == NULL)
2952 return(NULL);
2953
2954#ifdef XML_XML_NAMESPACE
2955 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2956 return(XML_XML_NAMESPACE);
2957#endif
2958
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002959 if (ctxt->namespaces != NULL) {
2960 int i;
2961
2962 for (i = 0;i < ctxt->nsNr;i++) {
2963 if ((ctxt->namespaces[i] != NULL) &&
2964 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2965 return(ctxt->namespaces[i]->href);
2966 }
2967 }
Owen Taylor3473f882001-02-23 17:55:21 +00002968
2969 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2970}
2971
2972/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002973 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002974 * @ctxt: the XPath context
2975 *
2976 * Cleanup the XPath context data associated to registered variables
2977 */
2978void
2979xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2980 if (ctxt == NULL)
2981 return;
2982
Daniel Veillard42766c02002-08-22 20:52:17 +00002983 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00002984 ctxt->nsHash = NULL;
2985}
2986
2987/************************************************************************
2988 * *
2989 * Routines to handle Values *
2990 * *
2991 ************************************************************************/
2992
2993/* Allocations are terrible, one need to optimize all this !!! */
2994
2995/**
2996 * xmlXPathNewFloat:
2997 * @val: the double value
2998 *
2999 * Create a new xmlXPathObjectPtr of type double and of value @val
3000 *
3001 * Returns the newly created object.
3002 */
3003xmlXPathObjectPtr
3004xmlXPathNewFloat(double val) {
3005 xmlXPathObjectPtr ret;
3006
3007 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3008 if (ret == NULL) {
3009 xmlGenericError(xmlGenericErrorContext,
3010 "xmlXPathNewFloat: out of memory\n");
3011 return(NULL);
3012 }
3013 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3014 ret->type = XPATH_NUMBER;
3015 ret->floatval = val;
3016 return(ret);
3017}
3018
3019/**
3020 * xmlXPathNewBoolean:
3021 * @val: the boolean value
3022 *
3023 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3024 *
3025 * Returns the newly created object.
3026 */
3027xmlXPathObjectPtr
3028xmlXPathNewBoolean(int val) {
3029 xmlXPathObjectPtr ret;
3030
3031 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3032 if (ret == NULL) {
3033 xmlGenericError(xmlGenericErrorContext,
3034 "xmlXPathNewBoolean: out of memory\n");
3035 return(NULL);
3036 }
3037 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3038 ret->type = XPATH_BOOLEAN;
3039 ret->boolval = (val != 0);
3040 return(ret);
3041}
3042
3043/**
3044 * xmlXPathNewString:
3045 * @val: the xmlChar * value
3046 *
3047 * Create a new xmlXPathObjectPtr of type string and of value @val
3048 *
3049 * Returns the newly created object.
3050 */
3051xmlXPathObjectPtr
3052xmlXPathNewString(const xmlChar *val) {
3053 xmlXPathObjectPtr ret;
3054
3055 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3056 if (ret == NULL) {
3057 xmlGenericError(xmlGenericErrorContext,
3058 "xmlXPathNewString: out of memory\n");
3059 return(NULL);
3060 }
3061 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3062 ret->type = XPATH_STRING;
3063 if (val != NULL)
3064 ret->stringval = xmlStrdup(val);
3065 else
3066 ret->stringval = xmlStrdup((const xmlChar *)"");
3067 return(ret);
3068}
3069
3070/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003071 * xmlXPathWrapString:
3072 * @val: the xmlChar * value
3073 *
3074 * Wraps the @val string into an XPath object.
3075 *
3076 * Returns the newly created object.
3077 */
3078xmlXPathObjectPtr
3079xmlXPathWrapString (xmlChar *val) {
3080 xmlXPathObjectPtr ret;
3081
3082 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3083 if (ret == NULL) {
3084 xmlGenericError(xmlGenericErrorContext,
3085 "xmlXPathWrapString: out of memory\n");
3086 return(NULL);
3087 }
3088 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3089 ret->type = XPATH_STRING;
3090 ret->stringval = val;
3091 return(ret);
3092}
3093
3094/**
Owen Taylor3473f882001-02-23 17:55:21 +00003095 * xmlXPathNewCString:
3096 * @val: the char * value
3097 *
3098 * Create a new xmlXPathObjectPtr of type string and of value @val
3099 *
3100 * Returns the newly created object.
3101 */
3102xmlXPathObjectPtr
3103xmlXPathNewCString(const char *val) {
3104 xmlXPathObjectPtr ret;
3105
3106 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3107 if (ret == NULL) {
3108 xmlGenericError(xmlGenericErrorContext,
3109 "xmlXPathNewCString: out of memory\n");
3110 return(NULL);
3111 }
3112 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3113 ret->type = XPATH_STRING;
3114 ret->stringval = xmlStrdup(BAD_CAST val);
3115 return(ret);
3116}
3117
3118/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003119 * xmlXPathWrapCString:
3120 * @val: the char * value
3121 *
3122 * Wraps a string into an XPath object.
3123 *
3124 * Returns the newly created object.
3125 */
3126xmlXPathObjectPtr
3127xmlXPathWrapCString (char * val) {
3128 return(xmlXPathWrapString((xmlChar *)(val)));
3129}
3130
3131/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003132 * xmlXPathWrapExternal:
3133 * @val: the user data
3134 *
3135 * Wraps the @val data into an XPath object.
3136 *
3137 * Returns the newly created object.
3138 */
3139xmlXPathObjectPtr
3140xmlXPathWrapExternal (void *val) {
3141 xmlXPathObjectPtr ret;
3142
3143 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3144 if (ret == NULL) {
3145 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003146 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003147 return(NULL);
3148 }
3149 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3150 ret->type = XPATH_USERS;
3151 ret->user = val;
3152 return(ret);
3153}
3154
3155/**
Owen Taylor3473f882001-02-23 17:55:21 +00003156 * xmlXPathObjectCopy:
3157 * @val: the original object
3158 *
3159 * allocate a new copy of a given object
3160 *
3161 * Returns the newly created object.
3162 */
3163xmlXPathObjectPtr
3164xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3165 xmlXPathObjectPtr ret;
3166
3167 if (val == NULL)
3168 return(NULL);
3169
3170 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3171 if (ret == NULL) {
3172 xmlGenericError(xmlGenericErrorContext,
3173 "xmlXPathObjectCopy: out of memory\n");
3174 return(NULL);
3175 }
3176 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3177 switch (val->type) {
3178 case XPATH_BOOLEAN:
3179 case XPATH_NUMBER:
3180 case XPATH_POINT:
3181 case XPATH_RANGE:
3182 break;
3183 case XPATH_STRING:
3184 ret->stringval = xmlStrdup(val->stringval);
3185 break;
3186 case XPATH_XSLT_TREE:
3187 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003188 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003189 xmlNodePtr cur, tmp;
3190 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003191
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003192 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003193 top = xmlNewDoc(NULL);
3194 top->name = (char *)
3195 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003196 ret->user = top;
3197 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003198 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003199 cur = val->nodesetval->nodeTab[0]->children;
3200 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003201 tmp = xmlDocCopyNode(cur, top, 1);
3202 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003203 cur = cur->next;
3204 }
3205 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003206 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003207 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003208 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003209 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003210 break;
3211 case XPATH_NODESET:
3212 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003213 /* Do not deallocate the copied tree value */
3214 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003215 break;
3216 case XPATH_LOCATIONSET:
3217#ifdef LIBXML_XPTR_ENABLED
3218 {
3219 xmlLocationSetPtr loc = val->user;
3220 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3221 break;
3222 }
3223#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003224 case XPATH_USERS:
3225 ret->user = val->user;
3226 break;
3227 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003228 xmlGenericError(xmlGenericErrorContext,
3229 "xmlXPathObjectCopy: unsupported type %d\n",
3230 val->type);
3231 break;
3232 }
3233 return(ret);
3234}
3235
3236/**
3237 * xmlXPathFreeObject:
3238 * @obj: the object to free
3239 *
3240 * Free up an xmlXPathObjectPtr object.
3241 */
3242void
3243xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3244 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003245 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003246 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003247 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003248 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003249 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003250 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003251 xmlXPathFreeValueTree(obj->nodesetval);
3252 } else {
3253 if (obj->nodesetval != NULL)
3254 xmlXPathFreeNodeSet(obj->nodesetval);
3255 }
Owen Taylor3473f882001-02-23 17:55:21 +00003256#ifdef LIBXML_XPTR_ENABLED
3257 } else if (obj->type == XPATH_LOCATIONSET) {
3258 if (obj->user != NULL)
3259 xmlXPtrFreeLocationSet(obj->user);
3260#endif
3261 } else if (obj->type == XPATH_STRING) {
3262 if (obj->stringval != NULL)
3263 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003264 }
3265
Owen Taylor3473f882001-02-23 17:55:21 +00003266 xmlFree(obj);
3267}
3268
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003269
3270/************************************************************************
3271 * *
3272 * Type Casting Routines *
3273 * *
3274 ************************************************************************/
3275
3276/**
3277 * xmlXPathCastBooleanToString:
3278 * @val: a boolean
3279 *
3280 * Converts a boolean to its string value.
3281 *
3282 * Returns a newly allocated string.
3283 */
3284xmlChar *
3285xmlXPathCastBooleanToString (int val) {
3286 xmlChar *ret;
3287 if (val)
3288 ret = xmlStrdup((const xmlChar *) "true");
3289 else
3290 ret = xmlStrdup((const xmlChar *) "false");
3291 return(ret);
3292}
3293
3294/**
3295 * xmlXPathCastNumberToString:
3296 * @val: a number
3297 *
3298 * Converts a number to its string value.
3299 *
3300 * Returns a newly allocated string.
3301 */
3302xmlChar *
3303xmlXPathCastNumberToString (double val) {
3304 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003305 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003306 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003307 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003308 break;
3309 case -1:
3310 ret = xmlStrdup((const xmlChar *) "-Infinity");
3311 break;
3312 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003313 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003314 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003315 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3316 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003317 } else {
3318 /* could be improved */
3319 char buf[100];
3320 xmlXPathFormatNumber(val, buf, 100);
3321 ret = xmlStrdup((const xmlChar *) buf);
3322 }
3323 }
3324 return(ret);
3325}
3326
3327/**
3328 * xmlXPathCastNodeToString:
3329 * @node: a node
3330 *
3331 * Converts a node to its string value.
3332 *
3333 * Returns a newly allocated string.
3334 */
3335xmlChar *
3336xmlXPathCastNodeToString (xmlNodePtr node) {
3337 return(xmlNodeGetContent(node));
3338}
3339
3340/**
3341 * xmlXPathCastNodeSetToString:
3342 * @ns: a node-set
3343 *
3344 * Converts a node-set to its string value.
3345 *
3346 * Returns a newly allocated string.
3347 */
3348xmlChar *
3349xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3350 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3351 return(xmlStrdup((const xmlChar *) ""));
3352
3353 xmlXPathNodeSetSort(ns);
3354 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3355}
3356
3357/**
3358 * xmlXPathCastToString:
3359 * @val: an XPath object
3360 *
3361 * Converts an existing object to its string() equivalent
3362 *
3363 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003364 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003365 * string object).
3366 */
3367xmlChar *
3368xmlXPathCastToString(xmlXPathObjectPtr val) {
3369 xmlChar *ret = NULL;
3370
3371 if (val == NULL)
3372 return(xmlStrdup((const xmlChar *) ""));
3373 switch (val->type) {
3374 case XPATH_UNDEFINED:
3375#ifdef DEBUG_EXPR
3376 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3377#endif
3378 ret = xmlStrdup((const xmlChar *) "");
3379 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003380 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003381 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003382 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3383 break;
3384 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003385 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003386 case XPATH_BOOLEAN:
3387 ret = xmlXPathCastBooleanToString(val->boolval);
3388 break;
3389 case XPATH_NUMBER: {
3390 ret = xmlXPathCastNumberToString(val->floatval);
3391 break;
3392 }
3393 case XPATH_USERS:
3394 case XPATH_POINT:
3395 case XPATH_RANGE:
3396 case XPATH_LOCATIONSET:
3397 TODO
3398 ret = xmlStrdup((const xmlChar *) "");
3399 break;
3400 }
3401 return(ret);
3402}
3403
3404/**
3405 * xmlXPathConvertString:
3406 * @val: an XPath object
3407 *
3408 * Converts an existing object to its string() equivalent
3409 *
3410 * Returns the new object, the old one is freed (or the operation
3411 * is done directly on @val)
3412 */
3413xmlXPathObjectPtr
3414xmlXPathConvertString(xmlXPathObjectPtr val) {
3415 xmlChar *res = NULL;
3416
3417 if (val == NULL)
3418 return(xmlXPathNewCString(""));
3419
3420 switch (val->type) {
3421 case XPATH_UNDEFINED:
3422#ifdef DEBUG_EXPR
3423 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3424#endif
3425 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003426 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003427 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003428 res = xmlXPathCastNodeSetToString(val->nodesetval);
3429 break;
3430 case XPATH_STRING:
3431 return(val);
3432 case XPATH_BOOLEAN:
3433 res = xmlXPathCastBooleanToString(val->boolval);
3434 break;
3435 case XPATH_NUMBER:
3436 res = xmlXPathCastNumberToString(val->floatval);
3437 break;
3438 case XPATH_USERS:
3439 case XPATH_POINT:
3440 case XPATH_RANGE:
3441 case XPATH_LOCATIONSET:
3442 TODO;
3443 break;
3444 }
3445 xmlXPathFreeObject(val);
3446 if (res == NULL)
3447 return(xmlXPathNewCString(""));
3448 return(xmlXPathWrapString(res));
3449}
3450
3451/**
3452 * xmlXPathCastBooleanToNumber:
3453 * @val: a boolean
3454 *
3455 * Converts a boolean to its number value
3456 *
3457 * Returns the number value
3458 */
3459double
3460xmlXPathCastBooleanToNumber(int val) {
3461 if (val)
3462 return(1.0);
3463 return(0.0);
3464}
3465
3466/**
3467 * xmlXPathCastStringToNumber:
3468 * @val: a string
3469 *
3470 * Converts a string to its number value
3471 *
3472 * Returns the number value
3473 */
3474double
3475xmlXPathCastStringToNumber(const xmlChar * val) {
3476 return(xmlXPathStringEvalNumber(val));
3477}
3478
3479/**
3480 * xmlXPathCastNodeToNumber:
3481 * @node: a node
3482 *
3483 * Converts a node to its number value
3484 *
3485 * Returns the number value
3486 */
3487double
3488xmlXPathCastNodeToNumber (xmlNodePtr node) {
3489 xmlChar *strval;
3490 double ret;
3491
3492 if (node == NULL)
3493 return(xmlXPathNAN);
3494 strval = xmlXPathCastNodeToString(node);
3495 if (strval == NULL)
3496 return(xmlXPathNAN);
3497 ret = xmlXPathCastStringToNumber(strval);
3498 xmlFree(strval);
3499
3500 return(ret);
3501}
3502
3503/**
3504 * xmlXPathCastNodeSetToNumber:
3505 * @ns: a node-set
3506 *
3507 * Converts a node-set to its number value
3508 *
3509 * Returns the number value
3510 */
3511double
3512xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3513 xmlChar *str;
3514 double ret;
3515
3516 if (ns == NULL)
3517 return(xmlXPathNAN);
3518 str = xmlXPathCastNodeSetToString(ns);
3519 ret = xmlXPathCastStringToNumber(str);
3520 xmlFree(str);
3521 return(ret);
3522}
3523
3524/**
3525 * xmlXPathCastToNumber:
3526 * @val: an XPath object
3527 *
3528 * Converts an XPath object to its number value
3529 *
3530 * Returns the number value
3531 */
3532double
3533xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3534 double ret = 0.0;
3535
3536 if (val == NULL)
3537 return(xmlXPathNAN);
3538 switch (val->type) {
3539 case XPATH_UNDEFINED:
3540#ifdef DEGUB_EXPR
3541 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3542#endif
3543 ret = xmlXPathNAN;
3544 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003545 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003546 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003547 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3548 break;
3549 case XPATH_STRING:
3550 ret = xmlXPathCastStringToNumber(val->stringval);
3551 break;
3552 case XPATH_NUMBER:
3553 ret = val->floatval;
3554 break;
3555 case XPATH_BOOLEAN:
3556 ret = xmlXPathCastBooleanToNumber(val->boolval);
3557 break;
3558 case XPATH_USERS:
3559 case XPATH_POINT:
3560 case XPATH_RANGE:
3561 case XPATH_LOCATIONSET:
3562 TODO;
3563 ret = xmlXPathNAN;
3564 break;
3565 }
3566 return(ret);
3567}
3568
3569/**
3570 * xmlXPathConvertNumber:
3571 * @val: an XPath object
3572 *
3573 * Converts an existing object to its number() equivalent
3574 *
3575 * Returns the new object, the old one is freed (or the operation
3576 * is done directly on @val)
3577 */
3578xmlXPathObjectPtr
3579xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3580 xmlXPathObjectPtr ret;
3581
3582 if (val == NULL)
3583 return(xmlXPathNewFloat(0.0));
3584 if (val->type == XPATH_NUMBER)
3585 return(val);
3586 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3587 xmlXPathFreeObject(val);
3588 return(ret);
3589}
3590
3591/**
3592 * xmlXPathCastNumberToBoolean:
3593 * @val: a number
3594 *
3595 * Converts a number to its boolean value
3596 *
3597 * Returns the boolean value
3598 */
3599int
3600xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003601 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003602 return(0);
3603 return(1);
3604}
3605
3606/**
3607 * xmlXPathCastStringToBoolean:
3608 * @val: a string
3609 *
3610 * Converts a string to its boolean value
3611 *
3612 * Returns the boolean value
3613 */
3614int
3615xmlXPathCastStringToBoolean (const xmlChar *val) {
3616 if ((val == NULL) || (xmlStrlen(val) == 0))
3617 return(0);
3618 return(1);
3619}
3620
3621/**
3622 * xmlXPathCastNodeSetToBoolean:
3623 * @ns: a node-set
3624 *
3625 * Converts a node-set to its boolean value
3626 *
3627 * Returns the boolean value
3628 */
3629int
3630xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3631 if ((ns == NULL) || (ns->nodeNr == 0))
3632 return(0);
3633 return(1);
3634}
3635
3636/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003637 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003638 * @val: an XPath object
3639 *
3640 * Converts an XPath object to its boolean value
3641 *
3642 * Returns the boolean value
3643 */
3644int
3645xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3646 int ret = 0;
3647
3648 if (val == NULL)
3649 return(0);
3650 switch (val->type) {
3651 case XPATH_UNDEFINED:
3652#ifdef DEBUG_EXPR
3653 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3654#endif
3655 ret = 0;
3656 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003657 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003658 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003659 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3660 break;
3661 case XPATH_STRING:
3662 ret = xmlXPathCastStringToBoolean(val->stringval);
3663 break;
3664 case XPATH_NUMBER:
3665 ret = xmlXPathCastNumberToBoolean(val->floatval);
3666 break;
3667 case XPATH_BOOLEAN:
3668 ret = val->boolval;
3669 break;
3670 case XPATH_USERS:
3671 case XPATH_POINT:
3672 case XPATH_RANGE:
3673 case XPATH_LOCATIONSET:
3674 TODO;
3675 ret = 0;
3676 break;
3677 }
3678 return(ret);
3679}
3680
3681
3682/**
3683 * xmlXPathConvertBoolean:
3684 * @val: an XPath object
3685 *
3686 * Converts an existing object to its boolean() equivalent
3687 *
3688 * Returns the new object, the old one is freed (or the operation
3689 * is done directly on @val)
3690 */
3691xmlXPathObjectPtr
3692xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3693 xmlXPathObjectPtr ret;
3694
3695 if (val == NULL)
3696 return(xmlXPathNewBoolean(0));
3697 if (val->type == XPATH_BOOLEAN)
3698 return(val);
3699 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3700 xmlXPathFreeObject(val);
3701 return(ret);
3702}
3703
Owen Taylor3473f882001-02-23 17:55:21 +00003704/************************************************************************
3705 * *
3706 * Routines to handle XPath contexts *
3707 * *
3708 ************************************************************************/
3709
3710/**
3711 * xmlXPathNewContext:
3712 * @doc: the XML document
3713 *
3714 * Create a new xmlXPathContext
3715 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003716 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003717 */
3718xmlXPathContextPtr
3719xmlXPathNewContext(xmlDocPtr doc) {
3720 xmlXPathContextPtr ret;
3721
3722 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3723 if (ret == NULL) {
3724 xmlGenericError(xmlGenericErrorContext,
3725 "xmlXPathNewContext: out of memory\n");
3726 return(NULL);
3727 }
3728 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3729 ret->doc = doc;
3730 ret->node = NULL;
3731
3732 ret->varHash = NULL;
3733
3734 ret->nb_types = 0;
3735 ret->max_types = 0;
3736 ret->types = NULL;
3737
3738 ret->funcHash = xmlHashCreate(0);
3739
3740 ret->nb_axis = 0;
3741 ret->max_axis = 0;
3742 ret->axis = NULL;
3743
3744 ret->nsHash = NULL;
3745 ret->user = NULL;
3746
3747 ret->contextSize = -1;
3748 ret->proximityPosition = -1;
3749
3750 xmlXPathRegisterAllFunctions(ret);
3751
3752 return(ret);
3753}
3754
3755/**
3756 * xmlXPathFreeContext:
3757 * @ctxt: the context to free
3758 *
3759 * Free up an xmlXPathContext
3760 */
3761void
3762xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3763 xmlXPathRegisteredNsCleanup(ctxt);
3764 xmlXPathRegisteredFuncsCleanup(ctxt);
3765 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003766 xmlFree(ctxt);
3767}
3768
3769/************************************************************************
3770 * *
3771 * Routines to handle XPath parser contexts *
3772 * *
3773 ************************************************************************/
3774
3775#define CHECK_CTXT(ctxt) \
3776 if (ctxt == NULL) { \
3777 xmlGenericError(xmlGenericErrorContext, \
3778 "%s:%d Internal error: ctxt == NULL\n", \
3779 __FILE__, __LINE__); \
3780 } \
3781
3782
3783#define CHECK_CONTEXT(ctxt) \
3784 if (ctxt == NULL) { \
3785 xmlGenericError(xmlGenericErrorContext, \
3786 "%s:%d Internal error: no context\n", \
3787 __FILE__, __LINE__); \
3788 } \
3789 else if (ctxt->doc == NULL) { \
3790 xmlGenericError(xmlGenericErrorContext, \
3791 "%s:%d Internal error: no document\n", \
3792 __FILE__, __LINE__); \
3793 } \
3794 else if (ctxt->doc->children == NULL) { \
3795 xmlGenericError(xmlGenericErrorContext, \
3796 "%s:%d Internal error: document without root\n", \
3797 __FILE__, __LINE__); \
3798 } \
3799
3800
3801/**
3802 * xmlXPathNewParserContext:
3803 * @str: the XPath expression
3804 * @ctxt: the XPath context
3805 *
3806 * Create a new xmlXPathParserContext
3807 *
3808 * Returns the xmlXPathParserContext just allocated.
3809 */
3810xmlXPathParserContextPtr
3811xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3812 xmlXPathParserContextPtr ret;
3813
3814 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3815 if (ret == NULL) {
3816 xmlGenericError(xmlGenericErrorContext,
3817 "xmlXPathNewParserContext: out of memory\n");
3818 return(NULL);
3819 }
3820 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3821 ret->cur = ret->base = str;
3822 ret->context = ctxt;
3823
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003824 ret->comp = xmlXPathNewCompExpr();
3825 if (ret->comp == NULL) {
3826 xmlFree(ret->valueTab);
3827 xmlFree(ret);
3828 return(NULL);
3829 }
3830
3831 return(ret);
3832}
3833
3834/**
3835 * xmlXPathCompParserContext:
3836 * @comp: the XPath compiled expression
3837 * @ctxt: the XPath context
3838 *
3839 * Create a new xmlXPathParserContext when processing a compiled expression
3840 *
3841 * Returns the xmlXPathParserContext just allocated.
3842 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003843static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003844xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3845 xmlXPathParserContextPtr ret;
3846
3847 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3848 if (ret == NULL) {
3849 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003850 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003851 return(NULL);
3852 }
3853 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3854
Owen Taylor3473f882001-02-23 17:55:21 +00003855 /* Allocate the value stack */
3856 ret->valueTab = (xmlXPathObjectPtr *)
3857 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003858 if (ret->valueTab == NULL) {
3859 xmlFree(ret);
3860 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003861 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003862 return(NULL);
3863 }
Owen Taylor3473f882001-02-23 17:55:21 +00003864 ret->valueNr = 0;
3865 ret->valueMax = 10;
3866 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003867
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003868 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003869 ret->comp = comp;
3870
Owen Taylor3473f882001-02-23 17:55:21 +00003871 return(ret);
3872}
3873
3874/**
3875 * xmlXPathFreeParserContext:
3876 * @ctxt: the context to free
3877 *
3878 * Free up an xmlXPathParserContext
3879 */
3880void
3881xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3882 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003883 xmlFree(ctxt->valueTab);
3884 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003885 if (ctxt->comp)
3886 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003887 xmlFree(ctxt);
3888}
3889
3890/************************************************************************
3891 * *
3892 * The implicit core function library *
3893 * *
3894 ************************************************************************/
3895
Owen Taylor3473f882001-02-23 17:55:21 +00003896/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003897 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003898 * @node: a node pointer
3899 *
3900 * Function computing the beginning of the string value of the node,
3901 * used to speed up comparisons
3902 *
3903 * Returns an int usable as a hash
3904 */
3905static unsigned int
3906xmlXPathNodeValHash(xmlNodePtr node) {
3907 int len = 2;
3908 const xmlChar * string = NULL;
3909 xmlNodePtr tmp = NULL;
3910 unsigned int ret = 0;
3911
3912 if (node == NULL)
3913 return(0);
3914
Daniel Veillard9adc0462003-03-24 18:39:54 +00003915 if (node->type == XML_DOCUMENT_NODE) {
3916 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3917 if (tmp == NULL)
3918 node = node->children;
3919 else
3920 node = tmp;
3921
3922 if (node == NULL)
3923 return(0);
3924 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003925
3926 switch (node->type) {
3927 case XML_COMMENT_NODE:
3928 case XML_PI_NODE:
3929 case XML_CDATA_SECTION_NODE:
3930 case XML_TEXT_NODE:
3931 string = node->content;
3932 if (string == NULL)
3933 return(0);
3934 if (string[0] == 0)
3935 return(0);
3936 return(((unsigned int) string[0]) +
3937 (((unsigned int) string[1]) << 8));
3938 case XML_NAMESPACE_DECL:
3939 string = ((xmlNsPtr)node)->href;
3940 if (string == NULL)
3941 return(0);
3942 if (string[0] == 0)
3943 return(0);
3944 return(((unsigned int) string[0]) +
3945 (((unsigned int) string[1]) << 8));
3946 case XML_ATTRIBUTE_NODE:
3947 tmp = ((xmlAttrPtr) node)->children;
3948 break;
3949 case XML_ELEMENT_NODE:
3950 tmp = node->children;
3951 break;
3952 default:
3953 return(0);
3954 }
3955 while (tmp != NULL) {
3956 switch (tmp->type) {
3957 case XML_COMMENT_NODE:
3958 case XML_PI_NODE:
3959 case XML_CDATA_SECTION_NODE:
3960 case XML_TEXT_NODE:
3961 string = tmp->content;
3962 break;
3963 case XML_NAMESPACE_DECL:
3964 string = ((xmlNsPtr)tmp)->href;
3965 break;
3966 default:
3967 break;
3968 }
3969 if ((string != NULL) && (string[0] != 0)) {
3970 if (string[0] == 0)
3971 return(0);
3972 if (len == 1) {
3973 return(ret + (((unsigned int) string[0]) << 8));
3974 }
3975 if (string[1] == 0) {
3976 len = 1;
3977 ret = (unsigned int) string[0];
3978 } else {
3979 return(((unsigned int) string[0]) +
3980 (((unsigned int) string[1]) << 8));
3981 }
3982 }
3983 /*
3984 * Skip to next node
3985 */
3986 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3987 if (tmp->children->type != XML_ENTITY_DECL) {
3988 tmp = tmp->children;
3989 continue;
3990 }
3991 }
3992 if (tmp == node)
3993 break;
3994
3995 if (tmp->next != NULL) {
3996 tmp = tmp->next;
3997 continue;
3998 }
3999
4000 do {
4001 tmp = tmp->parent;
4002 if (tmp == NULL)
4003 break;
4004 if (tmp == node) {
4005 tmp = NULL;
4006 break;
4007 }
4008 if (tmp->next != NULL) {
4009 tmp = tmp->next;
4010 break;
4011 }
4012 } while (tmp != NULL);
4013 }
4014 return(ret);
4015}
4016
4017/**
4018 * xmlXPathStringHash:
4019 * @string: a string
4020 *
4021 * Function computing the beginning of the string value of the node,
4022 * used to speed up comparisons
4023 *
4024 * Returns an int usable as a hash
4025 */
4026static unsigned int
4027xmlXPathStringHash(const xmlChar * string) {
4028 if (string == NULL)
4029 return((unsigned int) 0);
4030 if (string[0] == 0)
4031 return(0);
4032 return(((unsigned int) string[0]) +
4033 (((unsigned int) string[1]) << 8));
4034}
4035
4036/**
Owen Taylor3473f882001-02-23 17:55:21 +00004037 * xmlXPathCompareNodeSetFloat:
4038 * @ctxt: the XPath Parser context
4039 * @inf: less than (1) or greater than (0)
4040 * @strict: is the comparison strict
4041 * @arg: the node set
4042 * @f: the value
4043 *
4044 * Implement the compare operation between a nodeset and a number
4045 * @ns < @val (1, 1, ...
4046 * @ns <= @val (1, 0, ...
4047 * @ns > @val (0, 1, ...
4048 * @ns >= @val (0, 0, ...
4049 *
4050 * If one object to be compared is a node-set and the other is a number,
4051 * then the comparison will be true if and only if there is a node in the
4052 * node-set such that the result of performing the comparison on the number
4053 * to be compared and on the result of converting the string-value of that
4054 * node to a number using the number function is true.
4055 *
4056 * Returns 0 or 1 depending on the results of the test.
4057 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004058static int
Owen Taylor3473f882001-02-23 17:55:21 +00004059xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4060 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4061 int i, ret = 0;
4062 xmlNodeSetPtr ns;
4063 xmlChar *str2;
4064
4065 if ((f == NULL) || (arg == NULL) ||
4066 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4067 xmlXPathFreeObject(arg);
4068 xmlXPathFreeObject(f);
4069 return(0);
4070 }
4071 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004072 if (ns != NULL) {
4073 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004074 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004075 if (str2 != NULL) {
4076 valuePush(ctxt,
4077 xmlXPathNewString(str2));
4078 xmlFree(str2);
4079 xmlXPathNumberFunction(ctxt, 1);
4080 valuePush(ctxt, xmlXPathObjectCopy(f));
4081 ret = xmlXPathCompareValues(ctxt, inf, strict);
4082 if (ret)
4083 break;
4084 }
4085 }
Owen Taylor3473f882001-02-23 17:55:21 +00004086 }
4087 xmlXPathFreeObject(arg);
4088 xmlXPathFreeObject(f);
4089 return(ret);
4090}
4091
4092/**
4093 * xmlXPathCompareNodeSetString:
4094 * @ctxt: the XPath Parser context
4095 * @inf: less than (1) or greater than (0)
4096 * @strict: is the comparison strict
4097 * @arg: the node set
4098 * @s: the value
4099 *
4100 * Implement the compare operation between a nodeset and a string
4101 * @ns < @val (1, 1, ...
4102 * @ns <= @val (1, 0, ...
4103 * @ns > @val (0, 1, ...
4104 * @ns >= @val (0, 0, ...
4105 *
4106 * If one object to be compared is a node-set and the other is a string,
4107 * then the comparison will be true if and only if there is a node in
4108 * the node-set such that the result of performing the comparison on the
4109 * string-value of the node and the other string is true.
4110 *
4111 * Returns 0 or 1 depending on the results of the test.
4112 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004113static int
Owen Taylor3473f882001-02-23 17:55:21 +00004114xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4115 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4116 int i, ret = 0;
4117 xmlNodeSetPtr ns;
4118 xmlChar *str2;
4119
4120 if ((s == NULL) || (arg == NULL) ||
4121 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4122 xmlXPathFreeObject(arg);
4123 xmlXPathFreeObject(s);
4124 return(0);
4125 }
4126 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004127 if (ns != NULL) {
4128 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004129 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004130 if (str2 != NULL) {
4131 valuePush(ctxt,
4132 xmlXPathNewString(str2));
4133 xmlFree(str2);
4134 valuePush(ctxt, xmlXPathObjectCopy(s));
4135 ret = xmlXPathCompareValues(ctxt, inf, strict);
4136 if (ret)
4137 break;
4138 }
4139 }
Owen Taylor3473f882001-02-23 17:55:21 +00004140 }
4141 xmlXPathFreeObject(arg);
4142 xmlXPathFreeObject(s);
4143 return(ret);
4144}
4145
4146/**
4147 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004148 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004149 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004150 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004151 * @arg2: the second node set object
4152 *
4153 * Implement the compare operation on nodesets:
4154 *
4155 * If both objects to be compared are node-sets, then the comparison
4156 * will be true if and only if there is a node in the first node-set
4157 * and a node in the second node-set such that the result of performing
4158 * the comparison on the string-values of the two nodes is true.
4159 * ....
4160 * When neither object to be compared is a node-set and the operator
4161 * is <=, <, >= or >, then the objects are compared by converting both
4162 * objects to numbers and comparing the numbers according to IEEE 754.
4163 * ....
4164 * The number function converts its argument to a number as follows:
4165 * - a string that consists of optional whitespace followed by an
4166 * optional minus sign followed by a Number followed by whitespace
4167 * is converted to the IEEE 754 number that is nearest (according
4168 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4169 * represented by the string; any other string is converted to NaN
4170 *
4171 * Conclusion all nodes need to be converted first to their string value
4172 * and then the comparison must be done when possible
4173 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004174static int
4175xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004176 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4177 int i, j, init = 0;
4178 double val1;
4179 double *values2;
4180 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004181 xmlNodeSetPtr ns1;
4182 xmlNodeSetPtr ns2;
4183
4184 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004185 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4186 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004187 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004188 }
Owen Taylor3473f882001-02-23 17:55:21 +00004189 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004190 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4191 xmlXPathFreeObject(arg1);
4192 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004193 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004194 }
Owen Taylor3473f882001-02-23 17:55:21 +00004195
4196 ns1 = arg1->nodesetval;
4197 ns2 = arg2->nodesetval;
4198
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004199 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004200 xmlXPathFreeObject(arg1);
4201 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004202 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004203 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004204 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004205 xmlXPathFreeObject(arg1);
4206 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004207 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004208 }
Owen Taylor3473f882001-02-23 17:55:21 +00004209
4210 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4211 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004212 xmlXPathFreeObject(arg1);
4213 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004214 return(0);
4215 }
4216 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004217 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004218 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004219 continue;
4220 for (j = 0;j < ns2->nodeNr;j++) {
4221 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004222 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004223 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004224 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004225 continue;
4226 if (inf && strict)
4227 ret = (val1 < values2[j]);
4228 else if (inf && !strict)
4229 ret = (val1 <= values2[j]);
4230 else if (!inf && strict)
4231 ret = (val1 > values2[j]);
4232 else if (!inf && !strict)
4233 ret = (val1 >= values2[j]);
4234 if (ret)
4235 break;
4236 }
4237 if (ret)
4238 break;
4239 init = 1;
4240 }
4241 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004242 xmlXPathFreeObject(arg1);
4243 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004244 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004245}
4246
4247/**
4248 * xmlXPathCompareNodeSetValue:
4249 * @ctxt: the XPath Parser context
4250 * @inf: less than (1) or greater than (0)
4251 * @strict: is the comparison strict
4252 * @arg: the node set
4253 * @val: the value
4254 *
4255 * Implement the compare operation between a nodeset and a value
4256 * @ns < @val (1, 1, ...
4257 * @ns <= @val (1, 0, ...
4258 * @ns > @val (0, 1, ...
4259 * @ns >= @val (0, 0, ...
4260 *
4261 * If one object to be compared is a node-set and the other is a boolean,
4262 * then the comparison will be true if and only if the result of performing
4263 * the comparison on the boolean and on the result of converting
4264 * the node-set to a boolean using the boolean function is true.
4265 *
4266 * Returns 0 or 1 depending on the results of the test.
4267 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004268static int
Owen Taylor3473f882001-02-23 17:55:21 +00004269xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4270 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4271 if ((val == NULL) || (arg == NULL) ||
4272 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4273 return(0);
4274
4275 switch(val->type) {
4276 case XPATH_NUMBER:
4277 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4278 case XPATH_NODESET:
4279 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004280 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004281 case XPATH_STRING:
4282 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4283 case XPATH_BOOLEAN:
4284 valuePush(ctxt, arg);
4285 xmlXPathBooleanFunction(ctxt, 1);
4286 valuePush(ctxt, val);
4287 return(xmlXPathCompareValues(ctxt, inf, strict));
4288 default:
4289 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004290 }
4291 return(0);
4292}
4293
4294/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004295 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004296 * @arg: the nodeset object argument
4297 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004298 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004299 *
4300 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4301 * If one object to be compared is a node-set and the other is a string,
4302 * then the comparison will be true if and only if there is a node in
4303 * the node-set such that the result of performing the comparison on the
4304 * string-value of the node and the other string is true.
4305 *
4306 * Returns 0 or 1 depending on the results of the test.
4307 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004308static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004309xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004310{
Owen Taylor3473f882001-02-23 17:55:21 +00004311 int i;
4312 xmlNodeSetPtr ns;
4313 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004314 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004315
4316 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004317 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4318 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004319 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004320 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004321 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004322 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004323 if (ns->nodeNr <= 0) {
4324 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004325 return(neq ^ 1);
4326 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004327 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004328 for (i = 0; i < ns->nodeNr; i++) {
4329 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4330 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4331 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4332 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004333 if (neq)
4334 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004335 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004336 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4337 if (neq)
4338 continue;
4339 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004340 } else if (neq) {
4341 if (str2 != NULL)
4342 xmlFree(str2);
4343 return (1);
4344 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004345 if (str2 != NULL)
4346 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004347 } else if (neq)
4348 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004349 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004350 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004351}
4352
4353/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004354 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004355 * @arg: the nodeset object argument
4356 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004357 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004358 *
4359 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4360 * If one object to be compared is a node-set and the other is a number,
4361 * then the comparison will be true if and only if there is a node in
4362 * the node-set such that the result of performing the comparison on the
4363 * number to be compared and on the result of converting the string-value
4364 * of that node to a number using the number function is true.
4365 *
4366 * Returns 0 or 1 depending on the results of the test.
4367 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004368static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004369xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4370 xmlXPathObjectPtr arg, double f, int neq) {
4371 int i, ret=0;
4372 xmlNodeSetPtr ns;
4373 xmlChar *str2;
4374 xmlXPathObjectPtr val;
4375 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004376
4377 if ((arg == NULL) ||
4378 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4379 return(0);
4380
William M. Brack0c022ad2002-07-12 00:56:01 +00004381 ns = arg->nodesetval;
4382 if (ns != NULL) {
4383 for (i=0;i<ns->nodeNr;i++) {
4384 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4385 if (str2 != NULL) {
4386 valuePush(ctxt, xmlXPathNewString(str2));
4387 xmlFree(str2);
4388 xmlXPathNumberFunction(ctxt, 1);
4389 val = valuePop(ctxt);
4390 v = val->floatval;
4391 xmlXPathFreeObject(val);
4392 if (!xmlXPathIsNaN(v)) {
4393 if ((!neq) && (v==f)) {
4394 ret = 1;
4395 break;
4396 } else if ((neq) && (v!=f)) {
4397 ret = 1;
4398 break;
4399 }
4400 }
4401 }
4402 }
4403 }
4404
4405 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004406}
4407
4408
4409/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004410 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004411 * @arg1: first nodeset object argument
4412 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004413 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004414 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004415 * Implement the equal / not equal operation on XPath nodesets:
4416 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004417 * If both objects to be compared are node-sets, then the comparison
4418 * will be true if and only if there is a node in the first node-set and
4419 * a node in the second node-set such that the result of performing the
4420 * comparison on the string-values of the two nodes is true.
4421 *
4422 * (needless to say, this is a costly operation)
4423 *
4424 * Returns 0 or 1 depending on the results of the test.
4425 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004426static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004427xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004428 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004429 unsigned int *hashs1;
4430 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004431 xmlChar **values1;
4432 xmlChar **values2;
4433 int ret = 0;
4434 xmlNodeSetPtr ns1;
4435 xmlNodeSetPtr ns2;
4436
4437 if ((arg1 == NULL) ||
4438 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4439 return(0);
4440 if ((arg2 == NULL) ||
4441 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4442 return(0);
4443
4444 ns1 = arg1->nodesetval;
4445 ns2 = arg2->nodesetval;
4446
Daniel Veillard911f49a2001-04-07 15:39:35 +00004447 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004448 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004449 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004450 return(0);
4451
4452 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004453 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004454 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004455 if (neq == 0)
4456 for (i = 0;i < ns1->nodeNr;i++)
4457 for (j = 0;j < ns2->nodeNr;j++)
4458 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4459 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004460
4461 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4462 if (values1 == NULL)
4463 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004464 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4465 if (hashs1 == NULL) {
4466 xmlFree(values1);
4467 return(0);
4468 }
Owen Taylor3473f882001-02-23 17:55:21 +00004469 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4470 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4471 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004472 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004473 xmlFree(values1);
4474 return(0);
4475 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004476 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4477 if (hashs2 == NULL) {
4478 xmlFree(hashs1);
4479 xmlFree(values1);
4480 xmlFree(values2);
4481 return(0);
4482 }
Owen Taylor3473f882001-02-23 17:55:21 +00004483 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4484 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004485 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004486 for (j = 0;j < ns2->nodeNr;j++) {
4487 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004488 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004489 if (hashs1[i] != hashs2[j]) {
4490 if (neq) {
4491 ret = 1;
4492 break;
4493 }
4494 }
4495 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004496 if (values1[i] == NULL)
4497 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4498 if (values2[j] == NULL)
4499 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004500 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004501 if (ret)
4502 break;
4503 }
Owen Taylor3473f882001-02-23 17:55:21 +00004504 }
4505 if (ret)
4506 break;
4507 }
4508 for (i = 0;i < ns1->nodeNr;i++)
4509 if (values1[i] != NULL)
4510 xmlFree(values1[i]);
4511 for (j = 0;j < ns2->nodeNr;j++)
4512 if (values2[j] != NULL)
4513 xmlFree(values2[j]);
4514 xmlFree(values1);
4515 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004516 xmlFree(hashs1);
4517 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004518 return(ret);
4519}
4520
William M. Brack0c022ad2002-07-12 00:56:01 +00004521static int
4522xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4523 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004524 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004525 /*
4526 *At this point we are assured neither arg1 nor arg2
4527 *is a nodeset, so we can just pick the appropriate routine.
4528 */
Owen Taylor3473f882001-02-23 17:55:21 +00004529 switch (arg1->type) {
4530 case XPATH_UNDEFINED:
4531#ifdef DEBUG_EXPR
4532 xmlGenericError(xmlGenericErrorContext,
4533 "Equal: undefined\n");
4534#endif
4535 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004536 case XPATH_BOOLEAN:
4537 switch (arg2->type) {
4538 case XPATH_UNDEFINED:
4539#ifdef DEBUG_EXPR
4540 xmlGenericError(xmlGenericErrorContext,
4541 "Equal: undefined\n");
4542#endif
4543 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004544 case XPATH_BOOLEAN:
4545#ifdef DEBUG_EXPR
4546 xmlGenericError(xmlGenericErrorContext,
4547 "Equal: %d boolean %d \n",
4548 arg1->boolval, arg2->boolval);
4549#endif
4550 ret = (arg1->boolval == arg2->boolval);
4551 break;
4552 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004553 ret = (arg1->boolval ==
4554 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004555 break;
4556 case XPATH_STRING:
4557 if ((arg2->stringval == NULL) ||
4558 (arg2->stringval[0] == 0)) ret = 0;
4559 else
4560 ret = 1;
4561 ret = (arg1->boolval == ret);
4562 break;
4563 case XPATH_USERS:
4564 case XPATH_POINT:
4565 case XPATH_RANGE:
4566 case XPATH_LOCATIONSET:
4567 TODO
4568 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004569 case XPATH_NODESET:
4570 case XPATH_XSLT_TREE:
4571 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004572 }
4573 break;
4574 case XPATH_NUMBER:
4575 switch (arg2->type) {
4576 case XPATH_UNDEFINED:
4577#ifdef DEBUG_EXPR
4578 xmlGenericError(xmlGenericErrorContext,
4579 "Equal: undefined\n");
4580#endif
4581 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004582 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004583 ret = (arg2->boolval==
4584 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004585 break;
4586 case XPATH_STRING:
4587 valuePush(ctxt, arg2);
4588 xmlXPathNumberFunction(ctxt, 1);
4589 arg2 = valuePop(ctxt);
4590 /* no break on purpose */
4591 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004592 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004593 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4594 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004595 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4596 if (xmlXPathIsInf(arg2->floatval) == 1)
4597 ret = 1;
4598 else
4599 ret = 0;
4600 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4601 if (xmlXPathIsInf(arg2->floatval) == -1)
4602 ret = 1;
4603 else
4604 ret = 0;
4605 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4606 if (xmlXPathIsInf(arg1->floatval) == 1)
4607 ret = 1;
4608 else
4609 ret = 0;
4610 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4611 if (xmlXPathIsInf(arg1->floatval) == -1)
4612 ret = 1;
4613 else
4614 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004615 } else {
4616 ret = (arg1->floatval == arg2->floatval);
4617 }
Owen Taylor3473f882001-02-23 17:55:21 +00004618 break;
4619 case XPATH_USERS:
4620 case XPATH_POINT:
4621 case XPATH_RANGE:
4622 case XPATH_LOCATIONSET:
4623 TODO
4624 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004625 case XPATH_NODESET:
4626 case XPATH_XSLT_TREE:
4627 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004628 }
4629 break;
4630 case XPATH_STRING:
4631 switch (arg2->type) {
4632 case XPATH_UNDEFINED:
4633#ifdef DEBUG_EXPR
4634 xmlGenericError(xmlGenericErrorContext,
4635 "Equal: undefined\n");
4636#endif
4637 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004638 case XPATH_BOOLEAN:
4639 if ((arg1->stringval == NULL) ||
4640 (arg1->stringval[0] == 0)) ret = 0;
4641 else
4642 ret = 1;
4643 ret = (arg2->boolval == ret);
4644 break;
4645 case XPATH_STRING:
4646 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4647 break;
4648 case XPATH_NUMBER:
4649 valuePush(ctxt, arg1);
4650 xmlXPathNumberFunction(ctxt, 1);
4651 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004652 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004653 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4654 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004655 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4656 if (xmlXPathIsInf(arg2->floatval) == 1)
4657 ret = 1;
4658 else
4659 ret = 0;
4660 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4661 if (xmlXPathIsInf(arg2->floatval) == -1)
4662 ret = 1;
4663 else
4664 ret = 0;
4665 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4666 if (xmlXPathIsInf(arg1->floatval) == 1)
4667 ret = 1;
4668 else
4669 ret = 0;
4670 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4671 if (xmlXPathIsInf(arg1->floatval) == -1)
4672 ret = 1;
4673 else
4674 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004675 } else {
4676 ret = (arg1->floatval == arg2->floatval);
4677 }
Owen Taylor3473f882001-02-23 17:55:21 +00004678 break;
4679 case XPATH_USERS:
4680 case XPATH_POINT:
4681 case XPATH_RANGE:
4682 case XPATH_LOCATIONSET:
4683 TODO
4684 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004685 case XPATH_NODESET:
4686 case XPATH_XSLT_TREE:
4687 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004688 }
4689 break;
4690 case XPATH_USERS:
4691 case XPATH_POINT:
4692 case XPATH_RANGE:
4693 case XPATH_LOCATIONSET:
4694 TODO
4695 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004696 case XPATH_NODESET:
4697 case XPATH_XSLT_TREE:
4698 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004699 }
4700 xmlXPathFreeObject(arg1);
4701 xmlXPathFreeObject(arg2);
4702 return(ret);
4703}
4704
William M. Brack0c022ad2002-07-12 00:56:01 +00004705/**
4706 * xmlXPathEqualValues:
4707 * @ctxt: the XPath Parser context
4708 *
4709 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4710 *
4711 * Returns 0 or 1 depending on the results of the test.
4712 */
4713int
4714xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4715 xmlXPathObjectPtr arg1, arg2, argtmp;
4716 int ret = 0;
4717
4718 arg2 = valuePop(ctxt);
4719 arg1 = valuePop(ctxt);
4720 if ((arg1 == NULL) || (arg2 == NULL)) {
4721 if (arg1 != NULL)
4722 xmlXPathFreeObject(arg1);
4723 else
4724 xmlXPathFreeObject(arg2);
4725 XP_ERROR0(XPATH_INVALID_OPERAND);
4726 }
4727
4728 if (arg1 == arg2) {
4729#ifdef DEBUG_EXPR
4730 xmlGenericError(xmlGenericErrorContext,
4731 "Equal: by pointer\n");
4732#endif
4733 return(1);
4734 }
4735
4736 /*
4737 *If either argument is a nodeset, it's a 'special case'
4738 */
4739 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4740 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4741 /*
4742 *Hack it to assure arg1 is the nodeset
4743 */
4744 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4745 argtmp = arg2;
4746 arg2 = arg1;
4747 arg1 = argtmp;
4748 }
4749 switch (arg2->type) {
4750 case XPATH_UNDEFINED:
4751#ifdef DEBUG_EXPR
4752 xmlGenericError(xmlGenericErrorContext,
4753 "Equal: undefined\n");
4754#endif
4755 break;
4756 case XPATH_NODESET:
4757 case XPATH_XSLT_TREE:
4758 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4759 break;
4760 case XPATH_BOOLEAN:
4761 if ((arg1->nodesetval == NULL) ||
4762 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4763 else
4764 ret = 1;
4765 ret = (ret == arg2->boolval);
4766 break;
4767 case XPATH_NUMBER:
4768 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4769 break;
4770 case XPATH_STRING:
4771 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4772 break;
4773 case XPATH_USERS:
4774 case XPATH_POINT:
4775 case XPATH_RANGE:
4776 case XPATH_LOCATIONSET:
4777 TODO
4778 break;
4779 }
4780 xmlXPathFreeObject(arg1);
4781 xmlXPathFreeObject(arg2);
4782 return(ret);
4783 }
4784
4785 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4786}
4787
4788/**
4789 * xmlXPathNotEqualValues:
4790 * @ctxt: the XPath Parser context
4791 *
4792 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4793 *
4794 * Returns 0 or 1 depending on the results of the test.
4795 */
4796int
4797xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4798 xmlXPathObjectPtr arg1, arg2, argtmp;
4799 int ret = 0;
4800
4801 arg2 = valuePop(ctxt);
4802 arg1 = valuePop(ctxt);
4803 if ((arg1 == NULL) || (arg2 == NULL)) {
4804 if (arg1 != NULL)
4805 xmlXPathFreeObject(arg1);
4806 else
4807 xmlXPathFreeObject(arg2);
4808 XP_ERROR0(XPATH_INVALID_OPERAND);
4809 }
4810
4811 if (arg1 == arg2) {
4812#ifdef DEBUG_EXPR
4813 xmlGenericError(xmlGenericErrorContext,
4814 "NotEqual: by pointer\n");
4815#endif
4816 return(0);
4817 }
4818
4819 /*
4820 *If either argument is a nodeset, it's a 'special case'
4821 */
4822 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4823 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4824 /*
4825 *Hack it to assure arg1 is the nodeset
4826 */
4827 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4828 argtmp = arg2;
4829 arg2 = arg1;
4830 arg1 = argtmp;
4831 }
4832 switch (arg2->type) {
4833 case XPATH_UNDEFINED:
4834#ifdef DEBUG_EXPR
4835 xmlGenericError(xmlGenericErrorContext,
4836 "NotEqual: undefined\n");
4837#endif
4838 break;
4839 case XPATH_NODESET:
4840 case XPATH_XSLT_TREE:
4841 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4842 break;
4843 case XPATH_BOOLEAN:
4844 if ((arg1->nodesetval == NULL) ||
4845 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4846 else
4847 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004848 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004849 break;
4850 case XPATH_NUMBER:
4851 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4852 break;
4853 case XPATH_STRING:
4854 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4855 break;
4856 case XPATH_USERS:
4857 case XPATH_POINT:
4858 case XPATH_RANGE:
4859 case XPATH_LOCATIONSET:
4860 TODO
4861 break;
4862 }
4863 xmlXPathFreeObject(arg1);
4864 xmlXPathFreeObject(arg2);
4865 return(ret);
4866 }
4867
4868 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4869}
Owen Taylor3473f882001-02-23 17:55:21 +00004870
4871/**
4872 * xmlXPathCompareValues:
4873 * @ctxt: the XPath Parser context
4874 * @inf: less than (1) or greater than (0)
4875 * @strict: is the comparison strict
4876 *
4877 * Implement the compare operation on XPath objects:
4878 * @arg1 < @arg2 (1, 1, ...
4879 * @arg1 <= @arg2 (1, 0, ...
4880 * @arg1 > @arg2 (0, 1, ...
4881 * @arg1 >= @arg2 (0, 0, ...
4882 *
4883 * When neither object to be compared is a node-set and the operator is
4884 * <=, <, >=, >, then the objects are compared by converted both objects
4885 * to numbers and comparing the numbers according to IEEE 754. The <
4886 * comparison will be true if and only if the first number is less than the
4887 * second number. The <= comparison will be true if and only if the first
4888 * number is less than or equal to the second number. The > comparison
4889 * will be true if and only if the first number is greater than the second
4890 * number. The >= comparison will be true if and only if the first number
4891 * is greater than or equal to the second number.
4892 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004893 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004894 */
4895int
4896xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004897 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004898 xmlXPathObjectPtr arg1, arg2;
4899
William M. Brack0c022ad2002-07-12 00:56:01 +00004900 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004901 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004902 if ((arg1 == NULL) || (arg2 == NULL)) {
4903 if (arg1 != NULL)
4904 xmlXPathFreeObject(arg1);
4905 else
4906 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004907 XP_ERROR0(XPATH_INVALID_OPERAND);
4908 }
4909
William M. Brack0c022ad2002-07-12 00:56:01 +00004910 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4911 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4912 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4913 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004914 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004915 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004916 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004917 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4918 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004919 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004920 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4921 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004922 }
4923 }
4924 return(ret);
4925 }
4926
4927 if (arg1->type != XPATH_NUMBER) {
4928 valuePush(ctxt, arg1);
4929 xmlXPathNumberFunction(ctxt, 1);
4930 arg1 = valuePop(ctxt);
4931 }
4932 if (arg1->type != XPATH_NUMBER) {
4933 xmlXPathFreeObject(arg1);
4934 xmlXPathFreeObject(arg2);
4935 XP_ERROR0(XPATH_INVALID_OPERAND);
4936 }
4937 if (arg2->type != XPATH_NUMBER) {
4938 valuePush(ctxt, arg2);
4939 xmlXPathNumberFunction(ctxt, 1);
4940 arg2 = valuePop(ctxt);
4941 }
4942 if (arg2->type != XPATH_NUMBER) {
4943 xmlXPathFreeObject(arg1);
4944 xmlXPathFreeObject(arg2);
4945 XP_ERROR0(XPATH_INVALID_OPERAND);
4946 }
4947 /*
4948 * Add tests for infinity and nan
4949 * => feedback on 3.4 for Inf and NaN
4950 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004951 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004952 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004953 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004954 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004955 arg1i=xmlXPathIsInf(arg1->floatval);
4956 arg2i=xmlXPathIsInf(arg2->floatval);
4957 if (inf && strict) {
4958 if ((arg1i == -1 && arg2i != -1) ||
4959 (arg2i == 1 && arg1i != 1)) {
4960 ret = 1;
4961 } else if (arg1i == 0 && arg2i == 0) {
4962 ret = (arg1->floatval < arg2->floatval);
4963 } else {
4964 ret = 0;
4965 }
4966 }
4967 else if (inf && !strict) {
4968 if (arg1i == -1 || arg2i == 1) {
4969 ret = 1;
4970 } else if (arg1i == 0 && arg2i == 0) {
4971 ret = (arg1->floatval <= arg2->floatval);
4972 } else {
4973 ret = 0;
4974 }
4975 }
4976 else if (!inf && strict) {
4977 if ((arg1i == 1 && arg2i != 1) ||
4978 (arg2i == -1 && arg1i != -1)) {
4979 ret = 1;
4980 } else if (arg1i == 0 && arg2i == 0) {
4981 ret = (arg1->floatval > arg2->floatval);
4982 } else {
4983 ret = 0;
4984 }
4985 }
4986 else if (!inf && !strict) {
4987 if (arg1i == 1 || arg2i == -1) {
4988 ret = 1;
4989 } else if (arg1i == 0 && arg2i == 0) {
4990 ret = (arg1->floatval >= arg2->floatval);
4991 } else {
4992 ret = 0;
4993 }
4994 }
Daniel Veillard21458c82002-03-27 16:12:22 +00004995 }
Owen Taylor3473f882001-02-23 17:55:21 +00004996 xmlXPathFreeObject(arg1);
4997 xmlXPathFreeObject(arg2);
4998 return(ret);
4999}
5000
5001/**
5002 * xmlXPathValueFlipSign:
5003 * @ctxt: the XPath Parser context
5004 *
5005 * Implement the unary - operation on an XPath object
5006 * The numeric operators convert their operands to numbers as if
5007 * by calling the number function.
5008 */
5009void
5010xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005011 CAST_TO_NUMBER;
5012 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005013 if (xmlXPathIsNaN(ctxt->value->floatval))
5014 ctxt->value->floatval=xmlXPathNAN;
5015 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5016 ctxt->value->floatval=xmlXPathNINF;
5017 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5018 ctxt->value->floatval=xmlXPathPINF;
5019 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005020 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5021 ctxt->value->floatval = xmlXPathNZERO;
5022 else
5023 ctxt->value->floatval = 0;
5024 }
5025 else
5026 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005027}
5028
5029/**
5030 * xmlXPathAddValues:
5031 * @ctxt: the XPath Parser context
5032 *
5033 * Implement the add operation on XPath objects:
5034 * The numeric operators convert their operands to numbers as if
5035 * by calling the number function.
5036 */
5037void
5038xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5039 xmlXPathObjectPtr arg;
5040 double val;
5041
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005042 arg = valuePop(ctxt);
5043 if (arg == NULL)
5044 XP_ERROR(XPATH_INVALID_OPERAND);
5045 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005046 xmlXPathFreeObject(arg);
5047
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005048 CAST_TO_NUMBER;
5049 CHECK_TYPE(XPATH_NUMBER);
5050 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005051}
5052
5053/**
5054 * xmlXPathSubValues:
5055 * @ctxt: the XPath Parser context
5056 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005057 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005058 * The numeric operators convert their operands to numbers as if
5059 * by calling the number function.
5060 */
5061void
5062xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5063 xmlXPathObjectPtr arg;
5064 double val;
5065
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005066 arg = valuePop(ctxt);
5067 if (arg == NULL)
5068 XP_ERROR(XPATH_INVALID_OPERAND);
5069 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005070 xmlXPathFreeObject(arg);
5071
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005072 CAST_TO_NUMBER;
5073 CHECK_TYPE(XPATH_NUMBER);
5074 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005075}
5076
5077/**
5078 * xmlXPathMultValues:
5079 * @ctxt: the XPath Parser context
5080 *
5081 * Implement the multiply operation on XPath objects:
5082 * The numeric operators convert their operands to numbers as if
5083 * by calling the number function.
5084 */
5085void
5086xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5087 xmlXPathObjectPtr arg;
5088 double val;
5089
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005090 arg = valuePop(ctxt);
5091 if (arg == NULL)
5092 XP_ERROR(XPATH_INVALID_OPERAND);
5093 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005094 xmlXPathFreeObject(arg);
5095
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005096 CAST_TO_NUMBER;
5097 CHECK_TYPE(XPATH_NUMBER);
5098 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005099}
5100
5101/**
5102 * xmlXPathDivValues:
5103 * @ctxt: the XPath Parser context
5104 *
5105 * Implement the div operation on XPath objects @arg1 / @arg2:
5106 * The numeric operators convert their operands to numbers as if
5107 * by calling the number function.
5108 */
5109void
5110xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5111 xmlXPathObjectPtr arg;
5112 double val;
5113
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005114 arg = valuePop(ctxt);
5115 if (arg == NULL)
5116 XP_ERROR(XPATH_INVALID_OPERAND);
5117 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005118 xmlXPathFreeObject(arg);
5119
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005120 CAST_TO_NUMBER;
5121 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005122 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5123 ctxt->value->floatval = xmlXPathNAN;
5124 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005125 if (ctxt->value->floatval == 0)
5126 ctxt->value->floatval = xmlXPathNAN;
5127 else if (ctxt->value->floatval > 0)
5128 ctxt->value->floatval = xmlXPathNINF;
5129 else if (ctxt->value->floatval < 0)
5130 ctxt->value->floatval = xmlXPathPINF;
5131 }
5132 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005133 if (ctxt->value->floatval == 0)
5134 ctxt->value->floatval = xmlXPathNAN;
5135 else if (ctxt->value->floatval > 0)
5136 ctxt->value->floatval = xmlXPathPINF;
5137 else if (ctxt->value->floatval < 0)
5138 ctxt->value->floatval = xmlXPathNINF;
5139 } else
5140 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005141}
5142
5143/**
5144 * xmlXPathModValues:
5145 * @ctxt: the XPath Parser context
5146 *
5147 * Implement the mod operation on XPath objects: @arg1 / @arg2
5148 * The numeric operators convert their operands to numbers as if
5149 * by calling the number function.
5150 */
5151void
5152xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5153 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005154 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005155
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005156 arg = valuePop(ctxt);
5157 if (arg == NULL)
5158 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005159 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005160 xmlXPathFreeObject(arg);
5161
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005162 CAST_TO_NUMBER;
5163 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005164 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005165 if (arg2 == 0)
5166 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005167 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005168 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005169 }
Owen Taylor3473f882001-02-23 17:55:21 +00005170}
5171
5172/************************************************************************
5173 * *
5174 * The traversal functions *
5175 * *
5176 ************************************************************************/
5177
Owen Taylor3473f882001-02-23 17:55:21 +00005178/*
5179 * A traversal function enumerates nodes along an axis.
5180 * Initially it must be called with NULL, and it indicates
5181 * termination on the axis by returning NULL.
5182 */
5183typedef xmlNodePtr (*xmlXPathTraversalFunction)
5184 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5185
5186/**
5187 * xmlXPathNextSelf:
5188 * @ctxt: the XPath Parser context
5189 * @cur: the current node in the traversal
5190 *
5191 * Traversal function for the "self" direction
5192 * The self axis contains just the context node itself
5193 *
5194 * Returns the next element following that axis
5195 */
5196xmlNodePtr
5197xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5198 if (cur == NULL)
5199 return(ctxt->context->node);
5200 return(NULL);
5201}
5202
5203/**
5204 * xmlXPathNextChild:
5205 * @ctxt: the XPath Parser context
5206 * @cur: the current node in the traversal
5207 *
5208 * Traversal function for the "child" direction
5209 * The child axis contains the children of the context node in document order.
5210 *
5211 * Returns the next element following that axis
5212 */
5213xmlNodePtr
5214xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5215 if (cur == NULL) {
5216 if (ctxt->context->node == NULL) return(NULL);
5217 switch (ctxt->context->node->type) {
5218 case XML_ELEMENT_NODE:
5219 case XML_TEXT_NODE:
5220 case XML_CDATA_SECTION_NODE:
5221 case XML_ENTITY_REF_NODE:
5222 case XML_ENTITY_NODE:
5223 case XML_PI_NODE:
5224 case XML_COMMENT_NODE:
5225 case XML_NOTATION_NODE:
5226 case XML_DTD_NODE:
5227 return(ctxt->context->node->children);
5228 case XML_DOCUMENT_NODE:
5229 case XML_DOCUMENT_TYPE_NODE:
5230 case XML_DOCUMENT_FRAG_NODE:
5231 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005232#ifdef LIBXML_DOCB_ENABLED
5233 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005234#endif
5235 return(((xmlDocPtr) ctxt->context->node)->children);
5236 case XML_ELEMENT_DECL:
5237 case XML_ATTRIBUTE_DECL:
5238 case XML_ENTITY_DECL:
5239 case XML_ATTRIBUTE_NODE:
5240 case XML_NAMESPACE_DECL:
5241 case XML_XINCLUDE_START:
5242 case XML_XINCLUDE_END:
5243 return(NULL);
5244 }
5245 return(NULL);
5246 }
5247 if ((cur->type == XML_DOCUMENT_NODE) ||
5248 (cur->type == XML_HTML_DOCUMENT_NODE))
5249 return(NULL);
5250 return(cur->next);
5251}
5252
5253/**
5254 * xmlXPathNextDescendant:
5255 * @ctxt: the XPath Parser context
5256 * @cur: the current node in the traversal
5257 *
5258 * Traversal function for the "descendant" direction
5259 * the descendant axis contains the descendants of the context node in document
5260 * order; a descendant is a child or a child of a child and so on.
5261 *
5262 * Returns the next element following that axis
5263 */
5264xmlNodePtr
5265xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5266 if (cur == NULL) {
5267 if (ctxt->context->node == NULL)
5268 return(NULL);
5269 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5270 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5271 return(NULL);
5272
5273 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5274 return(ctxt->context->doc->children);
5275 return(ctxt->context->node->children);
5276 }
5277
Daniel Veillard567e1b42001-08-01 15:53:47 +00005278 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005279 /*
5280 * Do not descend on entities declarations
5281 */
5282 if (cur->children->type != XML_ENTITY_DECL) {
5283 cur = cur->children;
5284 /*
5285 * Skip DTDs
5286 */
5287 if (cur->type != XML_DTD_NODE)
5288 return(cur);
5289 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005290 }
5291
5292 if (cur == ctxt->context->node) return(NULL);
5293
Daniel Veillard68e9e742002-11-16 15:35:11 +00005294 while (cur->next != NULL) {
5295 cur = cur->next;
5296 if ((cur->type != XML_ENTITY_DECL) &&
5297 (cur->type != XML_DTD_NODE))
5298 return(cur);
5299 }
Owen Taylor3473f882001-02-23 17:55:21 +00005300
5301 do {
5302 cur = cur->parent;
5303 if (cur == NULL) return(NULL);
5304 if (cur == ctxt->context->node) return(NULL);
5305 if (cur->next != NULL) {
5306 cur = cur->next;
5307 return(cur);
5308 }
5309 } while (cur != NULL);
5310 return(cur);
5311}
5312
5313/**
5314 * xmlXPathNextDescendantOrSelf:
5315 * @ctxt: the XPath Parser context
5316 * @cur: the current node in the traversal
5317 *
5318 * Traversal function for the "descendant-or-self" direction
5319 * the descendant-or-self axis contains the context node and the descendants
5320 * of the context node in document order; thus the context node is the first
5321 * node on the axis, and the first child of the context node is the second node
5322 * on the axis
5323 *
5324 * Returns the next element following that axis
5325 */
5326xmlNodePtr
5327xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5328 if (cur == NULL) {
5329 if (ctxt->context->node == NULL)
5330 return(NULL);
5331 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5332 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5333 return(NULL);
5334 return(ctxt->context->node);
5335 }
5336
5337 return(xmlXPathNextDescendant(ctxt, cur));
5338}
5339
5340/**
5341 * xmlXPathNextParent:
5342 * @ctxt: the XPath Parser context
5343 * @cur: the current node in the traversal
5344 *
5345 * Traversal function for the "parent" direction
5346 * The parent axis contains the parent of the context node, if there is one.
5347 *
5348 * Returns the next element following that axis
5349 */
5350xmlNodePtr
5351xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5352 /*
5353 * the parent of an attribute or namespace node is the element
5354 * to which the attribute or namespace node is attached
5355 * Namespace handling !!!
5356 */
5357 if (cur == NULL) {
5358 if (ctxt->context->node == NULL) return(NULL);
5359 switch (ctxt->context->node->type) {
5360 case XML_ELEMENT_NODE:
5361 case XML_TEXT_NODE:
5362 case XML_CDATA_SECTION_NODE:
5363 case XML_ENTITY_REF_NODE:
5364 case XML_ENTITY_NODE:
5365 case XML_PI_NODE:
5366 case XML_COMMENT_NODE:
5367 case XML_NOTATION_NODE:
5368 case XML_DTD_NODE:
5369 case XML_ELEMENT_DECL:
5370 case XML_ATTRIBUTE_DECL:
5371 case XML_XINCLUDE_START:
5372 case XML_XINCLUDE_END:
5373 case XML_ENTITY_DECL:
5374 if (ctxt->context->node->parent == NULL)
5375 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005376 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005377 ((ctxt->context->node->parent->name[0] == ' ') ||
5378 (xmlStrEqual(ctxt->context->node->parent->name,
5379 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005380 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005381 return(ctxt->context->node->parent);
5382 case XML_ATTRIBUTE_NODE: {
5383 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5384
5385 return(att->parent);
5386 }
5387 case XML_DOCUMENT_NODE:
5388 case XML_DOCUMENT_TYPE_NODE:
5389 case XML_DOCUMENT_FRAG_NODE:
5390 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005391#ifdef LIBXML_DOCB_ENABLED
5392 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005393#endif
5394 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005395 case XML_NAMESPACE_DECL: {
5396 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5397
5398 if ((ns->next != NULL) &&
5399 (ns->next->type != XML_NAMESPACE_DECL))
5400 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005401 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005402 }
Owen Taylor3473f882001-02-23 17:55:21 +00005403 }
5404 }
5405 return(NULL);
5406}
5407
5408/**
5409 * xmlXPathNextAncestor:
5410 * @ctxt: the XPath Parser context
5411 * @cur: the current node in the traversal
5412 *
5413 * Traversal function for the "ancestor" direction
5414 * the ancestor axis contains the ancestors of the context node; the ancestors
5415 * of the context node consist of the parent of context node and the parent's
5416 * parent and so on; the nodes are ordered in reverse document order; thus the
5417 * parent is the first node on the axis, and the parent's parent is the second
5418 * node on the axis
5419 *
5420 * Returns the next element following that axis
5421 */
5422xmlNodePtr
5423xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5424 /*
5425 * the parent of an attribute or namespace node is the element
5426 * to which the attribute or namespace node is attached
5427 * !!!!!!!!!!!!!
5428 */
5429 if (cur == NULL) {
5430 if (ctxt->context->node == NULL) return(NULL);
5431 switch (ctxt->context->node->type) {
5432 case XML_ELEMENT_NODE:
5433 case XML_TEXT_NODE:
5434 case XML_CDATA_SECTION_NODE:
5435 case XML_ENTITY_REF_NODE:
5436 case XML_ENTITY_NODE:
5437 case XML_PI_NODE:
5438 case XML_COMMENT_NODE:
5439 case XML_DTD_NODE:
5440 case XML_ELEMENT_DECL:
5441 case XML_ATTRIBUTE_DECL:
5442 case XML_ENTITY_DECL:
5443 case XML_NOTATION_NODE:
5444 case XML_XINCLUDE_START:
5445 case XML_XINCLUDE_END:
5446 if (ctxt->context->node->parent == NULL)
5447 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005448 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005449 ((ctxt->context->node->parent->name[0] == ' ') ||
5450 (xmlStrEqual(ctxt->context->node->parent->name,
5451 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005452 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005453 return(ctxt->context->node->parent);
5454 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005455 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005456
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005457 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005458 }
5459 case XML_DOCUMENT_NODE:
5460 case XML_DOCUMENT_TYPE_NODE:
5461 case XML_DOCUMENT_FRAG_NODE:
5462 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005463#ifdef LIBXML_DOCB_ENABLED
5464 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005465#endif
5466 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005467 case XML_NAMESPACE_DECL: {
5468 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5469
5470 if ((ns->next != NULL) &&
5471 (ns->next->type != XML_NAMESPACE_DECL))
5472 return((xmlNodePtr) ns->next);
5473 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005474 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005475 }
Owen Taylor3473f882001-02-23 17:55:21 +00005476 }
5477 return(NULL);
5478 }
5479 if (cur == ctxt->context->doc->children)
5480 return((xmlNodePtr) ctxt->context->doc);
5481 if (cur == (xmlNodePtr) ctxt->context->doc)
5482 return(NULL);
5483 switch (cur->type) {
5484 case XML_ELEMENT_NODE:
5485 case XML_TEXT_NODE:
5486 case XML_CDATA_SECTION_NODE:
5487 case XML_ENTITY_REF_NODE:
5488 case XML_ENTITY_NODE:
5489 case XML_PI_NODE:
5490 case XML_COMMENT_NODE:
5491 case XML_NOTATION_NODE:
5492 case XML_DTD_NODE:
5493 case XML_ELEMENT_DECL:
5494 case XML_ATTRIBUTE_DECL:
5495 case XML_ENTITY_DECL:
5496 case XML_XINCLUDE_START:
5497 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005498 if (cur->parent == NULL)
5499 return(NULL);
5500 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005501 ((cur->parent->name[0] == ' ') ||
5502 (xmlStrEqual(cur->parent->name,
5503 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005504 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005505 return(cur->parent);
5506 case XML_ATTRIBUTE_NODE: {
5507 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5508
5509 return(att->parent);
5510 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005511 case XML_NAMESPACE_DECL: {
5512 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5513
5514 if ((ns->next != NULL) &&
5515 (ns->next->type != XML_NAMESPACE_DECL))
5516 return((xmlNodePtr) ns->next);
5517 /* Bad, how did that namespace ended-up there ? */
5518 return(NULL);
5519 }
Owen Taylor3473f882001-02-23 17:55:21 +00005520 case XML_DOCUMENT_NODE:
5521 case XML_DOCUMENT_TYPE_NODE:
5522 case XML_DOCUMENT_FRAG_NODE:
5523 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005524#ifdef LIBXML_DOCB_ENABLED
5525 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005526#endif
5527 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005528 }
5529 return(NULL);
5530}
5531
5532/**
5533 * xmlXPathNextAncestorOrSelf:
5534 * @ctxt: the XPath Parser context
5535 * @cur: the current node in the traversal
5536 *
5537 * Traversal function for the "ancestor-or-self" direction
5538 * he ancestor-or-self axis contains the context node and ancestors of
5539 * the context node in reverse document order; thus the context node is
5540 * the first node on the axis, and the context node's parent the second;
5541 * parent here is defined the same as with the parent axis.
5542 *
5543 * Returns the next element following that axis
5544 */
5545xmlNodePtr
5546xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5547 if (cur == NULL)
5548 return(ctxt->context->node);
5549 return(xmlXPathNextAncestor(ctxt, cur));
5550}
5551
5552/**
5553 * xmlXPathNextFollowingSibling:
5554 * @ctxt: the XPath Parser context
5555 * @cur: the current node in the traversal
5556 *
5557 * Traversal function for the "following-sibling" direction
5558 * The following-sibling axis contains the following siblings of the context
5559 * node in document order.
5560 *
5561 * Returns the next element following that axis
5562 */
5563xmlNodePtr
5564xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5565 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5566 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5567 return(NULL);
5568 if (cur == (xmlNodePtr) ctxt->context->doc)
5569 return(NULL);
5570 if (cur == NULL)
5571 return(ctxt->context->node->next);
5572 return(cur->next);
5573}
5574
5575/**
5576 * xmlXPathNextPrecedingSibling:
5577 * @ctxt: the XPath Parser context
5578 * @cur: the current node in the traversal
5579 *
5580 * Traversal function for the "preceding-sibling" direction
5581 * The preceding-sibling axis contains the preceding siblings of the context
5582 * node in reverse document order; the first preceding sibling is first on the
5583 * axis; the sibling preceding that node is the second on the axis and so on.
5584 *
5585 * Returns the next element following that axis
5586 */
5587xmlNodePtr
5588xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5589 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5590 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5591 return(NULL);
5592 if (cur == (xmlNodePtr) ctxt->context->doc)
5593 return(NULL);
5594 if (cur == NULL)
5595 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005596 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5597 cur = cur->prev;
5598 if (cur == NULL)
5599 return(ctxt->context->node->prev);
5600 }
Owen Taylor3473f882001-02-23 17:55:21 +00005601 return(cur->prev);
5602}
5603
5604/**
5605 * xmlXPathNextFollowing:
5606 * @ctxt: the XPath Parser context
5607 * @cur: the current node in the traversal
5608 *
5609 * Traversal function for the "following" direction
5610 * The following axis contains all nodes in the same document as the context
5611 * node that are after the context node in document order, excluding any
5612 * descendants and excluding attribute nodes and namespace nodes; the nodes
5613 * are ordered in document order
5614 *
5615 * Returns the next element following that axis
5616 */
5617xmlNodePtr
5618xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5619 if (cur != NULL && cur->children != NULL)
5620 return cur->children ;
5621 if (cur == NULL) cur = ctxt->context->node;
5622 if (cur == NULL) return(NULL) ; /* ERROR */
5623 if (cur->next != NULL) return(cur->next) ;
5624 do {
5625 cur = cur->parent;
5626 if (cur == NULL) return(NULL);
5627 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5628 if (cur->next != NULL) return(cur->next);
5629 } while (cur != NULL);
5630 return(cur);
5631}
5632
5633/*
5634 * xmlXPathIsAncestor:
5635 * @ancestor: the ancestor node
5636 * @node: the current node
5637 *
5638 * Check that @ancestor is a @node's ancestor
5639 *
5640 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5641 */
5642static int
5643xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5644 if ((ancestor == NULL) || (node == NULL)) return(0);
5645 /* nodes need to be in the same document */
5646 if (ancestor->doc != node->doc) return(0);
5647 /* avoid searching if ancestor or node is the root node */
5648 if (ancestor == (xmlNodePtr) node->doc) return(1);
5649 if (node == (xmlNodePtr) ancestor->doc) return(0);
5650 while (node->parent != NULL) {
5651 if (node->parent == ancestor)
5652 return(1);
5653 node = node->parent;
5654 }
5655 return(0);
5656}
5657
5658/**
5659 * xmlXPathNextPreceding:
5660 * @ctxt: the XPath Parser context
5661 * @cur: the current node in the traversal
5662 *
5663 * Traversal function for the "preceding" direction
5664 * the preceding axis contains all nodes in the same document as the context
5665 * node that are before the context node in document order, excluding any
5666 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5667 * ordered in reverse document order
5668 *
5669 * Returns the next element following that axis
5670 */
5671xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005672xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5673{
Owen Taylor3473f882001-02-23 17:55:21 +00005674 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005675 cur = ctxt->context->node;
5676 if (cur == NULL)
5677 return (NULL);
5678 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5679 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005680 do {
5681 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005682 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5683 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005684 }
5685
5686 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005687 if (cur == NULL)
5688 return (NULL);
5689 if (cur == ctxt->context->doc->children)
5690 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005691 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005692 return (cur);
5693}
5694
5695/**
5696 * xmlXPathNextPrecedingInternal:
5697 * @ctxt: the XPath Parser context
5698 * @cur: the current node in the traversal
5699 *
5700 * Traversal function for the "preceding" direction
5701 * the preceding axis contains all nodes in the same document as the context
5702 * node that are before the context node in document order, excluding any
5703 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5704 * ordered in reverse document order
5705 * This is a faster implementation but internal only since it requires a
5706 * state kept in the parser context: ctxt->ancestor.
5707 *
5708 * Returns the next element following that axis
5709 */
5710static xmlNodePtr
5711xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5712 xmlNodePtr cur)
5713{
5714 if (cur == NULL) {
5715 cur = ctxt->context->node;
5716 if (cur == NULL)
5717 return (NULL);
5718 ctxt->ancestor = cur->parent;
5719 }
5720 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5721 cur = cur->prev;
5722 while (cur->prev == NULL) {
5723 cur = cur->parent;
5724 if (cur == NULL)
5725 return (NULL);
5726 if (cur == ctxt->context->doc->children)
5727 return (NULL);
5728 if (cur != ctxt->ancestor)
5729 return (cur);
5730 ctxt->ancestor = cur->parent;
5731 }
5732 cur = cur->prev;
5733 while (cur->last != NULL)
5734 cur = cur->last;
5735 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005736}
5737
5738/**
5739 * xmlXPathNextNamespace:
5740 * @ctxt: the XPath Parser context
5741 * @cur: the current attribute in the traversal
5742 *
5743 * Traversal function for the "namespace" direction
5744 * the namespace axis contains the namespace nodes of the context node;
5745 * the order of nodes on this axis is implementation-defined; the axis will
5746 * be empty unless the context node is an element
5747 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005748 * We keep the XML namespace node at the end of the list.
5749 *
Owen Taylor3473f882001-02-23 17:55:21 +00005750 * Returns the next element following that axis
5751 */
5752xmlNodePtr
5753xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5754 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005755 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005756 if (ctxt->context->tmpNsList != NULL)
5757 xmlFree(ctxt->context->tmpNsList);
5758 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005759 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005760 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005761 if (ctxt->context->tmpNsList != NULL) {
5762 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5763 ctxt->context->tmpNsNr++;
5764 }
5765 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005766 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005767 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005768 if (ctxt->context->tmpNsNr > 0) {
5769 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5770 } else {
5771 if (ctxt->context->tmpNsList != NULL)
5772 xmlFree(ctxt->context->tmpNsList);
5773 ctxt->context->tmpNsList = NULL;
5774 return(NULL);
5775 }
Owen Taylor3473f882001-02-23 17:55:21 +00005776}
5777
5778/**
5779 * xmlXPathNextAttribute:
5780 * @ctxt: the XPath Parser context
5781 * @cur: the current attribute in the traversal
5782 *
5783 * Traversal function for the "attribute" direction
5784 * TODO: support DTD inherited default attributes
5785 *
5786 * Returns the next element following that axis
5787 */
5788xmlNodePtr
5789xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005790 if (ctxt->context->node == NULL)
5791 return(NULL);
5792 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5793 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005794 if (cur == NULL) {
5795 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5796 return(NULL);
5797 return((xmlNodePtr)ctxt->context->node->properties);
5798 }
5799 return((xmlNodePtr)cur->next);
5800}
5801
5802/************************************************************************
5803 * *
5804 * NodeTest Functions *
5805 * *
5806 ************************************************************************/
5807
Owen Taylor3473f882001-02-23 17:55:21 +00005808#define IS_FUNCTION 200
5809
Owen Taylor3473f882001-02-23 17:55:21 +00005810
5811/************************************************************************
5812 * *
5813 * Implicit tree core function library *
5814 * *
5815 ************************************************************************/
5816
5817/**
5818 * xmlXPathRoot:
5819 * @ctxt: the XPath Parser context
5820 *
5821 * Initialize the context to the root of the document
5822 */
5823void
5824xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5825 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5826 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5827}
5828
5829/************************************************************************
5830 * *
5831 * The explicit core function library *
5832 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5833 * *
5834 ************************************************************************/
5835
5836
5837/**
5838 * xmlXPathLastFunction:
5839 * @ctxt: the XPath Parser context
5840 * @nargs: the number of arguments
5841 *
5842 * Implement the last() XPath function
5843 * number last()
5844 * The last function returns the number of nodes in the context node list.
5845 */
5846void
5847xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5848 CHECK_ARITY(0);
5849 if (ctxt->context->contextSize >= 0) {
5850 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5851#ifdef DEBUG_EXPR
5852 xmlGenericError(xmlGenericErrorContext,
5853 "last() : %d\n", ctxt->context->contextSize);
5854#endif
5855 } else {
5856 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5857 }
5858}
5859
5860/**
5861 * xmlXPathPositionFunction:
5862 * @ctxt: the XPath Parser context
5863 * @nargs: the number of arguments
5864 *
5865 * Implement the position() XPath function
5866 * number position()
5867 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005868 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005869 * will be equal to last().
5870 */
5871void
5872xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5873 CHECK_ARITY(0);
5874 if (ctxt->context->proximityPosition >= 0) {
5875 valuePush(ctxt,
5876 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5877#ifdef DEBUG_EXPR
5878 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5879 ctxt->context->proximityPosition);
5880#endif
5881 } else {
5882 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5883 }
5884}
5885
5886/**
5887 * xmlXPathCountFunction:
5888 * @ctxt: the XPath Parser context
5889 * @nargs: the number of arguments
5890 *
5891 * Implement the count() XPath function
5892 * number count(node-set)
5893 */
5894void
5895xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5896 xmlXPathObjectPtr cur;
5897
5898 CHECK_ARITY(1);
5899 if ((ctxt->value == NULL) ||
5900 ((ctxt->value->type != XPATH_NODESET) &&
5901 (ctxt->value->type != XPATH_XSLT_TREE)))
5902 XP_ERROR(XPATH_INVALID_TYPE);
5903 cur = valuePop(ctxt);
5904
Daniel Veillard911f49a2001-04-07 15:39:35 +00005905 if ((cur == NULL) || (cur->nodesetval == NULL))
5906 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005907 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005908 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005909 } else {
5910 if ((cur->nodesetval->nodeNr != 1) ||
5911 (cur->nodesetval->nodeTab == NULL)) {
5912 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5913 } else {
5914 xmlNodePtr tmp;
5915 int i = 0;
5916
5917 tmp = cur->nodesetval->nodeTab[0];
5918 if (tmp != NULL) {
5919 tmp = tmp->children;
5920 while (tmp != NULL) {
5921 tmp = tmp->next;
5922 i++;
5923 }
5924 }
5925 valuePush(ctxt, xmlXPathNewFloat((double) i));
5926 }
5927 }
Owen Taylor3473f882001-02-23 17:55:21 +00005928 xmlXPathFreeObject(cur);
5929}
5930
5931/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005932 * xmlXPathGetElementsByIds:
5933 * @doc: the document
5934 * @ids: a whitespace separated list of IDs
5935 *
5936 * Selects elements by their unique ID.
5937 *
5938 * Returns a node-set of selected elements.
5939 */
5940static xmlNodeSetPtr
5941xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5942 xmlNodeSetPtr ret;
5943 const xmlChar *cur = ids;
5944 xmlChar *ID;
5945 xmlAttrPtr attr;
5946 xmlNodePtr elem = NULL;
5947
Daniel Veillard7a985a12003-07-06 17:57:42 +00005948 if (ids == NULL) return(NULL);
5949
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005950 ret = xmlXPathNodeSetCreate(NULL);
5951
5952 while (IS_BLANK(*cur)) cur++;
5953 while (*cur != 0) {
Daniel Veillarde209b332003-03-26 21:40:13 +00005954 while ((!IS_BLANK(*cur)) && (*cur != 0))
5955 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005956
5957 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00005958 if (ID != NULL) {
5959 if (xmlValidateNCName(ID, 1) == 0) {
5960 attr = xmlGetID(doc, ID);
5961 if (attr != NULL) {
5962 if (attr->type == XML_ATTRIBUTE_NODE)
5963 elem = attr->parent;
5964 else if (attr->type == XML_ELEMENT_NODE)
5965 elem = (xmlNodePtr) attr;
5966 else
5967 elem = NULL;
5968 if (elem != NULL)
5969 xmlXPathNodeSetAdd(ret, elem);
5970 }
5971 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005972 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00005973 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005974
5975 while (IS_BLANK(*cur)) cur++;
5976 ids = cur;
5977 }
5978 return(ret);
5979}
5980
5981/**
Owen Taylor3473f882001-02-23 17:55:21 +00005982 * xmlXPathIdFunction:
5983 * @ctxt: the XPath Parser context
5984 * @nargs: the number of arguments
5985 *
5986 * Implement the id() XPath function
5987 * node-set id(object)
5988 * The id function selects elements by their unique ID
5989 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5990 * then the result is the union of the result of applying id to the
5991 * string value of each of the nodes in the argument node-set. When the
5992 * argument to id is of any other type, the argument is converted to a
5993 * string as if by a call to the string function; the string is split
5994 * into a whitespace-separated list of tokens (whitespace is any sequence
5995 * of characters matching the production S); the result is a node-set
5996 * containing the elements in the same document as the context node that
5997 * have a unique ID equal to any of the tokens in the list.
5998 */
5999void
6000xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006001 xmlChar *tokens;
6002 xmlNodeSetPtr ret;
6003 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006004
6005 CHECK_ARITY(1);
6006 obj = valuePop(ctxt);
6007 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006008 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006009 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006010 int i;
6011
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006012 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006013
Daniel Veillard911f49a2001-04-07 15:39:35 +00006014 if (obj->nodesetval != NULL) {
6015 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006016 tokens =
6017 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6018 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6019 ret = xmlXPathNodeSetMerge(ret, ns);
6020 xmlXPathFreeNodeSet(ns);
6021 if (tokens != NULL)
6022 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006023 }
Owen Taylor3473f882001-02-23 17:55:21 +00006024 }
6025
6026 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006027 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006028 return;
6029 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006030 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006031
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006032 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6033 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006034
Owen Taylor3473f882001-02-23 17:55:21 +00006035 xmlXPathFreeObject(obj);
6036 return;
6037}
6038
6039/**
6040 * xmlXPathLocalNameFunction:
6041 * @ctxt: the XPath Parser context
6042 * @nargs: the number of arguments
6043 *
6044 * Implement the local-name() XPath function
6045 * string local-name(node-set?)
6046 * The local-name function returns a string containing the local part
6047 * of the name of the node in the argument node-set that is first in
6048 * document order. If the node-set is empty or the first node has no
6049 * name, an empty string is returned. If the argument is omitted it
6050 * defaults to the context node.
6051 */
6052void
6053xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6054 xmlXPathObjectPtr cur;
6055
6056 if (nargs == 0) {
6057 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6058 nargs = 1;
6059 }
6060
6061 CHECK_ARITY(1);
6062 if ((ctxt->value == NULL) ||
6063 ((ctxt->value->type != XPATH_NODESET) &&
6064 (ctxt->value->type != XPATH_XSLT_TREE)))
6065 XP_ERROR(XPATH_INVALID_TYPE);
6066 cur = valuePop(ctxt);
6067
Daniel Veillard911f49a2001-04-07 15:39:35 +00006068 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006069 valuePush(ctxt, xmlXPathNewCString(""));
6070 } else {
6071 int i = 0; /* Should be first in document order !!!!! */
6072 switch (cur->nodesetval->nodeTab[i]->type) {
6073 case XML_ELEMENT_NODE:
6074 case XML_ATTRIBUTE_NODE:
6075 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006076 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6077 valuePush(ctxt, xmlXPathNewCString(""));
6078 else
6079 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006080 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6081 break;
6082 case XML_NAMESPACE_DECL:
6083 valuePush(ctxt, xmlXPathNewString(
6084 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6085 break;
6086 default:
6087 valuePush(ctxt, xmlXPathNewCString(""));
6088 }
6089 }
6090 xmlXPathFreeObject(cur);
6091}
6092
6093/**
6094 * xmlXPathNamespaceURIFunction:
6095 * @ctxt: the XPath Parser context
6096 * @nargs: the number of arguments
6097 *
6098 * Implement the namespace-uri() XPath function
6099 * string namespace-uri(node-set?)
6100 * The namespace-uri function returns a string containing the
6101 * namespace URI of the expanded name of the node in the argument
6102 * node-set that is first in document order. If the node-set is empty,
6103 * the first node has no name, or the expanded name has no namespace
6104 * URI, an empty string is returned. If the argument is omitted it
6105 * defaults to the context node.
6106 */
6107void
6108xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6109 xmlXPathObjectPtr cur;
6110
6111 if (nargs == 0) {
6112 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6113 nargs = 1;
6114 }
6115 CHECK_ARITY(1);
6116 if ((ctxt->value == NULL) ||
6117 ((ctxt->value->type != XPATH_NODESET) &&
6118 (ctxt->value->type != XPATH_XSLT_TREE)))
6119 XP_ERROR(XPATH_INVALID_TYPE);
6120 cur = valuePop(ctxt);
6121
Daniel Veillard911f49a2001-04-07 15:39:35 +00006122 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006123 valuePush(ctxt, xmlXPathNewCString(""));
6124 } else {
6125 int i = 0; /* Should be first in document order !!!!! */
6126 switch (cur->nodesetval->nodeTab[i]->type) {
6127 case XML_ELEMENT_NODE:
6128 case XML_ATTRIBUTE_NODE:
6129 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6130 valuePush(ctxt, xmlXPathNewCString(""));
6131 else
6132 valuePush(ctxt, xmlXPathNewString(
6133 cur->nodesetval->nodeTab[i]->ns->href));
6134 break;
6135 default:
6136 valuePush(ctxt, xmlXPathNewCString(""));
6137 }
6138 }
6139 xmlXPathFreeObject(cur);
6140}
6141
6142/**
6143 * xmlXPathNameFunction:
6144 * @ctxt: the XPath Parser context
6145 * @nargs: the number of arguments
6146 *
6147 * Implement the name() XPath function
6148 * string name(node-set?)
6149 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006150 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006151 * order. The QName must represent the name with respect to the namespace
6152 * declarations in effect on the node whose name is being represented.
6153 * Typically, this will be the form in which the name occurred in the XML
6154 * source. This need not be the case if there are namespace declarations
6155 * in effect on the node that associate multiple prefixes with the same
6156 * namespace. However, an implementation may include information about
6157 * the original prefix in its representation of nodes; in this case, an
6158 * implementation can ensure that the returned string is always the same
6159 * as the QName used in the XML source. If the argument it omitted it
6160 * defaults to the context node.
6161 * Libxml keep the original prefix so the "real qualified name" used is
6162 * returned.
6163 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006164static void
Daniel Veillard04383752001-07-08 14:27:15 +00006165xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6166{
Owen Taylor3473f882001-02-23 17:55:21 +00006167 xmlXPathObjectPtr cur;
6168
6169 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006170 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6171 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006172 }
6173
6174 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006175 if ((ctxt->value == NULL) ||
6176 ((ctxt->value->type != XPATH_NODESET) &&
6177 (ctxt->value->type != XPATH_XSLT_TREE)))
6178 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006179 cur = valuePop(ctxt);
6180
Daniel Veillard911f49a2001-04-07 15:39:35 +00006181 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006182 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006183 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006184 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006185
Daniel Veillard04383752001-07-08 14:27:15 +00006186 switch (cur->nodesetval->nodeTab[i]->type) {
6187 case XML_ELEMENT_NODE:
6188 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006189 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6190 valuePush(ctxt, xmlXPathNewCString(""));
6191 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6192 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006193 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006194 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006195
Daniel Veillard652d8a92003-02-04 19:28:49 +00006196 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006197 xmlChar *fullname;
6198
6199 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6200 cur->nodesetval->nodeTab[i]->ns->prefix,
6201 NULL, 0);
6202 if (fullname == cur->nodesetval->nodeTab[i]->name)
6203 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6204 if (fullname == NULL) {
6205 XP_ERROR(XPATH_MEMORY_ERROR);
6206 }
6207 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006208 }
6209 break;
6210 default:
6211 valuePush(ctxt,
6212 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6213 xmlXPathLocalNameFunction(ctxt, 1);
6214 }
Owen Taylor3473f882001-02-23 17:55:21 +00006215 }
6216 xmlXPathFreeObject(cur);
6217}
6218
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006219
6220/**
Owen Taylor3473f882001-02-23 17:55:21 +00006221 * xmlXPathStringFunction:
6222 * @ctxt: the XPath Parser context
6223 * @nargs: the number of arguments
6224 *
6225 * Implement the string() XPath function
6226 * string string(object?)
6227 * he string function converts an object to a string as follows:
6228 * - A node-set is converted to a string by returning the value of
6229 * the node in the node-set that is first in document order.
6230 * If the node-set is empty, an empty string is returned.
6231 * - A number is converted to a string as follows
6232 * + NaN is converted to the string NaN
6233 * + positive zero is converted to the string 0
6234 * + negative zero is converted to the string 0
6235 * + positive infinity is converted to the string Infinity
6236 * + negative infinity is converted to the string -Infinity
6237 * + if the number is an integer, the number is represented in
6238 * decimal form as a Number with no decimal point and no leading
6239 * zeros, preceded by a minus sign (-) if the number is negative
6240 * + otherwise, the number is represented in decimal form as a
6241 * Number including a decimal point with at least one digit
6242 * before the decimal point and at least one digit after the
6243 * decimal point, preceded by a minus sign (-) if the number
6244 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006245 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006246 * before the decimal point; beyond the one required digit
6247 * after the decimal point there must be as many, but only as
6248 * many, more digits as are needed to uniquely distinguish the
6249 * number from all other IEEE 754 numeric values.
6250 * - The boolean false value is converted to the string false.
6251 * The boolean true value is converted to the string true.
6252 *
6253 * If the argument is omitted, it defaults to a node-set with the
6254 * context node as its only member.
6255 */
6256void
6257xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6258 xmlXPathObjectPtr cur;
6259
6260 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006261 valuePush(ctxt,
6262 xmlXPathWrapString(
6263 xmlXPathCastNodeToString(ctxt->context->node)));
6264 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006265 }
6266
6267 CHECK_ARITY(1);
6268 cur = valuePop(ctxt);
6269 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006270 cur = xmlXPathConvertString(cur);
6271 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006272}
6273
6274/**
6275 * xmlXPathStringLengthFunction:
6276 * @ctxt: the XPath Parser context
6277 * @nargs: the number of arguments
6278 *
6279 * Implement the string-length() XPath function
6280 * number string-length(string?)
6281 * The string-length returns the number of characters in the string
6282 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6283 * the context node converted to a string, in other words the value
6284 * of the context node.
6285 */
6286void
6287xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6288 xmlXPathObjectPtr cur;
6289
6290 if (nargs == 0) {
6291 if (ctxt->context->node == NULL) {
6292 valuePush(ctxt, xmlXPathNewFloat(0));
6293 } else {
6294 xmlChar *content;
6295
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006296 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006297 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006298 xmlFree(content);
6299 }
6300 return;
6301 }
6302 CHECK_ARITY(1);
6303 CAST_TO_STRING;
6304 CHECK_TYPE(XPATH_STRING);
6305 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006306 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006307 xmlXPathFreeObject(cur);
6308}
6309
6310/**
6311 * xmlXPathConcatFunction:
6312 * @ctxt: the XPath Parser context
6313 * @nargs: the number of arguments
6314 *
6315 * Implement the concat() XPath function
6316 * string concat(string, string, string*)
6317 * The concat function returns the concatenation of its arguments.
6318 */
6319void
6320xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6321 xmlXPathObjectPtr cur, newobj;
6322 xmlChar *tmp;
6323
6324 if (nargs < 2) {
6325 CHECK_ARITY(2);
6326 }
6327
6328 CAST_TO_STRING;
6329 cur = valuePop(ctxt);
6330 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6331 xmlXPathFreeObject(cur);
6332 return;
6333 }
6334 nargs--;
6335
6336 while (nargs > 0) {
6337 CAST_TO_STRING;
6338 newobj = valuePop(ctxt);
6339 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6340 xmlXPathFreeObject(newobj);
6341 xmlXPathFreeObject(cur);
6342 XP_ERROR(XPATH_INVALID_TYPE);
6343 }
6344 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6345 newobj->stringval = cur->stringval;
6346 cur->stringval = tmp;
6347
6348 xmlXPathFreeObject(newobj);
6349 nargs--;
6350 }
6351 valuePush(ctxt, cur);
6352}
6353
6354/**
6355 * xmlXPathContainsFunction:
6356 * @ctxt: the XPath Parser context
6357 * @nargs: the number of arguments
6358 *
6359 * Implement the contains() XPath function
6360 * boolean contains(string, string)
6361 * The contains function returns true if the first argument string
6362 * contains the second argument string, and otherwise returns false.
6363 */
6364void
6365xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6366 xmlXPathObjectPtr hay, needle;
6367
6368 CHECK_ARITY(2);
6369 CAST_TO_STRING;
6370 CHECK_TYPE(XPATH_STRING);
6371 needle = valuePop(ctxt);
6372 CAST_TO_STRING;
6373 hay = valuePop(ctxt);
6374 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6375 xmlXPathFreeObject(hay);
6376 xmlXPathFreeObject(needle);
6377 XP_ERROR(XPATH_INVALID_TYPE);
6378 }
6379 if (xmlStrstr(hay->stringval, needle->stringval))
6380 valuePush(ctxt, xmlXPathNewBoolean(1));
6381 else
6382 valuePush(ctxt, xmlXPathNewBoolean(0));
6383 xmlXPathFreeObject(hay);
6384 xmlXPathFreeObject(needle);
6385}
6386
6387/**
6388 * xmlXPathStartsWithFunction:
6389 * @ctxt: the XPath Parser context
6390 * @nargs: the number of arguments
6391 *
6392 * Implement the starts-with() XPath function
6393 * boolean starts-with(string, string)
6394 * The starts-with function returns true if the first argument string
6395 * starts with the second argument string, and otherwise returns false.
6396 */
6397void
6398xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6399 xmlXPathObjectPtr hay, needle;
6400 int n;
6401
6402 CHECK_ARITY(2);
6403 CAST_TO_STRING;
6404 CHECK_TYPE(XPATH_STRING);
6405 needle = valuePop(ctxt);
6406 CAST_TO_STRING;
6407 hay = valuePop(ctxt);
6408 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6409 xmlXPathFreeObject(hay);
6410 xmlXPathFreeObject(needle);
6411 XP_ERROR(XPATH_INVALID_TYPE);
6412 }
6413 n = xmlStrlen(needle->stringval);
6414 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6415 valuePush(ctxt, xmlXPathNewBoolean(0));
6416 else
6417 valuePush(ctxt, xmlXPathNewBoolean(1));
6418 xmlXPathFreeObject(hay);
6419 xmlXPathFreeObject(needle);
6420}
6421
6422/**
6423 * xmlXPathSubstringFunction:
6424 * @ctxt: the XPath Parser context
6425 * @nargs: the number of arguments
6426 *
6427 * Implement the substring() XPath function
6428 * string substring(string, number, number?)
6429 * The substring function returns the substring of the first argument
6430 * starting at the position specified in the second argument with
6431 * length specified in the third argument. For example,
6432 * substring("12345",2,3) returns "234". If the third argument is not
6433 * specified, it returns the substring starting at the position specified
6434 * in the second argument and continuing to the end of the string. For
6435 * example, substring("12345",2) returns "2345". More precisely, each
6436 * character in the string (see [3.6 Strings]) is considered to have a
6437 * numeric position: the position of the first character is 1, the position
6438 * of the second character is 2 and so on. The returned substring contains
6439 * those characters for which the position of the character is greater than
6440 * or equal to the second argument and, if the third argument is specified,
6441 * less than the sum of the second and third arguments; the comparisons
6442 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6443 * - substring("12345", 1.5, 2.6) returns "234"
6444 * - substring("12345", 0, 3) returns "12"
6445 * - substring("12345", 0 div 0, 3) returns ""
6446 * - substring("12345", 1, 0 div 0) returns ""
6447 * - substring("12345", -42, 1 div 0) returns "12345"
6448 * - substring("12345", -1 div 0, 1 div 0) returns ""
6449 */
6450void
6451xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6452 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006453 double le=0, in;
6454 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006455 xmlChar *ret;
6456
Owen Taylor3473f882001-02-23 17:55:21 +00006457 if (nargs < 2) {
6458 CHECK_ARITY(2);
6459 }
6460 if (nargs > 3) {
6461 CHECK_ARITY(3);
6462 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006463 /*
6464 * take care of possible last (position) argument
6465 */
Owen Taylor3473f882001-02-23 17:55:21 +00006466 if (nargs == 3) {
6467 CAST_TO_NUMBER;
6468 CHECK_TYPE(XPATH_NUMBER);
6469 len = valuePop(ctxt);
6470 le = len->floatval;
6471 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006472 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006473
Owen Taylor3473f882001-02-23 17:55:21 +00006474 CAST_TO_NUMBER;
6475 CHECK_TYPE(XPATH_NUMBER);
6476 start = valuePop(ctxt);
6477 in = start->floatval;
6478 xmlXPathFreeObject(start);
6479 CAST_TO_STRING;
6480 CHECK_TYPE(XPATH_STRING);
6481 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006482 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006483
Daniel Veillard97ac1312001-05-30 19:14:17 +00006484 /*
6485 * If last pos not present, calculate last position
6486 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006487 if (nargs != 3) {
6488 le = (double)m;
6489 if (in < 1.0)
6490 in = 1.0;
6491 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006492
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006493 /* Need to check for the special cases where either
6494 * the index is NaN, the length is NaN, or both
6495 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006496 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006497 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006498 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006499 * To meet the requirements of the spec, the arguments
6500 * must be converted to integer format before
6501 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006502 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006503 * First we go to integer form, rounding up
6504 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006505 */
6506 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006507 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006508
Daniel Veillard9e412302002-06-10 15:59:44 +00006509 if (xmlXPathIsInf(le) == 1) {
6510 l = m;
6511 if (i < 1)
6512 i = 1;
6513 }
6514 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6515 l = 0;
6516 else {
6517 l = (int) le;
6518 if (((double)l)+0.5 <= le) l++;
6519 }
6520
6521 /* Now we normalize inidices */
6522 i -= 1;
6523 l += i;
6524 if (i < 0)
6525 i = 0;
6526 if (l > m)
6527 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006528
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006529 /* number of chars to copy */
6530 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006531
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006532 ret = xmlUTF8Strsub(str->stringval, i, l);
6533 }
6534 else {
6535 ret = NULL;
6536 }
6537
Owen Taylor3473f882001-02-23 17:55:21 +00006538 if (ret == NULL)
6539 valuePush(ctxt, xmlXPathNewCString(""));
6540 else {
6541 valuePush(ctxt, xmlXPathNewString(ret));
6542 xmlFree(ret);
6543 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006544
Owen Taylor3473f882001-02-23 17:55:21 +00006545 xmlXPathFreeObject(str);
6546}
6547
6548/**
6549 * xmlXPathSubstringBeforeFunction:
6550 * @ctxt: the XPath Parser context
6551 * @nargs: the number of arguments
6552 *
6553 * Implement the substring-before() XPath function
6554 * string substring-before(string, string)
6555 * The substring-before function returns the substring of the first
6556 * argument string that precedes the first occurrence of the second
6557 * argument string in the first argument string, or the empty string
6558 * if the first argument string does not contain the second argument
6559 * string. For example, substring-before("1999/04/01","/") returns 1999.
6560 */
6561void
6562xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6563 xmlXPathObjectPtr str;
6564 xmlXPathObjectPtr find;
6565 xmlBufferPtr target;
6566 const xmlChar *point;
6567 int offset;
6568
6569 CHECK_ARITY(2);
6570 CAST_TO_STRING;
6571 find = valuePop(ctxt);
6572 CAST_TO_STRING;
6573 str = valuePop(ctxt);
6574
6575 target = xmlBufferCreate();
6576 if (target) {
6577 point = xmlStrstr(str->stringval, find->stringval);
6578 if (point) {
6579 offset = (int)(point - str->stringval);
6580 xmlBufferAdd(target, str->stringval, offset);
6581 }
6582 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6583 xmlBufferFree(target);
6584 }
6585
6586 xmlXPathFreeObject(str);
6587 xmlXPathFreeObject(find);
6588}
6589
6590/**
6591 * xmlXPathSubstringAfterFunction:
6592 * @ctxt: the XPath Parser context
6593 * @nargs: the number of arguments
6594 *
6595 * Implement the substring-after() XPath function
6596 * string substring-after(string, string)
6597 * The substring-after function returns the substring of the first
6598 * argument string that follows the first occurrence of the second
6599 * argument string in the first argument string, or the empty stringi
6600 * if the first argument string does not contain the second argument
6601 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6602 * and substring-after("1999/04/01","19") returns 99/04/01.
6603 */
6604void
6605xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6606 xmlXPathObjectPtr str;
6607 xmlXPathObjectPtr find;
6608 xmlBufferPtr target;
6609 const xmlChar *point;
6610 int offset;
6611
6612 CHECK_ARITY(2);
6613 CAST_TO_STRING;
6614 find = valuePop(ctxt);
6615 CAST_TO_STRING;
6616 str = valuePop(ctxt);
6617
6618 target = xmlBufferCreate();
6619 if (target) {
6620 point = xmlStrstr(str->stringval, find->stringval);
6621 if (point) {
6622 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6623 xmlBufferAdd(target, &str->stringval[offset],
6624 xmlStrlen(str->stringval) - offset);
6625 }
6626 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6627 xmlBufferFree(target);
6628 }
6629
6630 xmlXPathFreeObject(str);
6631 xmlXPathFreeObject(find);
6632}
6633
6634/**
6635 * xmlXPathNormalizeFunction:
6636 * @ctxt: the XPath Parser context
6637 * @nargs: the number of arguments
6638 *
6639 * Implement the normalize-space() XPath function
6640 * string normalize-space(string?)
6641 * The normalize-space function returns the argument string with white
6642 * space normalized by stripping leading and trailing whitespace
6643 * and replacing sequences of whitespace characters by a single
6644 * space. Whitespace characters are the same allowed by the S production
6645 * in XML. If the argument is omitted, it defaults to the context
6646 * node converted to a string, in other words the value of the context node.
6647 */
6648void
6649xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6650 xmlXPathObjectPtr obj = NULL;
6651 xmlChar *source = NULL;
6652 xmlBufferPtr target;
6653 xmlChar blank;
6654
6655 if (nargs == 0) {
6656 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006657 valuePush(ctxt,
6658 xmlXPathWrapString(
6659 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006660 nargs = 1;
6661 }
6662
6663 CHECK_ARITY(1);
6664 CAST_TO_STRING;
6665 CHECK_TYPE(XPATH_STRING);
6666 obj = valuePop(ctxt);
6667 source = obj->stringval;
6668
6669 target = xmlBufferCreate();
6670 if (target && source) {
6671
6672 /* Skip leading whitespaces */
6673 while (IS_BLANK(*source))
6674 source++;
6675
6676 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6677 blank = 0;
6678 while (*source) {
6679 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006680 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006681 } else {
6682 if (blank) {
6683 xmlBufferAdd(target, &blank, 1);
6684 blank = 0;
6685 }
6686 xmlBufferAdd(target, source, 1);
6687 }
6688 source++;
6689 }
6690
6691 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6692 xmlBufferFree(target);
6693 }
6694 xmlXPathFreeObject(obj);
6695}
6696
6697/**
6698 * xmlXPathTranslateFunction:
6699 * @ctxt: the XPath Parser context
6700 * @nargs: the number of arguments
6701 *
6702 * Implement the translate() XPath function
6703 * string translate(string, string, string)
6704 * The translate function returns the first argument string with
6705 * occurrences of characters in the second argument string replaced
6706 * by the character at the corresponding position in the third argument
6707 * string. For example, translate("bar","abc","ABC") returns the string
6708 * BAr. If there is a character in the second argument string with no
6709 * character at a corresponding position in the third argument string
6710 * (because the second argument string is longer than the third argument
6711 * string), then occurrences of that character in the first argument
6712 * string are removed. For example, translate("--aaa--","abc-","ABC")
6713 * returns "AAA". If a character occurs more than once in second
6714 * argument string, then the first occurrence determines the replacement
6715 * character. If the third argument string is longer than the second
6716 * argument string, then excess characters are ignored.
6717 */
6718void
6719xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006720 xmlXPathObjectPtr str;
6721 xmlXPathObjectPtr from;
6722 xmlXPathObjectPtr to;
6723 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006724 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006725 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006726 xmlChar *point;
6727 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006728
Daniel Veillarde043ee12001-04-16 14:08:07 +00006729 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006730
Daniel Veillarde043ee12001-04-16 14:08:07 +00006731 CAST_TO_STRING;
6732 to = valuePop(ctxt);
6733 CAST_TO_STRING;
6734 from = valuePop(ctxt);
6735 CAST_TO_STRING;
6736 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006737
Daniel Veillarde043ee12001-04-16 14:08:07 +00006738 target = xmlBufferCreate();
6739 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006740 max = xmlUTF8Strlen(to->stringval);
6741 for (cptr = str->stringval; (ch=*cptr); ) {
6742 offset = xmlUTF8Strloc(from->stringval, cptr);
6743 if (offset >= 0) {
6744 if (offset < max) {
6745 point = xmlUTF8Strpos(to->stringval, offset);
6746 if (point)
6747 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6748 }
6749 } else
6750 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6751
6752 /* Step to next character in input */
6753 cptr++;
6754 if ( ch & 0x80 ) {
6755 /* if not simple ascii, verify proper format */
6756 if ( (ch & 0xc0) != 0xc0 ) {
6757 xmlGenericError(xmlGenericErrorContext,
6758 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6759 break;
6760 }
6761 /* then skip over remaining bytes for this char */
6762 while ( (ch <<= 1) & 0x80 )
6763 if ( (*cptr++ & 0xc0) != 0x80 ) {
6764 xmlGenericError(xmlGenericErrorContext,
6765 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6766 break;
6767 }
6768 if (ch & 0x80) /* must have had error encountered */
6769 break;
6770 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006771 }
Owen Taylor3473f882001-02-23 17:55:21 +00006772 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006773 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6774 xmlBufferFree(target);
6775 xmlXPathFreeObject(str);
6776 xmlXPathFreeObject(from);
6777 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006778}
6779
6780/**
6781 * xmlXPathBooleanFunction:
6782 * @ctxt: the XPath Parser context
6783 * @nargs: the number of arguments
6784 *
6785 * Implement the boolean() XPath function
6786 * boolean boolean(object)
6787 * he boolean function converts its argument to a boolean as follows:
6788 * - a number is true if and only if it is neither positive or
6789 * negative zero nor NaN
6790 * - a node-set is true if and only if it is non-empty
6791 * - a string is true if and only if its length is non-zero
6792 */
6793void
6794xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6795 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006796
6797 CHECK_ARITY(1);
6798 cur = valuePop(ctxt);
6799 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006800 cur = xmlXPathConvertBoolean(cur);
6801 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006802}
6803
6804/**
6805 * xmlXPathNotFunction:
6806 * @ctxt: the XPath Parser context
6807 * @nargs: the number of arguments
6808 *
6809 * Implement the not() XPath function
6810 * boolean not(boolean)
6811 * The not function returns true if its argument is false,
6812 * and false otherwise.
6813 */
6814void
6815xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6816 CHECK_ARITY(1);
6817 CAST_TO_BOOLEAN;
6818 CHECK_TYPE(XPATH_BOOLEAN);
6819 ctxt->value->boolval = ! ctxt->value->boolval;
6820}
6821
6822/**
6823 * xmlXPathTrueFunction:
6824 * @ctxt: the XPath Parser context
6825 * @nargs: the number of arguments
6826 *
6827 * Implement the true() XPath function
6828 * boolean true()
6829 */
6830void
6831xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6832 CHECK_ARITY(0);
6833 valuePush(ctxt, xmlXPathNewBoolean(1));
6834}
6835
6836/**
6837 * xmlXPathFalseFunction:
6838 * @ctxt: the XPath Parser context
6839 * @nargs: the number of arguments
6840 *
6841 * Implement the false() XPath function
6842 * boolean false()
6843 */
6844void
6845xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6846 CHECK_ARITY(0);
6847 valuePush(ctxt, xmlXPathNewBoolean(0));
6848}
6849
6850/**
6851 * xmlXPathLangFunction:
6852 * @ctxt: the XPath Parser context
6853 * @nargs: the number of arguments
6854 *
6855 * Implement the lang() XPath function
6856 * boolean lang(string)
6857 * The lang function returns true or false depending on whether the
6858 * language of the context node as specified by xml:lang attributes
6859 * is the same as or is a sublanguage of the language specified by
6860 * the argument string. The language of the context node is determined
6861 * by the value of the xml:lang attribute on the context node, or, if
6862 * the context node has no xml:lang attribute, by the value of the
6863 * xml:lang attribute on the nearest ancestor of the context node that
6864 * has an xml:lang attribute. If there is no such attribute, then lang
6865 * returns false. If there is such an attribute, then lang returns
6866 * true if the attribute value is equal to the argument ignoring case,
6867 * or if there is some suffix starting with - such that the attribute
6868 * value is equal to the argument ignoring that suffix of the attribute
6869 * value and ignoring case.
6870 */
6871void
6872xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6873 xmlXPathObjectPtr val;
6874 const xmlChar *theLang;
6875 const xmlChar *lang;
6876 int ret = 0;
6877 int i;
6878
6879 CHECK_ARITY(1);
6880 CAST_TO_STRING;
6881 CHECK_TYPE(XPATH_STRING);
6882 val = valuePop(ctxt);
6883 lang = val->stringval;
6884 theLang = xmlNodeGetLang(ctxt->context->node);
6885 if ((theLang != NULL) && (lang != NULL)) {
6886 for (i = 0;lang[i] != 0;i++)
6887 if (toupper(lang[i]) != toupper(theLang[i]))
6888 goto not_equal;
6889 ret = 1;
6890 }
6891not_equal:
6892 xmlXPathFreeObject(val);
6893 valuePush(ctxt, xmlXPathNewBoolean(ret));
6894}
6895
6896/**
6897 * xmlXPathNumberFunction:
6898 * @ctxt: the XPath Parser context
6899 * @nargs: the number of arguments
6900 *
6901 * Implement the number() XPath function
6902 * number number(object?)
6903 */
6904void
6905xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6906 xmlXPathObjectPtr cur;
6907 double res;
6908
6909 if (nargs == 0) {
6910 if (ctxt->context->node == NULL) {
6911 valuePush(ctxt, xmlXPathNewFloat(0.0));
6912 } else {
6913 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6914
6915 res = xmlXPathStringEvalNumber(content);
6916 valuePush(ctxt, xmlXPathNewFloat(res));
6917 xmlFree(content);
6918 }
6919 return;
6920 }
6921
6922 CHECK_ARITY(1);
6923 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006924 cur = xmlXPathConvertNumber(cur);
6925 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006926}
6927
6928/**
6929 * xmlXPathSumFunction:
6930 * @ctxt: the XPath Parser context
6931 * @nargs: the number of arguments
6932 *
6933 * Implement the sum() XPath function
6934 * number sum(node-set)
6935 * The sum function returns the sum of the values of the nodes in
6936 * the argument node-set.
6937 */
6938void
6939xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6940 xmlXPathObjectPtr cur;
6941 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006942 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006943
6944 CHECK_ARITY(1);
6945 if ((ctxt->value == NULL) ||
6946 ((ctxt->value->type != XPATH_NODESET) &&
6947 (ctxt->value->type != XPATH_XSLT_TREE)))
6948 XP_ERROR(XPATH_INVALID_TYPE);
6949 cur = valuePop(ctxt);
6950
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006951 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006952 valuePush(ctxt, xmlXPathNewFloat(0.0));
6953 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006954 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6955 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006956 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006957 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006958 }
6959 xmlXPathFreeObject(cur);
6960}
6961
6962/**
6963 * xmlXPathFloorFunction:
6964 * @ctxt: the XPath Parser context
6965 * @nargs: the number of arguments
6966 *
6967 * Implement the floor() XPath function
6968 * number floor(number)
6969 * The floor function returns the largest (closest to positive infinity)
6970 * number that is not greater than the argument and that is an integer.
6971 */
6972void
6973xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006974 double f;
6975
Owen Taylor3473f882001-02-23 17:55:21 +00006976 CHECK_ARITY(1);
6977 CAST_TO_NUMBER;
6978 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006979
6980 f = (double)((int) ctxt->value->floatval);
6981 if (f != ctxt->value->floatval) {
6982 if (ctxt->value->floatval > 0)
6983 ctxt->value->floatval = f;
6984 else
6985 ctxt->value->floatval = f - 1;
6986 }
Owen Taylor3473f882001-02-23 17:55:21 +00006987}
6988
6989/**
6990 * xmlXPathCeilingFunction:
6991 * @ctxt: the XPath Parser context
6992 * @nargs: the number of arguments
6993 *
6994 * Implement the ceiling() XPath function
6995 * number ceiling(number)
6996 * The ceiling function returns the smallest (closest to negative infinity)
6997 * number that is not less than the argument and that is an integer.
6998 */
6999void
7000xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7001 double f;
7002
7003 CHECK_ARITY(1);
7004 CAST_TO_NUMBER;
7005 CHECK_TYPE(XPATH_NUMBER);
7006
7007#if 0
7008 ctxt->value->floatval = ceil(ctxt->value->floatval);
7009#else
7010 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007011 if (f != ctxt->value->floatval) {
7012 if (ctxt->value->floatval > 0)
7013 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007014 else {
7015 if (ctxt->value->floatval < 0 && f == 0)
7016 ctxt->value->floatval = xmlXPathNZERO;
7017 else
7018 ctxt->value->floatval = f;
7019 }
7020
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007021 }
Owen Taylor3473f882001-02-23 17:55:21 +00007022#endif
7023}
7024
7025/**
7026 * xmlXPathRoundFunction:
7027 * @ctxt: the XPath Parser context
7028 * @nargs: the number of arguments
7029 *
7030 * Implement the round() XPath function
7031 * number round(number)
7032 * The round function returns the number that is closest to the
7033 * argument and that is an integer. If there are two such numbers,
7034 * then the one that is even is returned.
7035 */
7036void
7037xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7038 double f;
7039
7040 CHECK_ARITY(1);
7041 CAST_TO_NUMBER;
7042 CHECK_TYPE(XPATH_NUMBER);
7043
Daniel Veillardcda96922001-08-21 10:56:31 +00007044 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7045 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7046 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007047 (ctxt->value->floatval == 0.0))
7048 return;
7049
Owen Taylor3473f882001-02-23 17:55:21 +00007050 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007051 if (ctxt->value->floatval < 0) {
7052 if (ctxt->value->floatval < f - 0.5)
7053 ctxt->value->floatval = f - 1;
7054 else
7055 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007056 if (ctxt->value->floatval == 0)
7057 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007058 } else {
7059 if (ctxt->value->floatval < f + 0.5)
7060 ctxt->value->floatval = f;
7061 else
7062 ctxt->value->floatval = f + 1;
7063 }
Owen Taylor3473f882001-02-23 17:55:21 +00007064}
7065
7066/************************************************************************
7067 * *
7068 * The Parser *
7069 * *
7070 ************************************************************************/
7071
7072/*
7073 * a couple of forward declarations since we use a recursive call based
7074 * implementation.
7075 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007076static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007077static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007078static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007079static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007080static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7081 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007082
7083/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007084 * xmlXPathCurrentChar:
7085 * @ctxt: the XPath parser context
7086 * @cur: pointer to the beginning of the char
7087 * @len: pointer to the length of the char read
7088 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007089 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007090 * bytes in the input buffer.
7091 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007092 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007093 */
7094
7095static int
7096xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7097 unsigned char c;
7098 unsigned int val;
7099 const xmlChar *cur;
7100
7101 if (ctxt == NULL)
7102 return(0);
7103 cur = ctxt->cur;
7104
7105 /*
7106 * We are supposed to handle UTF8, check it's valid
7107 * From rfc2044: encoding of the Unicode values on UTF-8:
7108 *
7109 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7110 * 0000 0000-0000 007F 0xxxxxxx
7111 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7112 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7113 *
7114 * Check for the 0x110000 limit too
7115 */
7116 c = *cur;
7117 if (c & 0x80) {
7118 if ((cur[1] & 0xc0) != 0x80)
7119 goto encoding_error;
7120 if ((c & 0xe0) == 0xe0) {
7121
7122 if ((cur[2] & 0xc0) != 0x80)
7123 goto encoding_error;
7124 if ((c & 0xf0) == 0xf0) {
7125 if (((c & 0xf8) != 0xf0) ||
7126 ((cur[3] & 0xc0) != 0x80))
7127 goto encoding_error;
7128 /* 4-byte code */
7129 *len = 4;
7130 val = (cur[0] & 0x7) << 18;
7131 val |= (cur[1] & 0x3f) << 12;
7132 val |= (cur[2] & 0x3f) << 6;
7133 val |= cur[3] & 0x3f;
7134 } else {
7135 /* 3-byte code */
7136 *len = 3;
7137 val = (cur[0] & 0xf) << 12;
7138 val |= (cur[1] & 0x3f) << 6;
7139 val |= cur[2] & 0x3f;
7140 }
7141 } else {
7142 /* 2-byte code */
7143 *len = 2;
7144 val = (cur[0] & 0x1f) << 6;
7145 val |= cur[1] & 0x3f;
7146 }
7147 if (!IS_CHAR(val)) {
7148 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7149 }
7150 return(val);
7151 } else {
7152 /* 1-byte code */
7153 *len = 1;
7154 return((int) *cur);
7155 }
7156encoding_error:
7157 /*
7158 * If we detect an UTF8 error that probably mean that the
7159 * input encoding didn't get properly advertized in the
7160 * declaration header. Report the error and switch the encoding
7161 * to ISO-Latin-1 (if you don't like this policy, just declare the
7162 * encoding !)
7163 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007164 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007165 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007166}
7167
7168/**
Owen Taylor3473f882001-02-23 17:55:21 +00007169 * xmlXPathParseNCName:
7170 * @ctxt: the XPath Parser context
7171 *
7172 * parse an XML namespace non qualified name.
7173 *
7174 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7175 *
7176 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7177 * CombiningChar | Extender
7178 *
7179 * Returns the namespace name or NULL
7180 */
7181
7182xmlChar *
7183xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007184 const xmlChar *in;
7185 xmlChar *ret;
7186 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007187
Daniel Veillard2156a562001-04-28 12:24:34 +00007188 /*
7189 * Accelerator for simple ASCII names
7190 */
7191 in = ctxt->cur;
7192 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7193 ((*in >= 0x41) && (*in <= 0x5A)) ||
7194 (*in == '_')) {
7195 in++;
7196 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7197 ((*in >= 0x41) && (*in <= 0x5A)) ||
7198 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007199 (*in == '_') || (*in == '.') ||
7200 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007201 in++;
7202 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7203 (*in == '[') || (*in == ']') || (*in == ':') ||
7204 (*in == '@') || (*in == '*')) {
7205 count = in - ctxt->cur;
7206 if (count == 0)
7207 return(NULL);
7208 ret = xmlStrndup(ctxt->cur, count);
7209 ctxt->cur = in;
7210 return(ret);
7211 }
7212 }
7213 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007214}
7215
Daniel Veillard2156a562001-04-28 12:24:34 +00007216
Owen Taylor3473f882001-02-23 17:55:21 +00007217/**
7218 * xmlXPathParseQName:
7219 * @ctxt: the XPath Parser context
7220 * @prefix: a xmlChar **
7221 *
7222 * parse an XML qualified name
7223 *
7224 * [NS 5] QName ::= (Prefix ':')? LocalPart
7225 *
7226 * [NS 6] Prefix ::= NCName
7227 *
7228 * [NS 7] LocalPart ::= NCName
7229 *
7230 * Returns the function returns the local part, and prefix is updated
7231 * to get the Prefix if any.
7232 */
7233
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007234static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007235xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7236 xmlChar *ret = NULL;
7237
7238 *prefix = NULL;
7239 ret = xmlXPathParseNCName(ctxt);
7240 if (CUR == ':') {
7241 *prefix = ret;
7242 NEXT;
7243 ret = xmlXPathParseNCName(ctxt);
7244 }
7245 return(ret);
7246}
7247
7248/**
7249 * xmlXPathParseName:
7250 * @ctxt: the XPath Parser context
7251 *
7252 * parse an XML name
7253 *
7254 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7255 * CombiningChar | Extender
7256 *
7257 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7258 *
7259 * Returns the namespace name or NULL
7260 */
7261
7262xmlChar *
7263xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007264 const xmlChar *in;
7265 xmlChar *ret;
7266 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007267
Daniel Veillard61d80a22001-04-27 17:13:01 +00007268 /*
7269 * Accelerator for simple ASCII names
7270 */
7271 in = ctxt->cur;
7272 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7273 ((*in >= 0x41) && (*in <= 0x5A)) ||
7274 (*in == '_') || (*in == ':')) {
7275 in++;
7276 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7277 ((*in >= 0x41) && (*in <= 0x5A)) ||
7278 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007279 (*in == '_') || (*in == '-') ||
7280 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007281 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007282 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007283 count = in - ctxt->cur;
7284 ret = xmlStrndup(ctxt->cur, count);
7285 ctxt->cur = in;
7286 return(ret);
7287 }
7288 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007289 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007290}
7291
Daniel Veillard61d80a22001-04-27 17:13:01 +00007292static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007293xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007294 xmlChar buf[XML_MAX_NAMELEN + 5];
7295 int len = 0, l;
7296 int c;
7297
7298 /*
7299 * Handler for more complex cases
7300 */
7301 c = CUR_CHAR(l);
7302 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007303 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7304 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007305 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007306 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007307 return(NULL);
7308 }
7309
7310 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7311 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7312 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007313 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007314 (IS_COMBINING(c)) ||
7315 (IS_EXTENDER(c)))) {
7316 COPY_BUF(l,buf,len,c);
7317 NEXTL(l);
7318 c = CUR_CHAR(l);
7319 if (len >= XML_MAX_NAMELEN) {
7320 /*
7321 * Okay someone managed to make a huge name, so he's ready to pay
7322 * for the processing speed.
7323 */
7324 xmlChar *buffer;
7325 int max = len * 2;
7326
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007327 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007328 if (buffer == NULL) {
7329 XP_ERROR0(XPATH_MEMORY_ERROR);
7330 }
7331 memcpy(buffer, buf, len);
7332 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7333 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007334 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007335 (IS_COMBINING(c)) ||
7336 (IS_EXTENDER(c))) {
7337 if (len + 10 > max) {
7338 max *= 2;
7339 buffer = (xmlChar *) xmlRealloc(buffer,
7340 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007341 if (buffer == NULL) {
7342 XP_ERROR0(XPATH_MEMORY_ERROR);
7343 }
7344 }
7345 COPY_BUF(l,buffer,len,c);
7346 NEXTL(l);
7347 c = CUR_CHAR(l);
7348 }
7349 buffer[len] = 0;
7350 return(buffer);
7351 }
7352 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007353 if (len == 0)
7354 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007355 return(xmlStrndup(buf, len));
7356}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007357
7358#define MAX_FRAC 20
7359
7360static double my_pow10[MAX_FRAC] = {
7361 1.0, 10.0, 100.0, 1000.0, 10000.0,
7362 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7363 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7364 100000000000000.0,
7365 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7366 1000000000000000000.0, 10000000000000000000.0
7367};
7368
Owen Taylor3473f882001-02-23 17:55:21 +00007369/**
7370 * xmlXPathStringEvalNumber:
7371 * @str: A string to scan
7372 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007373 * [30a] Float ::= Number ('e' Digits?)?
7374 *
Owen Taylor3473f882001-02-23 17:55:21 +00007375 * [30] Number ::= Digits ('.' Digits?)?
7376 * | '.' Digits
7377 * [31] Digits ::= [0-9]+
7378 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007379 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007380 * In complement of the Number expression, this function also handles
7381 * negative values : '-' Number.
7382 *
7383 * Returns the double value.
7384 */
7385double
7386xmlXPathStringEvalNumber(const xmlChar *str) {
7387 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007388 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007389 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007390 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007391 int exponent = 0;
7392 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007393#ifdef __GNUC__
7394 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007395 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007396#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007397 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007398 while (IS_BLANK(*cur)) cur++;
7399 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7400 return(xmlXPathNAN);
7401 }
7402 if (*cur == '-') {
7403 isneg = 1;
7404 cur++;
7405 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007406
7407#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007408 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007409 * tmp/temp is a workaround against a gcc compiler bug
7410 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007411 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007412 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007413 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007414 ret = ret * 10;
7415 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007416 ok = 1;
7417 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007418 temp = (double) tmp;
7419 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007420 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007421#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007422 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007423 while ((*cur >= '0') && (*cur <= '9')) {
7424 ret = ret * 10 + (*cur - '0');
7425 ok = 1;
7426 cur++;
7427 }
7428#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007429
Owen Taylor3473f882001-02-23 17:55:21 +00007430 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007431 int v, frac = 0;
7432 double fraction = 0;
7433
Owen Taylor3473f882001-02-23 17:55:21 +00007434 cur++;
7435 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7436 return(xmlXPathNAN);
7437 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007438 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7439 v = (*cur - '0');
7440 fraction = fraction * 10 + v;
7441 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007442 cur++;
7443 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007444 fraction /= my_pow10[frac];
7445 ret = ret + fraction;
7446 while ((*cur >= '0') && (*cur <= '9'))
7447 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007448 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007449 if ((*cur == 'e') || (*cur == 'E')) {
7450 cur++;
7451 if (*cur == '-') {
7452 is_exponent_negative = 1;
7453 cur++;
7454 }
7455 while ((*cur >= '0') && (*cur <= '9')) {
7456 exponent = exponent * 10 + (*cur - '0');
7457 cur++;
7458 }
7459 }
Owen Taylor3473f882001-02-23 17:55:21 +00007460 while (IS_BLANK(*cur)) cur++;
7461 if (*cur != 0) return(xmlXPathNAN);
7462 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007463 if (is_exponent_negative) exponent = -exponent;
7464 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007465 return(ret);
7466}
7467
7468/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007469 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007470 * @ctxt: the XPath Parser context
7471 *
7472 * [30] Number ::= Digits ('.' Digits?)?
7473 * | '.' Digits
7474 * [31] Digits ::= [0-9]+
7475 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007476 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007477 *
7478 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007479static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007480xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7481{
Owen Taylor3473f882001-02-23 17:55:21 +00007482 double ret = 0.0;
7483 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007484 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007485 int exponent = 0;
7486 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007487#ifdef __GNUC__
7488 unsigned long tmp = 0;
7489 double temp;
7490#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007491
7492 CHECK_ERROR;
7493 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7494 XP_ERROR(XPATH_NUMBER_ERROR);
7495 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007496#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007497 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007498 * tmp/temp is a workaround against a gcc compiler bug
7499 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007500 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007501 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007502 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007503 ret = ret * 10;
7504 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007505 ok = 1;
7506 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007507 temp = (double) tmp;
7508 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007509 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007510#else
7511 ret = 0;
7512 while ((CUR >= '0') && (CUR <= '9')) {
7513 ret = ret * 10 + (CUR - '0');
7514 ok = 1;
7515 NEXT;
7516 }
7517#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007518 if (CUR == '.') {
7519 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007520 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7521 XP_ERROR(XPATH_NUMBER_ERROR);
7522 }
7523 while ((CUR >= '0') && (CUR <= '9')) {
7524 mult /= 10;
7525 ret = ret + (CUR - '0') * mult;
7526 NEXT;
7527 }
Owen Taylor3473f882001-02-23 17:55:21 +00007528 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007529 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007530 NEXT;
7531 if (CUR == '-') {
7532 is_exponent_negative = 1;
7533 NEXT;
7534 }
7535 while ((CUR >= '0') && (CUR <= '9')) {
7536 exponent = exponent * 10 + (CUR - '0');
7537 NEXT;
7538 }
7539 if (is_exponent_negative)
7540 exponent = -exponent;
7541 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007542 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007543 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007544 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007545}
7546
7547/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007548 * xmlXPathParseLiteral:
7549 * @ctxt: the XPath Parser context
7550 *
7551 * Parse a Literal
7552 *
7553 * [29] Literal ::= '"' [^"]* '"'
7554 * | "'" [^']* "'"
7555 *
7556 * Returns the value found or NULL in case of error
7557 */
7558static xmlChar *
7559xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7560 const xmlChar *q;
7561 xmlChar *ret = NULL;
7562
7563 if (CUR == '"') {
7564 NEXT;
7565 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007566 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007567 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007568 if (!IS_CHAR((unsigned int) CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007569 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7570 } else {
7571 ret = xmlStrndup(q, CUR_PTR - q);
7572 NEXT;
7573 }
7574 } else if (CUR == '\'') {
7575 NEXT;
7576 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007577 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007578 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007579 if (!IS_CHAR((unsigned int) CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007580 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7581 } else {
7582 ret = xmlStrndup(q, CUR_PTR - q);
7583 NEXT;
7584 }
7585 } else {
7586 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7587 }
7588 return(ret);
7589}
7590
7591/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007592 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007593 * @ctxt: the XPath Parser context
7594 *
7595 * Parse a Literal and push it on the stack.
7596 *
7597 * [29] Literal ::= '"' [^"]* '"'
7598 * | "'" [^']* "'"
7599 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007600 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007601 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007602static void
7603xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007604 const xmlChar *q;
7605 xmlChar *ret = NULL;
7606
7607 if (CUR == '"') {
7608 NEXT;
7609 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007610 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007611 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007612 if (!IS_CHAR((unsigned int) CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007613 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7614 } else {
7615 ret = xmlStrndup(q, CUR_PTR - q);
7616 NEXT;
7617 }
7618 } else if (CUR == '\'') {
7619 NEXT;
7620 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007621 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007622 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007623 if (!IS_CHAR((unsigned int) CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007624 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7625 } else {
7626 ret = xmlStrndup(q, CUR_PTR - q);
7627 NEXT;
7628 }
7629 } else {
7630 XP_ERROR(XPATH_START_LITERAL_ERROR);
7631 }
7632 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007633 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7634 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007635 xmlFree(ret);
7636}
7637
7638/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007639 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007640 * @ctxt: the XPath Parser context
7641 *
7642 * Parse a VariableReference, evaluate it and push it on the stack.
7643 *
7644 * The variable bindings consist of a mapping from variable names
7645 * to variable values. The value of a variable is an object, which
7646 * of any of the types that are possible for the value of an expression,
7647 * and may also be of additional types not specified here.
7648 *
7649 * Early evaluation is possible since:
7650 * The variable bindings [...] used to evaluate a subexpression are
7651 * always the same as those used to evaluate the containing expression.
7652 *
7653 * [36] VariableReference ::= '$' QName
7654 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007655static void
7656xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007657 xmlChar *name;
7658 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007659
7660 SKIP_BLANKS;
7661 if (CUR != '$') {
7662 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7663 }
7664 NEXT;
7665 name = xmlXPathParseQName(ctxt, &prefix);
7666 if (name == NULL) {
7667 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7668 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007669 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007670 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7671 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007672 SKIP_BLANKS;
7673}
7674
7675/**
7676 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007677 * @name: a name string
7678 *
7679 * Is the name given a NodeType one.
7680 *
7681 * [38] NodeType ::= 'comment'
7682 * | 'text'
7683 * | 'processing-instruction'
7684 * | 'node'
7685 *
7686 * Returns 1 if true 0 otherwise
7687 */
7688int
7689xmlXPathIsNodeType(const xmlChar *name) {
7690 if (name == NULL)
7691 return(0);
7692
Daniel Veillard1971ee22002-01-31 20:29:19 +00007693 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007694 return(1);
7695 if (xmlStrEqual(name, BAD_CAST "text"))
7696 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007697 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007698 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007699 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007700 return(1);
7701 return(0);
7702}
7703
7704/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007705 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007706 * @ctxt: the XPath Parser context
7707 *
7708 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7709 * [17] Argument ::= Expr
7710 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007711 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007712 * pushed on the stack
7713 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007714static void
7715xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007716 xmlChar *name;
7717 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007718 int nbargs = 0;
7719
7720 name = xmlXPathParseQName(ctxt, &prefix);
7721 if (name == NULL) {
7722 XP_ERROR(XPATH_EXPR_ERROR);
7723 }
7724 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007725#ifdef DEBUG_EXPR
7726 if (prefix == NULL)
7727 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7728 name);
7729 else
7730 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7731 prefix, name);
7732#endif
7733
Owen Taylor3473f882001-02-23 17:55:21 +00007734 if (CUR != '(') {
7735 XP_ERROR(XPATH_EXPR_ERROR);
7736 }
7737 NEXT;
7738 SKIP_BLANKS;
7739
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007740 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007741 if (CUR != ')') {
7742 while (CUR != 0) {
7743 int op1 = ctxt->comp->last;
7744 ctxt->comp->last = -1;
7745 xmlXPathCompileExpr(ctxt);
7746 CHECK_ERROR;
7747 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7748 nbargs++;
7749 if (CUR == ')') break;
7750 if (CUR != ',') {
7751 XP_ERROR(XPATH_EXPR_ERROR);
7752 }
7753 NEXT;
7754 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007755 }
Owen Taylor3473f882001-02-23 17:55:21 +00007756 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007757 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7758 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007759 NEXT;
7760 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007761}
7762
7763/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007764 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007765 * @ctxt: the XPath Parser context
7766 *
7767 * [15] PrimaryExpr ::= VariableReference
7768 * | '(' Expr ')'
7769 * | Literal
7770 * | Number
7771 * | FunctionCall
7772 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007773 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007774 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007775static void
7776xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007777 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007778 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007779 else if (CUR == '(') {
7780 NEXT;
7781 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007782 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007783 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007784 if (CUR != ')') {
7785 XP_ERROR(XPATH_EXPR_ERROR);
7786 }
7787 NEXT;
7788 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007789 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007790 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007791 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007792 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007793 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007794 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007795 }
7796 SKIP_BLANKS;
7797}
7798
7799/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007800 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007801 * @ctxt: the XPath Parser context
7802 *
7803 * [20] FilterExpr ::= PrimaryExpr
7804 * | FilterExpr Predicate
7805 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007806 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007807 * Square brackets are used to filter expressions in the same way that
7808 * they are used in location paths. It is an error if the expression to
7809 * be filtered does not evaluate to a node-set. The context node list
7810 * used for evaluating the expression in square brackets is the node-set
7811 * to be filtered listed in document order.
7812 */
7813
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007814static void
7815xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7816 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007817 CHECK_ERROR;
7818 SKIP_BLANKS;
7819
7820 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007821 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007822 SKIP_BLANKS;
7823 }
7824
7825
7826}
7827
7828/**
7829 * xmlXPathScanName:
7830 * @ctxt: the XPath Parser context
7831 *
7832 * Trickery: parse an XML name but without consuming the input flow
7833 * Needed to avoid insanity in the parser state.
7834 *
7835 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7836 * CombiningChar | Extender
7837 *
7838 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7839 *
7840 * [6] Names ::= Name (S Name)*
7841 *
7842 * Returns the Name parsed or NULL
7843 */
7844
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007845static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007846xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7847 xmlChar buf[XML_MAX_NAMELEN];
7848 int len = 0;
7849
7850 SKIP_BLANKS;
7851 if (!IS_LETTER(CUR) && (CUR != '_') &&
7852 (CUR != ':')) {
7853 return(NULL);
7854 }
7855
7856 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7857 (NXT(len) == '.') || (NXT(len) == '-') ||
7858 (NXT(len) == '_') || (NXT(len) == ':') ||
7859 (IS_COMBINING(NXT(len))) ||
7860 (IS_EXTENDER(NXT(len)))) {
7861 buf[len] = NXT(len);
7862 len++;
7863 if (len >= XML_MAX_NAMELEN) {
7864 xmlGenericError(xmlGenericErrorContext,
7865 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7866 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7867 (NXT(len) == '.') || (NXT(len) == '-') ||
7868 (NXT(len) == '_') || (NXT(len) == ':') ||
7869 (IS_COMBINING(NXT(len))) ||
7870 (IS_EXTENDER(NXT(len))))
7871 len++;
7872 break;
7873 }
7874 }
7875 return(xmlStrndup(buf, len));
7876}
7877
7878/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007879 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007880 * @ctxt: the XPath Parser context
7881 *
7882 * [19] PathExpr ::= LocationPath
7883 * | FilterExpr
7884 * | FilterExpr '/' RelativeLocationPath
7885 * | FilterExpr '//' RelativeLocationPath
7886 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007887 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007888 * The / operator and // operators combine an arbitrary expression
7889 * and a relative location path. It is an error if the expression
7890 * does not evaluate to a node-set.
7891 * The / operator does composition in the same way as when / is
7892 * used in a location path. As in location paths, // is short for
7893 * /descendant-or-self::node()/.
7894 */
7895
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007896static void
7897xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007898 int lc = 1; /* Should we branch to LocationPath ? */
7899 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7900
7901 SKIP_BLANKS;
7902 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007903 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007904 lc = 0;
7905 } else if (CUR == '*') {
7906 /* relative or absolute location path */
7907 lc = 1;
7908 } else if (CUR == '/') {
7909 /* relative or absolute location path */
7910 lc = 1;
7911 } else if (CUR == '@') {
7912 /* relative abbreviated attribute location path */
7913 lc = 1;
7914 } else if (CUR == '.') {
7915 /* relative abbreviated attribute location path */
7916 lc = 1;
7917 } else {
7918 /*
7919 * Problem is finding if we have a name here whether it's:
7920 * - a nodetype
7921 * - a function call in which case it's followed by '('
7922 * - an axis in which case it's followed by ':'
7923 * - a element name
7924 * We do an a priori analysis here rather than having to
7925 * maintain parsed token content through the recursive function
7926 * calls. This looks uglier but makes the code quite easier to
7927 * read/write/debug.
7928 */
7929 SKIP_BLANKS;
7930 name = xmlXPathScanName(ctxt);
7931 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7932#ifdef DEBUG_STEP
7933 xmlGenericError(xmlGenericErrorContext,
7934 "PathExpr: Axis\n");
7935#endif
7936 lc = 1;
7937 xmlFree(name);
7938 } else if (name != NULL) {
7939 int len =xmlStrlen(name);
7940 int blank = 0;
7941
7942
7943 while (NXT(len) != 0) {
7944 if (NXT(len) == '/') {
7945 /* element name */
7946#ifdef DEBUG_STEP
7947 xmlGenericError(xmlGenericErrorContext,
7948 "PathExpr: AbbrRelLocation\n");
7949#endif
7950 lc = 1;
7951 break;
7952 } else if (IS_BLANK(NXT(len))) {
7953 /* skip to next */
7954 blank = 1;
7955 } else if (NXT(len) == ':') {
7956#ifdef DEBUG_STEP
7957 xmlGenericError(xmlGenericErrorContext,
7958 "PathExpr: AbbrRelLocation\n");
7959#endif
7960 lc = 1;
7961 break;
7962 } else if ((NXT(len) == '(')) {
7963 /* Note Type or Function */
7964 if (xmlXPathIsNodeType(name)) {
7965#ifdef DEBUG_STEP
7966 xmlGenericError(xmlGenericErrorContext,
7967 "PathExpr: Type search\n");
7968#endif
7969 lc = 1;
7970 } else {
7971#ifdef DEBUG_STEP
7972 xmlGenericError(xmlGenericErrorContext,
7973 "PathExpr: function call\n");
7974#endif
7975 lc = 0;
7976 }
7977 break;
7978 } else if ((NXT(len) == '[')) {
7979 /* element name */
7980#ifdef DEBUG_STEP
7981 xmlGenericError(xmlGenericErrorContext,
7982 "PathExpr: AbbrRelLocation\n");
7983#endif
7984 lc = 1;
7985 break;
7986 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7987 (NXT(len) == '=')) {
7988 lc = 1;
7989 break;
7990 } else {
7991 lc = 1;
7992 break;
7993 }
7994 len++;
7995 }
7996 if (NXT(len) == 0) {
7997#ifdef DEBUG_STEP
7998 xmlGenericError(xmlGenericErrorContext,
7999 "PathExpr: AbbrRelLocation\n");
8000#endif
8001 /* element name */
8002 lc = 1;
8003 }
8004 xmlFree(name);
8005 } else {
8006 /* make sure all cases are covered explicitely */
8007 XP_ERROR(XPATH_EXPR_ERROR);
8008 }
8009 }
8010
8011 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008012 if (CUR == '/') {
8013 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8014 } else {
8015 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008016 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008017 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008018 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008019 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008020 CHECK_ERROR;
8021 if ((CUR == '/') && (NXT(1) == '/')) {
8022 SKIP(2);
8023 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008024
8025 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8026 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8027 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8028
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008029 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008030 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008031 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008032 }
8033 }
8034 SKIP_BLANKS;
8035}
8036
8037/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008038 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008039 * @ctxt: the XPath Parser context
8040 *
8041 * [18] UnionExpr ::= PathExpr
8042 * | UnionExpr '|' PathExpr
8043 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008044 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008045 */
8046
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008047static void
8048xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8049 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008050 CHECK_ERROR;
8051 SKIP_BLANKS;
8052 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008053 int op1 = ctxt->comp->last;
8054 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008055
8056 NEXT;
8057 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008058 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008059
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008060 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8061
Owen Taylor3473f882001-02-23 17:55:21 +00008062 SKIP_BLANKS;
8063 }
Owen Taylor3473f882001-02-23 17:55:21 +00008064}
8065
8066/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008067 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008068 * @ctxt: the XPath Parser context
8069 *
8070 * [27] UnaryExpr ::= UnionExpr
8071 * | '-' UnaryExpr
8072 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008073 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008074 */
8075
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008076static void
8077xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008078 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008079 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008080
8081 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008082 while (CUR == '-') {
8083 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008084 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008085 NEXT;
8086 SKIP_BLANKS;
8087 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008088
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008089 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008090 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008091 if (found) {
8092 if (minus)
8093 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8094 else
8095 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008096 }
8097}
8098
8099/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008100 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008101 * @ctxt: the XPath Parser context
8102 *
8103 * [26] MultiplicativeExpr ::= UnaryExpr
8104 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8105 * | MultiplicativeExpr 'div' UnaryExpr
8106 * | MultiplicativeExpr 'mod' UnaryExpr
8107 * [34] MultiplyOperator ::= '*'
8108 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008109 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008110 */
8111
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008112static void
8113xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8114 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008115 CHECK_ERROR;
8116 SKIP_BLANKS;
8117 while ((CUR == '*') ||
8118 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8119 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8120 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008121 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008122
8123 if (CUR == '*') {
8124 op = 0;
8125 NEXT;
8126 } else if (CUR == 'd') {
8127 op = 1;
8128 SKIP(3);
8129 } else if (CUR == 'm') {
8130 op = 2;
8131 SKIP(3);
8132 }
8133 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008134 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008135 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008136 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008137 SKIP_BLANKS;
8138 }
8139}
8140
8141/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008142 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008143 * @ctxt: the XPath Parser context
8144 *
8145 * [25] AdditiveExpr ::= MultiplicativeExpr
8146 * | AdditiveExpr '+' MultiplicativeExpr
8147 * | AdditiveExpr '-' MultiplicativeExpr
8148 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008149 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008150 */
8151
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008152static void
8153xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008154
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008155 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008156 CHECK_ERROR;
8157 SKIP_BLANKS;
8158 while ((CUR == '+') || (CUR == '-')) {
8159 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008160 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008161
8162 if (CUR == '+') plus = 1;
8163 else plus = 0;
8164 NEXT;
8165 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008166 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008167 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008168 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008169 SKIP_BLANKS;
8170 }
8171}
8172
8173/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008174 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008175 * @ctxt: the XPath Parser context
8176 *
8177 * [24] RelationalExpr ::= AdditiveExpr
8178 * | RelationalExpr '<' AdditiveExpr
8179 * | RelationalExpr '>' AdditiveExpr
8180 * | RelationalExpr '<=' AdditiveExpr
8181 * | RelationalExpr '>=' AdditiveExpr
8182 *
8183 * A <= B > C is allowed ? Answer from James, yes with
8184 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8185 * which is basically what got implemented.
8186 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008187 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008188 * on the stack
8189 */
8190
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008191static void
8192xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8193 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008194 CHECK_ERROR;
8195 SKIP_BLANKS;
8196 while ((CUR == '<') ||
8197 (CUR == '>') ||
8198 ((CUR == '<') && (NXT(1) == '=')) ||
8199 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008200 int inf, strict;
8201 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008202
8203 if (CUR == '<') inf = 1;
8204 else inf = 0;
8205 if (NXT(1) == '=') strict = 0;
8206 else strict = 1;
8207 NEXT;
8208 if (!strict) NEXT;
8209 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008210 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008211 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008212 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008213 SKIP_BLANKS;
8214 }
8215}
8216
8217/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008218 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008219 * @ctxt: the XPath Parser context
8220 *
8221 * [23] EqualityExpr ::= RelationalExpr
8222 * | EqualityExpr '=' RelationalExpr
8223 * | EqualityExpr '!=' RelationalExpr
8224 *
8225 * A != B != C is allowed ? Answer from James, yes with
8226 * (RelationalExpr = RelationalExpr) = RelationalExpr
8227 * (RelationalExpr != RelationalExpr) != RelationalExpr
8228 * which is basically what got implemented.
8229 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008230 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008231 *
8232 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008233static void
8234xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8235 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008236 CHECK_ERROR;
8237 SKIP_BLANKS;
8238 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008239 int eq;
8240 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008241
8242 if (CUR == '=') eq = 1;
8243 else eq = 0;
8244 NEXT;
8245 if (!eq) NEXT;
8246 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008247 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008248 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008249 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008250 SKIP_BLANKS;
8251 }
8252}
8253
8254/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008255 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008256 * @ctxt: the XPath Parser context
8257 *
8258 * [22] AndExpr ::= EqualityExpr
8259 * | AndExpr 'and' EqualityExpr
8260 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008261 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008262 *
8263 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008264static void
8265xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8266 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008267 CHECK_ERROR;
8268 SKIP_BLANKS;
8269 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008270 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008271 SKIP(3);
8272 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008273 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008274 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008275 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008276 SKIP_BLANKS;
8277 }
8278}
8279
8280/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008281 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008282 * @ctxt: the XPath Parser context
8283 *
8284 * [14] Expr ::= OrExpr
8285 * [21] OrExpr ::= AndExpr
8286 * | OrExpr 'or' AndExpr
8287 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008288 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008289 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008290static void
8291xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8292 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008293 CHECK_ERROR;
8294 SKIP_BLANKS;
8295 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008296 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008297 SKIP(2);
8298 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008299 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008300 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008301 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8302 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008303 SKIP_BLANKS;
8304 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008305 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8306 /* more ops could be optimized too */
8307 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8308 }
Owen Taylor3473f882001-02-23 17:55:21 +00008309}
8310
8311/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008312 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008313 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008314 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008315 *
8316 * [8] Predicate ::= '[' PredicateExpr ']'
8317 * [9] PredicateExpr ::= Expr
8318 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008319 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008320 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008321static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008322xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008323 int op1 = ctxt->comp->last;
8324
8325 SKIP_BLANKS;
8326 if (CUR != '[') {
8327 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8328 }
8329 NEXT;
8330 SKIP_BLANKS;
8331
8332 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008333 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008334 CHECK_ERROR;
8335
8336 if (CUR != ']') {
8337 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8338 }
8339
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008340 if (filter)
8341 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8342 else
8343 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008344
8345 NEXT;
8346 SKIP_BLANKS;
8347}
8348
8349/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008350 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008351 * @ctxt: the XPath Parser context
8352 * @test: pointer to a xmlXPathTestVal
8353 * @type: pointer to a xmlXPathTypeVal
8354 * @prefix: placeholder for a possible name prefix
8355 *
8356 * [7] NodeTest ::= NameTest
8357 * | NodeType '(' ')'
8358 * | 'processing-instruction' '(' Literal ')'
8359 *
8360 * [37] NameTest ::= '*'
8361 * | NCName ':' '*'
8362 * | QName
8363 * [38] NodeType ::= 'comment'
8364 * | 'text'
8365 * | 'processing-instruction'
8366 * | 'node'
8367 *
8368 * Returns the name found and update @test, @type and @prefix appropriately
8369 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008370static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008371xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8372 xmlXPathTypeVal *type, const xmlChar **prefix,
8373 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008374 int blanks;
8375
8376 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8377 STRANGE;
8378 return(NULL);
8379 }
8380 *type = 0;
8381 *test = 0;
8382 *prefix = NULL;
8383 SKIP_BLANKS;
8384
8385 if ((name == NULL) && (CUR == '*')) {
8386 /*
8387 * All elements
8388 */
8389 NEXT;
8390 *test = NODE_TEST_ALL;
8391 return(NULL);
8392 }
8393
8394 if (name == NULL)
8395 name = xmlXPathParseNCName(ctxt);
8396 if (name == NULL) {
8397 XP_ERROR0(XPATH_EXPR_ERROR);
8398 }
8399
8400 blanks = IS_BLANK(CUR);
8401 SKIP_BLANKS;
8402 if (CUR == '(') {
8403 NEXT;
8404 /*
8405 * NodeType or PI search
8406 */
8407 if (xmlStrEqual(name, BAD_CAST "comment"))
8408 *type = NODE_TYPE_COMMENT;
8409 else if (xmlStrEqual(name, BAD_CAST "node"))
8410 *type = NODE_TYPE_NODE;
8411 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8412 *type = NODE_TYPE_PI;
8413 else if (xmlStrEqual(name, BAD_CAST "text"))
8414 *type = NODE_TYPE_TEXT;
8415 else {
8416 if (name != NULL)
8417 xmlFree(name);
8418 XP_ERROR0(XPATH_EXPR_ERROR);
8419 }
8420
8421 *test = NODE_TEST_TYPE;
8422
8423 SKIP_BLANKS;
8424 if (*type == NODE_TYPE_PI) {
8425 /*
8426 * Specific case: search a PI by name.
8427 */
Owen Taylor3473f882001-02-23 17:55:21 +00008428 if (name != NULL)
8429 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008430 name = NULL;
8431 if (CUR != ')') {
8432 name = xmlXPathParseLiteral(ctxt);
8433 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008434 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008435 SKIP_BLANKS;
8436 }
Owen Taylor3473f882001-02-23 17:55:21 +00008437 }
8438 if (CUR != ')') {
8439 if (name != NULL)
8440 xmlFree(name);
8441 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8442 }
8443 NEXT;
8444 return(name);
8445 }
8446 *test = NODE_TEST_NAME;
8447 if ((!blanks) && (CUR == ':')) {
8448 NEXT;
8449
8450 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008451 * Since currently the parser context don't have a
8452 * namespace list associated:
8453 * The namespace name for this prefix can be computed
8454 * only at evaluation time. The compilation is done
8455 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008456 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008457#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008458 *prefix = xmlXPathNsLookup(ctxt->context, name);
8459 if (name != NULL)
8460 xmlFree(name);
8461 if (*prefix == NULL) {
8462 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8463 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008464#else
8465 *prefix = name;
8466#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008467
8468 if (CUR == '*') {
8469 /*
8470 * All elements
8471 */
8472 NEXT;
8473 *test = NODE_TEST_ALL;
8474 return(NULL);
8475 }
8476
8477 name = xmlXPathParseNCName(ctxt);
8478 if (name == NULL) {
8479 XP_ERROR0(XPATH_EXPR_ERROR);
8480 }
8481 }
8482 return(name);
8483}
8484
8485/**
8486 * xmlXPathIsAxisName:
8487 * @name: a preparsed name token
8488 *
8489 * [6] AxisName ::= 'ancestor'
8490 * | 'ancestor-or-self'
8491 * | 'attribute'
8492 * | 'child'
8493 * | 'descendant'
8494 * | 'descendant-or-self'
8495 * | 'following'
8496 * | 'following-sibling'
8497 * | 'namespace'
8498 * | 'parent'
8499 * | 'preceding'
8500 * | 'preceding-sibling'
8501 * | 'self'
8502 *
8503 * Returns the axis or 0
8504 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008505static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008506xmlXPathIsAxisName(const xmlChar *name) {
8507 xmlXPathAxisVal ret = 0;
8508 switch (name[0]) {
8509 case 'a':
8510 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8511 ret = AXIS_ANCESTOR;
8512 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8513 ret = AXIS_ANCESTOR_OR_SELF;
8514 if (xmlStrEqual(name, BAD_CAST "attribute"))
8515 ret = AXIS_ATTRIBUTE;
8516 break;
8517 case 'c':
8518 if (xmlStrEqual(name, BAD_CAST "child"))
8519 ret = AXIS_CHILD;
8520 break;
8521 case 'd':
8522 if (xmlStrEqual(name, BAD_CAST "descendant"))
8523 ret = AXIS_DESCENDANT;
8524 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8525 ret = AXIS_DESCENDANT_OR_SELF;
8526 break;
8527 case 'f':
8528 if (xmlStrEqual(name, BAD_CAST "following"))
8529 ret = AXIS_FOLLOWING;
8530 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8531 ret = AXIS_FOLLOWING_SIBLING;
8532 break;
8533 case 'n':
8534 if (xmlStrEqual(name, BAD_CAST "namespace"))
8535 ret = AXIS_NAMESPACE;
8536 break;
8537 case 'p':
8538 if (xmlStrEqual(name, BAD_CAST "parent"))
8539 ret = AXIS_PARENT;
8540 if (xmlStrEqual(name, BAD_CAST "preceding"))
8541 ret = AXIS_PRECEDING;
8542 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8543 ret = AXIS_PRECEDING_SIBLING;
8544 break;
8545 case 's':
8546 if (xmlStrEqual(name, BAD_CAST "self"))
8547 ret = AXIS_SELF;
8548 break;
8549 }
8550 return(ret);
8551}
8552
8553/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008554 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008555 * @ctxt: the XPath Parser context
8556 *
8557 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8558 * | AbbreviatedStep
8559 *
8560 * [12] AbbreviatedStep ::= '.' | '..'
8561 *
8562 * [5] AxisSpecifier ::= AxisName '::'
8563 * | AbbreviatedAxisSpecifier
8564 *
8565 * [13] AbbreviatedAxisSpecifier ::= '@'?
8566 *
8567 * Modified for XPtr range support as:
8568 *
8569 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8570 * | AbbreviatedStep
8571 * | 'range-to' '(' Expr ')' Predicate*
8572 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008573 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008574 * A location step of . is short for self::node(). This is
8575 * particularly useful in conjunction with //. For example, the
8576 * location path .//para is short for
8577 * self::node()/descendant-or-self::node()/child::para
8578 * and so will select all para descendant elements of the context
8579 * node.
8580 * Similarly, a location step of .. is short for parent::node().
8581 * For example, ../title is short for parent::node()/child::title
8582 * and so will select the title children of the parent of the context
8583 * node.
8584 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008585static void
8586xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008587#ifdef LIBXML_XPTR_ENABLED
8588 int rangeto = 0;
8589 int op2 = -1;
8590#endif
8591
Owen Taylor3473f882001-02-23 17:55:21 +00008592 SKIP_BLANKS;
8593 if ((CUR == '.') && (NXT(1) == '.')) {
8594 SKIP(2);
8595 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008596 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8597 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008598 } else if (CUR == '.') {
8599 NEXT;
8600 SKIP_BLANKS;
8601 } else {
8602 xmlChar *name = NULL;
8603 const xmlChar *prefix = NULL;
8604 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008605 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008606 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008607 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008608
8609 /*
8610 * The modification needed for XPointer change to the production
8611 */
8612#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008613 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008614 name = xmlXPathParseNCName(ctxt);
8615 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008616 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008617 xmlFree(name);
8618 SKIP_BLANKS;
8619 if (CUR != '(') {
8620 XP_ERROR(XPATH_EXPR_ERROR);
8621 }
8622 NEXT;
8623 SKIP_BLANKS;
8624
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008625 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008626 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008627 CHECK_ERROR;
8628
8629 SKIP_BLANKS;
8630 if (CUR != ')') {
8631 XP_ERROR(XPATH_EXPR_ERROR);
8632 }
8633 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008634 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008635 goto eval_predicates;
8636 }
8637 }
8638#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008639 if (CUR == '*') {
8640 axis = AXIS_CHILD;
8641 } else {
8642 if (name == NULL)
8643 name = xmlXPathParseNCName(ctxt);
8644 if (name != NULL) {
8645 axis = xmlXPathIsAxisName(name);
8646 if (axis != 0) {
8647 SKIP_BLANKS;
8648 if ((CUR == ':') && (NXT(1) == ':')) {
8649 SKIP(2);
8650 xmlFree(name);
8651 name = NULL;
8652 } else {
8653 /* an element name can conflict with an axis one :-\ */
8654 axis = AXIS_CHILD;
8655 }
Owen Taylor3473f882001-02-23 17:55:21 +00008656 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008657 axis = AXIS_CHILD;
8658 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008659 } else if (CUR == '@') {
8660 NEXT;
8661 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008662 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008663 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008664 }
Owen Taylor3473f882001-02-23 17:55:21 +00008665 }
8666
8667 CHECK_ERROR;
8668
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008669 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008670 if (test == 0)
8671 return;
8672
8673#ifdef DEBUG_STEP
8674 xmlGenericError(xmlGenericErrorContext,
8675 "Basis : computing new set\n");
8676#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008677
Owen Taylor3473f882001-02-23 17:55:21 +00008678#ifdef DEBUG_STEP
8679 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008680 if (ctxt->value == NULL)
8681 xmlGenericError(xmlGenericErrorContext, "no value\n");
8682 else if (ctxt->value->nodesetval == NULL)
8683 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8684 else
8685 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008686#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008687
8688eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008689 op1 = ctxt->comp->last;
8690 ctxt->comp->last = -1;
8691
Owen Taylor3473f882001-02-23 17:55:21 +00008692 SKIP_BLANKS;
8693 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008694 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008695 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008696
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008697#ifdef LIBXML_XPTR_ENABLED
8698 if (rangeto) {
8699 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8700 } else
8701#endif
8702 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8703 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008704
Owen Taylor3473f882001-02-23 17:55:21 +00008705 }
8706#ifdef DEBUG_STEP
8707 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008708 if (ctxt->value == NULL)
8709 xmlGenericError(xmlGenericErrorContext, "no value\n");
8710 else if (ctxt->value->nodesetval == NULL)
8711 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8712 else
8713 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8714 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008715#endif
8716}
8717
8718/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008719 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008720 * @ctxt: the XPath Parser context
8721 *
8722 * [3] RelativeLocationPath ::= Step
8723 * | RelativeLocationPath '/' Step
8724 * | AbbreviatedRelativeLocationPath
8725 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8726 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008727 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008728 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008729static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008730xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008731(xmlXPathParserContextPtr ctxt) {
8732 SKIP_BLANKS;
8733 if ((CUR == '/') && (NXT(1) == '/')) {
8734 SKIP(2);
8735 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008736 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8737 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008738 } else if (CUR == '/') {
8739 NEXT;
8740 SKIP_BLANKS;
8741 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008742 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008743 SKIP_BLANKS;
8744 while (CUR == '/') {
8745 if ((CUR == '/') && (NXT(1) == '/')) {
8746 SKIP(2);
8747 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008748 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008749 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008750 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008751 } else if (CUR == '/') {
8752 NEXT;
8753 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008754 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008755 }
8756 SKIP_BLANKS;
8757 }
8758}
8759
8760/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008761 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008762 * @ctxt: the XPath Parser context
8763 *
8764 * [1] LocationPath ::= RelativeLocationPath
8765 * | AbsoluteLocationPath
8766 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8767 * | AbbreviatedAbsoluteLocationPath
8768 * [10] AbbreviatedAbsoluteLocationPath ::=
8769 * '//' RelativeLocationPath
8770 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008771 * Compile a location path
8772 *
Owen Taylor3473f882001-02-23 17:55:21 +00008773 * // is short for /descendant-or-self::node()/. For example,
8774 * //para is short for /descendant-or-self::node()/child::para and
8775 * so will select any para element in the document (even a para element
8776 * that is a document element will be selected by //para since the
8777 * document element node is a child of the root node); div//para is
8778 * short for div/descendant-or-self::node()/child::para and so will
8779 * select all para descendants of div children.
8780 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008781static void
8782xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008783 SKIP_BLANKS;
8784 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008785 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008786 } else {
8787 while (CUR == '/') {
8788 if ((CUR == '/') && (NXT(1) == '/')) {
8789 SKIP(2);
8790 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008791 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8792 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008793 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008794 } else if (CUR == '/') {
8795 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008796 SKIP_BLANKS;
8797 if ((CUR != 0 ) &&
8798 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8799 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008800 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008801 }
8802 }
8803 }
8804}
8805
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008806/************************************************************************
8807 * *
8808 * XPath precompiled expression evaluation *
8809 * *
8810 ************************************************************************/
8811
Daniel Veillardf06307e2001-07-03 10:35:50 +00008812static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008813xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8814
8815/**
8816 * xmlXPathNodeCollectAndTest:
8817 * @ctxt: the XPath Parser context
8818 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008819 * @first: pointer to the first element in document order
8820 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008821 *
8822 * This is the function implementing a step: based on the current list
8823 * of nodes, it builds up a new list, looking at all nodes under that
8824 * axis and selecting them it also do the predicate filtering
8825 *
8826 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008827 *
8828 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008829 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008830static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008831xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008832 xmlXPathStepOpPtr op,
8833 xmlNodePtr * first, xmlNodePtr * last)
8834{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008835 xmlXPathAxisVal axis = op->value;
8836 xmlXPathTestVal test = op->value2;
8837 xmlXPathTypeVal type = op->value3;
8838 const xmlChar *prefix = op->value4;
8839 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008840 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008841
8842#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008843 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008844#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008845 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008846 xmlNodeSetPtr ret, list;
8847 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008848 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008849 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008850 xmlNodePtr cur = NULL;
8851 xmlXPathObjectPtr obj;
8852 xmlNodeSetPtr nodelist;
8853 xmlNodePtr tmp;
8854
Daniel Veillardf06307e2001-07-03 10:35:50 +00008855 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008856 obj = valuePop(ctxt);
8857 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008858 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008859 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008860 URI = xmlXPathNsLookup(ctxt->context, prefix);
8861 if (URI == NULL)
8862 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008863 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008864#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008865 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008866#endif
8867 switch (axis) {
8868 case AXIS_ANCESTOR:
8869#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008870 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008871#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008872 first = NULL;
8873 next = xmlXPathNextAncestor;
8874 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008875 case AXIS_ANCESTOR_OR_SELF:
8876#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008877 xmlGenericError(xmlGenericErrorContext,
8878 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008879#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008880 first = NULL;
8881 next = xmlXPathNextAncestorOrSelf;
8882 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008883 case AXIS_ATTRIBUTE:
8884#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008885 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008886#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008887 first = NULL;
8888 last = NULL;
8889 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008890 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008891 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008892 case AXIS_CHILD:
8893#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008894 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008895#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008896 last = NULL;
8897 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008898 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008899 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008900 case AXIS_DESCENDANT:
8901#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008903#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008904 last = NULL;
8905 next = xmlXPathNextDescendant;
8906 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008907 case AXIS_DESCENDANT_OR_SELF:
8908#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008909 xmlGenericError(xmlGenericErrorContext,
8910 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008911#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 last = NULL;
8913 next = xmlXPathNextDescendantOrSelf;
8914 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008915 case AXIS_FOLLOWING:
8916#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008918#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008919 last = NULL;
8920 next = xmlXPathNextFollowing;
8921 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008922 case AXIS_FOLLOWING_SIBLING:
8923#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008924 xmlGenericError(xmlGenericErrorContext,
8925 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008926#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008927 last = NULL;
8928 next = xmlXPathNextFollowingSibling;
8929 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008930 case AXIS_NAMESPACE:
8931#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008932 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008933#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008934 first = NULL;
8935 last = NULL;
8936 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008937 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008939 case AXIS_PARENT:
8940#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008941 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008942#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008943 first = NULL;
8944 next = xmlXPathNextParent;
8945 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008946 case AXIS_PRECEDING:
8947#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008948 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008949#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008950 first = NULL;
8951 next = xmlXPathNextPrecedingInternal;
8952 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008953 case AXIS_PRECEDING_SIBLING:
8954#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 xmlGenericError(xmlGenericErrorContext,
8956 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008957#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008958 first = NULL;
8959 next = xmlXPathNextPrecedingSibling;
8960 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008961 case AXIS_SELF:
8962#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008963 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008964#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008965 first = NULL;
8966 last = NULL;
8967 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008968 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970 }
8971 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973
8974 nodelist = obj->nodesetval;
8975 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976 xmlXPathFreeObject(obj);
8977 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8978 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008979 }
8980 addNode = xmlXPathNodeSetAddUnique;
8981 ret = NULL;
8982#ifdef DEBUG_STEP
8983 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008984 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008986 case NODE_TEST_NONE:
8987 xmlGenericError(xmlGenericErrorContext,
8988 " searching for none !!!\n");
8989 break;
8990 case NODE_TEST_TYPE:
8991 xmlGenericError(xmlGenericErrorContext,
8992 " searching for type %d\n", type);
8993 break;
8994 case NODE_TEST_PI:
8995 xmlGenericError(xmlGenericErrorContext,
8996 " searching for PI !!!\n");
8997 break;
8998 case NODE_TEST_ALL:
8999 xmlGenericError(xmlGenericErrorContext,
9000 " searching for *\n");
9001 break;
9002 case NODE_TEST_NS:
9003 xmlGenericError(xmlGenericErrorContext,
9004 " searching for namespace %s\n",
9005 prefix);
9006 break;
9007 case NODE_TEST_NAME:
9008 xmlGenericError(xmlGenericErrorContext,
9009 " searching for name %s\n", name);
9010 if (prefix != NULL)
9011 xmlGenericError(xmlGenericErrorContext,
9012 " with namespace %s\n", prefix);
9013 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009014 }
9015 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9016#endif
9017 /*
9018 * 2.3 Node Tests
9019 * - For the attribute axis, the principal node type is attribute.
9020 * - For the namespace axis, the principal node type is namespace.
9021 * - For other axes, the principal node type is element.
9022 *
9023 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009024 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009025 * select all element children of the context node
9026 */
9027 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009029 ctxt->context->node = nodelist->nodeTab[i];
9030
Daniel Veillardf06307e2001-07-03 10:35:50 +00009031 cur = NULL;
9032 list = xmlXPathNodeSetCreate(NULL);
9033 do {
9034 cur = next(ctxt, cur);
9035 if (cur == NULL)
9036 break;
9037 if ((first != NULL) && (*first == cur))
9038 break;
9039 if (((t % 256) == 0) &&
9040 (first != NULL) && (*first != NULL) &&
9041 (xmlXPathCmpNodes(*first, cur) >= 0))
9042 break;
9043 if ((last != NULL) && (*last == cur))
9044 break;
9045 if (((t % 256) == 0) &&
9046 (last != NULL) && (*last != NULL) &&
9047 (xmlXPathCmpNodes(cur, *last) >= 0))
9048 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009049 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009050#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009051 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9052#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009054 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009055 ctxt->context->node = tmp;
9056 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009057 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009058 if ((cur->type == type) ||
9059 ((type == NODE_TYPE_NODE) &&
9060 ((cur->type == XML_DOCUMENT_NODE) ||
9061 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9062 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009063 (cur->type == XML_NAMESPACE_DECL) ||
9064 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009065 (cur->type == XML_PI_NODE) ||
9066 (cur->type == XML_COMMENT_NODE) ||
9067 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009068 (cur->type == XML_TEXT_NODE))) ||
9069 ((type == NODE_TYPE_TEXT) &&
9070 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009071#ifdef DEBUG_STEP
9072 n++;
9073#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 addNode(list, cur);
9075 }
9076 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009077 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009078 if (cur->type == XML_PI_NODE) {
9079 if ((name != NULL) &&
9080 (!xmlStrEqual(name, cur->name)))
9081 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009082#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009083 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009084#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009085 addNode(list, cur);
9086 }
9087 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009088 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 if (axis == AXIS_ATTRIBUTE) {
9090 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 addNode(list, cur);
9095 }
9096 } else if (axis == AXIS_NAMESPACE) {
9097 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009098#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009100#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009101 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9102 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 }
9104 } else {
9105 if (cur->type == XML_ELEMENT_NODE) {
9106 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009107#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009109#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009110 addNode(list, cur);
9111 } else if ((cur->ns != NULL) &&
9112 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009113#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009115#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009116 addNode(list, cur);
9117 }
9118 }
9119 }
9120 break;
9121 case NODE_TEST_NS:{
9122 TODO;
9123 break;
9124 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009125 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009126 switch (cur->type) {
9127 case XML_ELEMENT_NODE:
9128 if (xmlStrEqual(name, cur->name)) {
9129 if (prefix == NULL) {
9130 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009131#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009133#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 addNode(list, cur);
9135 }
9136 } else {
9137 if ((cur->ns != NULL) &&
9138 (xmlStrEqual(URI,
9139 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009140#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009142#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 addNode(list, cur);
9144 }
9145 }
9146 }
9147 break;
9148 case XML_ATTRIBUTE_NODE:{
9149 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009150
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 if (xmlStrEqual(name, attr->name)) {
9152 if (prefix == NULL) {
9153 if ((attr->ns == NULL) ||
9154 (attr->ns->prefix == NULL)) {
9155#ifdef DEBUG_STEP
9156 n++;
9157#endif
9158 addNode(list,
9159 (xmlNodePtr) attr);
9160 }
9161 } else {
9162 if ((attr->ns != NULL) &&
9163 (xmlStrEqual(URI,
9164 attr->ns->
9165 href))) {
9166#ifdef DEBUG_STEP
9167 n++;
9168#endif
9169 addNode(list,
9170 (xmlNodePtr) attr);
9171 }
9172 }
9173 }
9174 break;
9175 }
9176 case XML_NAMESPACE_DECL:
9177 if (cur->type == XML_NAMESPACE_DECL) {
9178 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009179
Daniel Veillardf06307e2001-07-03 10:35:50 +00009180 if ((ns->prefix != NULL) && (name != NULL)
9181 && (xmlStrEqual(ns->prefix, name))) {
9182#ifdef DEBUG_STEP
9183 n++;
9184#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009185 xmlXPathNodeSetAddNs(list,
9186 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009187 }
9188 }
9189 break;
9190 default:
9191 break;
9192 }
9193 break;
9194 break;
9195 }
9196 } while (cur != NULL);
9197
9198 /*
9199 * If there is some predicate filtering do it now
9200 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009201 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009202 xmlXPathObjectPtr obj2;
9203
9204 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9205 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9206 CHECK_TYPE0(XPATH_NODESET);
9207 obj2 = valuePop(ctxt);
9208 list = obj2->nodesetval;
9209 obj2->nodesetval = NULL;
9210 xmlXPathFreeObject(obj2);
9211 }
9212 if (ret == NULL) {
9213 ret = list;
9214 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009215 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009216 xmlXPathFreeNodeSet(list);
9217 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009218 }
9219 ctxt->context->node = tmp;
9220#ifdef DEBUG_STEP
9221 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009222 "\nExamined %d nodes, found %d nodes at that step\n",
9223 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009224#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009225 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009226 if ((obj->boolval) && (obj->user != NULL)) {
9227 ctxt->value->boolval = 1;
9228 ctxt->value->user = obj->user;
9229 obj->user = NULL;
9230 obj->boolval = 0;
9231 }
9232 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009233 return(t);
9234}
9235
9236/**
9237 * xmlXPathNodeCollectAndTestNth:
9238 * @ctxt: the XPath Parser context
9239 * @op: the XPath precompiled step operation
9240 * @indx: the index to collect
9241 * @first: pointer to the first element in document order
9242 * @last: pointer to the last element in document order
9243 *
9244 * This is the function implementing a step: based on the current list
9245 * of nodes, it builds up a new list, looking at all nodes under that
9246 * axis and selecting them it also do the predicate filtering
9247 *
9248 * Pushes the new NodeSet resulting from the search.
9249 * Returns the number of node traversed
9250 */
9251static int
9252xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9253 xmlXPathStepOpPtr op, int indx,
9254 xmlNodePtr * first, xmlNodePtr * last)
9255{
9256 xmlXPathAxisVal axis = op->value;
9257 xmlXPathTestVal test = op->value2;
9258 xmlXPathTypeVal type = op->value3;
9259 const xmlChar *prefix = op->value4;
9260 const xmlChar *name = op->value5;
9261 const xmlChar *URI = NULL;
9262 int n = 0, t = 0;
9263
9264 int i;
9265 xmlNodeSetPtr list;
9266 xmlXPathTraversalFunction next = NULL;
9267 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9268 xmlNodePtr cur = NULL;
9269 xmlXPathObjectPtr obj;
9270 xmlNodeSetPtr nodelist;
9271 xmlNodePtr tmp;
9272
9273 CHECK_TYPE0(XPATH_NODESET);
9274 obj = valuePop(ctxt);
9275 addNode = xmlXPathNodeSetAdd;
9276 if (prefix != NULL) {
9277 URI = xmlXPathNsLookup(ctxt->context, prefix);
9278 if (URI == NULL)
9279 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9280 }
9281#ifdef DEBUG_STEP_NTH
9282 xmlGenericError(xmlGenericErrorContext, "new step : ");
9283 if (first != NULL) {
9284 if (*first != NULL)
9285 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9286 (*first)->name);
9287 else
9288 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9289 }
9290 if (last != NULL) {
9291 if (*last != NULL)
9292 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9293 (*last)->name);
9294 else
9295 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9296 }
9297#endif
9298 switch (axis) {
9299 case AXIS_ANCESTOR:
9300#ifdef DEBUG_STEP_NTH
9301 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9302#endif
9303 first = NULL;
9304 next = xmlXPathNextAncestor;
9305 break;
9306 case AXIS_ANCESTOR_OR_SELF:
9307#ifdef DEBUG_STEP_NTH
9308 xmlGenericError(xmlGenericErrorContext,
9309 "axis 'ancestors-or-self' ");
9310#endif
9311 first = NULL;
9312 next = xmlXPathNextAncestorOrSelf;
9313 break;
9314 case AXIS_ATTRIBUTE:
9315#ifdef DEBUG_STEP_NTH
9316 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9317#endif
9318 first = NULL;
9319 last = NULL;
9320 next = xmlXPathNextAttribute;
9321 break;
9322 case AXIS_CHILD:
9323#ifdef DEBUG_STEP_NTH
9324 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9325#endif
9326 last = NULL;
9327 next = xmlXPathNextChild;
9328 break;
9329 case AXIS_DESCENDANT:
9330#ifdef DEBUG_STEP_NTH
9331 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9332#endif
9333 last = NULL;
9334 next = xmlXPathNextDescendant;
9335 break;
9336 case AXIS_DESCENDANT_OR_SELF:
9337#ifdef DEBUG_STEP_NTH
9338 xmlGenericError(xmlGenericErrorContext,
9339 "axis 'descendant-or-self' ");
9340#endif
9341 last = NULL;
9342 next = xmlXPathNextDescendantOrSelf;
9343 break;
9344 case AXIS_FOLLOWING:
9345#ifdef DEBUG_STEP_NTH
9346 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9347#endif
9348 last = NULL;
9349 next = xmlXPathNextFollowing;
9350 break;
9351 case AXIS_FOLLOWING_SIBLING:
9352#ifdef DEBUG_STEP_NTH
9353 xmlGenericError(xmlGenericErrorContext,
9354 "axis 'following-siblings' ");
9355#endif
9356 last = NULL;
9357 next = xmlXPathNextFollowingSibling;
9358 break;
9359 case AXIS_NAMESPACE:
9360#ifdef DEBUG_STEP_NTH
9361 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9362#endif
9363 last = NULL;
9364 first = NULL;
9365 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9366 break;
9367 case AXIS_PARENT:
9368#ifdef DEBUG_STEP_NTH
9369 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9370#endif
9371 first = NULL;
9372 next = xmlXPathNextParent;
9373 break;
9374 case AXIS_PRECEDING:
9375#ifdef DEBUG_STEP_NTH
9376 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9377#endif
9378 first = NULL;
9379 next = xmlXPathNextPrecedingInternal;
9380 break;
9381 case AXIS_PRECEDING_SIBLING:
9382#ifdef DEBUG_STEP_NTH
9383 xmlGenericError(xmlGenericErrorContext,
9384 "axis 'preceding-sibling' ");
9385#endif
9386 first = NULL;
9387 next = xmlXPathNextPrecedingSibling;
9388 break;
9389 case AXIS_SELF:
9390#ifdef DEBUG_STEP_NTH
9391 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9392#endif
9393 first = NULL;
9394 last = NULL;
9395 next = xmlXPathNextSelf;
9396 break;
9397 }
9398 if (next == NULL)
9399 return(0);
9400
9401 nodelist = obj->nodesetval;
9402 if (nodelist == NULL) {
9403 xmlXPathFreeObject(obj);
9404 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9405 return(0);
9406 }
9407 addNode = xmlXPathNodeSetAddUnique;
9408#ifdef DEBUG_STEP_NTH
9409 xmlGenericError(xmlGenericErrorContext,
9410 " context contains %d nodes\n", nodelist->nodeNr);
9411 switch (test) {
9412 case NODE_TEST_NONE:
9413 xmlGenericError(xmlGenericErrorContext,
9414 " searching for none !!!\n");
9415 break;
9416 case NODE_TEST_TYPE:
9417 xmlGenericError(xmlGenericErrorContext,
9418 " searching for type %d\n", type);
9419 break;
9420 case NODE_TEST_PI:
9421 xmlGenericError(xmlGenericErrorContext,
9422 " searching for PI !!!\n");
9423 break;
9424 case NODE_TEST_ALL:
9425 xmlGenericError(xmlGenericErrorContext,
9426 " searching for *\n");
9427 break;
9428 case NODE_TEST_NS:
9429 xmlGenericError(xmlGenericErrorContext,
9430 " searching for namespace %s\n",
9431 prefix);
9432 break;
9433 case NODE_TEST_NAME:
9434 xmlGenericError(xmlGenericErrorContext,
9435 " searching for name %s\n", name);
9436 if (prefix != NULL)
9437 xmlGenericError(xmlGenericErrorContext,
9438 " with namespace %s\n", prefix);
9439 break;
9440 }
9441 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9442#endif
9443 /*
9444 * 2.3 Node Tests
9445 * - For the attribute axis, the principal node type is attribute.
9446 * - For the namespace axis, the principal node type is namespace.
9447 * - For other axes, the principal node type is element.
9448 *
9449 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009450 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009451 * select all element children of the context node
9452 */
9453 tmp = ctxt->context->node;
9454 list = xmlXPathNodeSetCreate(NULL);
9455 for (i = 0; i < nodelist->nodeNr; i++) {
9456 ctxt->context->node = nodelist->nodeTab[i];
9457
9458 cur = NULL;
9459 n = 0;
9460 do {
9461 cur = next(ctxt, cur);
9462 if (cur == NULL)
9463 break;
9464 if ((first != NULL) && (*first == cur))
9465 break;
9466 if (((t % 256) == 0) &&
9467 (first != NULL) && (*first != NULL) &&
9468 (xmlXPathCmpNodes(*first, cur) >= 0))
9469 break;
9470 if ((last != NULL) && (*last == cur))
9471 break;
9472 if (((t % 256) == 0) &&
9473 (last != NULL) && (*last != NULL) &&
9474 (xmlXPathCmpNodes(cur, *last) >= 0))
9475 break;
9476 t++;
9477 switch (test) {
9478 case NODE_TEST_NONE:
9479 ctxt->context->node = tmp;
9480 STRANGE return(0);
9481 case NODE_TEST_TYPE:
9482 if ((cur->type == type) ||
9483 ((type == NODE_TYPE_NODE) &&
9484 ((cur->type == XML_DOCUMENT_NODE) ||
9485 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9486 (cur->type == XML_ELEMENT_NODE) ||
9487 (cur->type == XML_PI_NODE) ||
9488 (cur->type == XML_COMMENT_NODE) ||
9489 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009490 (cur->type == XML_TEXT_NODE))) ||
9491 ((type == NODE_TYPE_TEXT) &&
9492 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009493 n++;
9494 if (n == indx)
9495 addNode(list, cur);
9496 }
9497 break;
9498 case NODE_TEST_PI:
9499 if (cur->type == XML_PI_NODE) {
9500 if ((name != NULL) &&
9501 (!xmlStrEqual(name, cur->name)))
9502 break;
9503 n++;
9504 if (n == indx)
9505 addNode(list, cur);
9506 }
9507 break;
9508 case NODE_TEST_ALL:
9509 if (axis == AXIS_ATTRIBUTE) {
9510 if (cur->type == XML_ATTRIBUTE_NODE) {
9511 n++;
9512 if (n == indx)
9513 addNode(list, cur);
9514 }
9515 } else if (axis == AXIS_NAMESPACE) {
9516 if (cur->type == XML_NAMESPACE_DECL) {
9517 n++;
9518 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009519 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9520 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009521 }
9522 } else {
9523 if (cur->type == XML_ELEMENT_NODE) {
9524 if (prefix == NULL) {
9525 n++;
9526 if (n == indx)
9527 addNode(list, cur);
9528 } else if ((cur->ns != NULL) &&
9529 (xmlStrEqual(URI, cur->ns->href))) {
9530 n++;
9531 if (n == indx)
9532 addNode(list, cur);
9533 }
9534 }
9535 }
9536 break;
9537 case NODE_TEST_NS:{
9538 TODO;
9539 break;
9540 }
9541 case NODE_TEST_NAME:
9542 switch (cur->type) {
9543 case XML_ELEMENT_NODE:
9544 if (xmlStrEqual(name, cur->name)) {
9545 if (prefix == NULL) {
9546 if (cur->ns == NULL) {
9547 n++;
9548 if (n == indx)
9549 addNode(list, cur);
9550 }
9551 } else {
9552 if ((cur->ns != NULL) &&
9553 (xmlStrEqual(URI,
9554 cur->ns->href))) {
9555 n++;
9556 if (n == indx)
9557 addNode(list, cur);
9558 }
9559 }
9560 }
9561 break;
9562 case XML_ATTRIBUTE_NODE:{
9563 xmlAttrPtr attr = (xmlAttrPtr) cur;
9564
9565 if (xmlStrEqual(name, attr->name)) {
9566 if (prefix == NULL) {
9567 if ((attr->ns == NULL) ||
9568 (attr->ns->prefix == NULL)) {
9569 n++;
9570 if (n == indx)
9571 addNode(list, cur);
9572 }
9573 } else {
9574 if ((attr->ns != NULL) &&
9575 (xmlStrEqual(URI,
9576 attr->ns->
9577 href))) {
9578 n++;
9579 if (n == indx)
9580 addNode(list, cur);
9581 }
9582 }
9583 }
9584 break;
9585 }
9586 case XML_NAMESPACE_DECL:
9587 if (cur->type == XML_NAMESPACE_DECL) {
9588 xmlNsPtr ns = (xmlNsPtr) cur;
9589
9590 if ((ns->prefix != NULL) && (name != NULL)
9591 && (xmlStrEqual(ns->prefix, name))) {
9592 n++;
9593 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009594 xmlXPathNodeSetAddNs(list,
9595 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009596 }
9597 }
9598 break;
9599 default:
9600 break;
9601 }
9602 break;
9603 break;
9604 }
9605 } while (n < indx);
9606 }
9607 ctxt->context->node = tmp;
9608#ifdef DEBUG_STEP_NTH
9609 xmlGenericError(xmlGenericErrorContext,
9610 "\nExamined %d nodes, found %d nodes at that step\n",
9611 t, list->nodeNr);
9612#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009613 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009614 if ((obj->boolval) && (obj->user != NULL)) {
9615 ctxt->value->boolval = 1;
9616 ctxt->value->user = obj->user;
9617 obj->user = NULL;
9618 obj->boolval = 0;
9619 }
9620 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009621 return(t);
9622}
9623
9624/**
9625 * xmlXPathCompOpEvalFirst:
9626 * @ctxt: the XPath parser context with the compiled expression
9627 * @op: an XPath compiled operation
9628 * @first: the first elem found so far
9629 *
9630 * Evaluate the Precompiled XPath operation searching only the first
9631 * element in document order
9632 *
9633 * Returns the number of examined objects.
9634 */
9635static int
9636xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9637 xmlXPathStepOpPtr op, xmlNodePtr * first)
9638{
9639 int total = 0, cur;
9640 xmlXPathCompExprPtr comp;
9641 xmlXPathObjectPtr arg1, arg2;
9642
Daniel Veillard556c6682001-10-06 09:59:51 +00009643 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009644 comp = ctxt->comp;
9645 switch (op->op) {
9646 case XPATH_OP_END:
9647 return (0);
9648 case XPATH_OP_UNION:
9649 total =
9650 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9651 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009652 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009653 if ((ctxt->value != NULL)
9654 && (ctxt->value->type == XPATH_NODESET)
9655 && (ctxt->value->nodesetval != NULL)
9656 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9657 /*
9658 * limit tree traversing to first node in the result
9659 */
9660 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9661 *first = ctxt->value->nodesetval->nodeTab[0];
9662 }
9663 cur =
9664 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9665 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009666 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009667 CHECK_TYPE0(XPATH_NODESET);
9668 arg2 = valuePop(ctxt);
9669
9670 CHECK_TYPE0(XPATH_NODESET);
9671 arg1 = valuePop(ctxt);
9672
9673 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9674 arg2->nodesetval);
9675 valuePush(ctxt, arg1);
9676 xmlXPathFreeObject(arg2);
9677 /* optimizer */
9678 if (total > cur)
9679 xmlXPathCompSwap(op);
9680 return (total + cur);
9681 case XPATH_OP_ROOT:
9682 xmlXPathRoot(ctxt);
9683 return (0);
9684 case XPATH_OP_NODE:
9685 if (op->ch1 != -1)
9686 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009687 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009688 if (op->ch2 != -1)
9689 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009690 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009691 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9692 return (total);
9693 case XPATH_OP_RESET:
9694 if (op->ch1 != -1)
9695 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009696 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009697 if (op->ch2 != -1)
9698 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009699 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009700 ctxt->context->node = NULL;
9701 return (total);
9702 case XPATH_OP_COLLECT:{
9703 if (op->ch1 == -1)
9704 return (total);
9705
9706 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009707 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009708
9709 /*
9710 * Optimization for [n] selection where n is a number
9711 */
9712 if ((op->ch2 != -1) &&
9713 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9714 (comp->steps[op->ch2].ch1 == -1) &&
9715 (comp->steps[op->ch2].ch2 != -1) &&
9716 (comp->steps[comp->steps[op->ch2].ch2].op ==
9717 XPATH_OP_VALUE)) {
9718 xmlXPathObjectPtr val;
9719
9720 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9721 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9722 int indx = (int) val->floatval;
9723
9724 if (val->floatval == (float) indx) {
9725 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9726 first, NULL);
9727 return (total);
9728 }
9729 }
9730 }
9731 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9732 return (total);
9733 }
9734 case XPATH_OP_VALUE:
9735 valuePush(ctxt,
9736 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9737 return (0);
9738 case XPATH_OP_SORT:
9739 if (op->ch1 != -1)
9740 total +=
9741 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9742 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009743 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009744 if ((ctxt->value != NULL)
9745 && (ctxt->value->type == XPATH_NODESET)
9746 && (ctxt->value->nodesetval != NULL))
9747 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9748 return (total);
9749 default:
9750 return (xmlXPathCompOpEval(ctxt, op));
9751 }
9752}
9753
9754/**
9755 * xmlXPathCompOpEvalLast:
9756 * @ctxt: the XPath parser context with the compiled expression
9757 * @op: an XPath compiled operation
9758 * @last: the last elem found so far
9759 *
9760 * Evaluate the Precompiled XPath operation searching only the last
9761 * element in document order
9762 *
9763 * Returns the number of node traversed
9764 */
9765static int
9766xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9767 xmlNodePtr * last)
9768{
9769 int total = 0, cur;
9770 xmlXPathCompExprPtr comp;
9771 xmlXPathObjectPtr arg1, arg2;
9772
Daniel Veillard556c6682001-10-06 09:59:51 +00009773 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009774 comp = ctxt->comp;
9775 switch (op->op) {
9776 case XPATH_OP_END:
9777 return (0);
9778 case XPATH_OP_UNION:
9779 total =
9780 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009781 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009782 if ((ctxt->value != NULL)
9783 && (ctxt->value->type == XPATH_NODESET)
9784 && (ctxt->value->nodesetval != NULL)
9785 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9786 /*
9787 * limit tree traversing to first node in the result
9788 */
9789 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9790 *last =
9791 ctxt->value->nodesetval->nodeTab[ctxt->value->
9792 nodesetval->nodeNr -
9793 1];
9794 }
9795 cur =
9796 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009797 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009798 if ((ctxt->value != NULL)
9799 && (ctxt->value->type == XPATH_NODESET)
9800 && (ctxt->value->nodesetval != NULL)
9801 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9802 }
9803 CHECK_TYPE0(XPATH_NODESET);
9804 arg2 = valuePop(ctxt);
9805
9806 CHECK_TYPE0(XPATH_NODESET);
9807 arg1 = valuePop(ctxt);
9808
9809 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9810 arg2->nodesetval);
9811 valuePush(ctxt, arg1);
9812 xmlXPathFreeObject(arg2);
9813 /* optimizer */
9814 if (total > cur)
9815 xmlXPathCompSwap(op);
9816 return (total + cur);
9817 case XPATH_OP_ROOT:
9818 xmlXPathRoot(ctxt);
9819 return (0);
9820 case XPATH_OP_NODE:
9821 if (op->ch1 != -1)
9822 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009823 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009824 if (op->ch2 != -1)
9825 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009826 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009827 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9828 return (total);
9829 case XPATH_OP_RESET:
9830 if (op->ch1 != -1)
9831 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009832 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009833 if (op->ch2 != -1)
9834 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009835 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009836 ctxt->context->node = NULL;
9837 return (total);
9838 case XPATH_OP_COLLECT:{
9839 if (op->ch1 == -1)
9840 return (0);
9841
9842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009843 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009844
9845 /*
9846 * Optimization for [n] selection where n is a number
9847 */
9848 if ((op->ch2 != -1) &&
9849 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9850 (comp->steps[op->ch2].ch1 == -1) &&
9851 (comp->steps[op->ch2].ch2 != -1) &&
9852 (comp->steps[comp->steps[op->ch2].ch2].op ==
9853 XPATH_OP_VALUE)) {
9854 xmlXPathObjectPtr val;
9855
9856 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9857 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9858 int indx = (int) val->floatval;
9859
9860 if (val->floatval == (float) indx) {
9861 total +=
9862 xmlXPathNodeCollectAndTestNth(ctxt, op,
9863 indx, NULL,
9864 last);
9865 return (total);
9866 }
9867 }
9868 }
9869 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9870 return (total);
9871 }
9872 case XPATH_OP_VALUE:
9873 valuePush(ctxt,
9874 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9875 return (0);
9876 case XPATH_OP_SORT:
9877 if (op->ch1 != -1)
9878 total +=
9879 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9880 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009881 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009882 if ((ctxt->value != NULL)
9883 && (ctxt->value->type == XPATH_NODESET)
9884 && (ctxt->value->nodesetval != NULL))
9885 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9886 return (total);
9887 default:
9888 return (xmlXPathCompOpEval(ctxt, op));
9889 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009890}
9891
Owen Taylor3473f882001-02-23 17:55:21 +00009892/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009893 * xmlXPathCompOpEval:
9894 * @ctxt: the XPath parser context with the compiled expression
9895 * @op: an XPath compiled operation
9896 *
9897 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009898 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009899 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009900static int
9901xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9902{
9903 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009904 int equal, ret;
9905 xmlXPathCompExprPtr comp;
9906 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009907 xmlNodePtr bak;
9908 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009909 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009910 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009911
Daniel Veillard556c6682001-10-06 09:59:51 +00009912 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009913 comp = ctxt->comp;
9914 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009915 case XPATH_OP_END:
9916 return (0);
9917 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009918 bakd = ctxt->context->doc;
9919 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009920 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009921 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009923 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009924 xmlXPathBooleanFunction(ctxt, 1);
9925 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9926 return (total);
9927 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009928 ctxt->context->doc = bakd;
9929 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009930 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009931 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009932 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009933 if (ctxt->error) {
9934 xmlXPathFreeObject(arg2);
9935 return(0);
9936 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009937 xmlXPathBooleanFunction(ctxt, 1);
9938 arg1 = valuePop(ctxt);
9939 arg1->boolval &= arg2->boolval;
9940 valuePush(ctxt, arg1);
9941 xmlXPathFreeObject(arg2);
9942 return (total);
9943 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009944 bakd = ctxt->context->doc;
9945 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009946 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009947 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009949 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009950 xmlXPathBooleanFunction(ctxt, 1);
9951 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9952 return (total);
9953 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009954 ctxt->context->doc = bakd;
9955 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009956 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009957 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009958 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009959 if (ctxt->error) {
9960 xmlXPathFreeObject(arg2);
9961 return(0);
9962 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009963 xmlXPathBooleanFunction(ctxt, 1);
9964 arg1 = valuePop(ctxt);
9965 arg1->boolval |= arg2->boolval;
9966 valuePush(ctxt, arg1);
9967 xmlXPathFreeObject(arg2);
9968 return (total);
9969 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009970 bakd = ctxt->context->doc;
9971 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009972 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009973 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009974 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009975 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009976 ctxt->context->doc = bakd;
9977 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009978 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009979 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009981 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009982 if (op->value)
9983 equal = xmlXPathEqualValues(ctxt);
9984 else
9985 equal = xmlXPathNotEqualValues(ctxt);
9986 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009987 return (total);
9988 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009989 bakd = ctxt->context->doc;
9990 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009991 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009992 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009993 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009994 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009995 ctxt->context->doc = bakd;
9996 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009997 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009998 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009999 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010000 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010001 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10002 valuePush(ctxt, xmlXPathNewBoolean(ret));
10003 return (total);
10004 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010005 bakd = ctxt->context->doc;
10006 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010007 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010008 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010009 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010010 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010011 if (op->ch2 != -1) {
10012 ctxt->context->doc = bakd;
10013 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010014 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010015 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010017 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010018 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010019 if (op->value == 0)
10020 xmlXPathSubValues(ctxt);
10021 else if (op->value == 1)
10022 xmlXPathAddValues(ctxt);
10023 else if (op->value == 2)
10024 xmlXPathValueFlipSign(ctxt);
10025 else if (op->value == 3) {
10026 CAST_TO_NUMBER;
10027 CHECK_TYPE0(XPATH_NUMBER);
10028 }
10029 return (total);
10030 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010031 bakd = ctxt->context->doc;
10032 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010033 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010034 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010035 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010036 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010037 ctxt->context->doc = bakd;
10038 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010039 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010040 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010041 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010042 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 if (op->value == 0)
10044 xmlXPathMultValues(ctxt);
10045 else if (op->value == 1)
10046 xmlXPathDivValues(ctxt);
10047 else if (op->value == 2)
10048 xmlXPathModValues(ctxt);
10049 return (total);
10050 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010051 bakd = ctxt->context->doc;
10052 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010053 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010054 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010055 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010056 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010057 ctxt->context->doc = bakd;
10058 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010059 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010060 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010062 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010063 CHECK_TYPE0(XPATH_NODESET);
10064 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010065
Daniel Veillardf06307e2001-07-03 10:35:50 +000010066 CHECK_TYPE0(XPATH_NODESET);
10067 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010068
Daniel Veillardf06307e2001-07-03 10:35:50 +000010069 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10070 arg2->nodesetval);
10071 valuePush(ctxt, arg1);
10072 xmlXPathFreeObject(arg2);
10073 return (total);
10074 case XPATH_OP_ROOT:
10075 xmlXPathRoot(ctxt);
10076 return (total);
10077 case XPATH_OP_NODE:
10078 if (op->ch1 != -1)
10079 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010080 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010081 if (op->ch2 != -1)
10082 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010083 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010084 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10085 return (total);
10086 case XPATH_OP_RESET:
10087 if (op->ch1 != -1)
10088 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010089 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010090 if (op->ch2 != -1)
10091 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010092 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010093 ctxt->context->node = NULL;
10094 return (total);
10095 case XPATH_OP_COLLECT:{
10096 if (op->ch1 == -1)
10097 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010098
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010100 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010101
Daniel Veillardf06307e2001-07-03 10:35:50 +000010102 /*
10103 * Optimization for [n] selection where n is a number
10104 */
10105 if ((op->ch2 != -1) &&
10106 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10107 (comp->steps[op->ch2].ch1 == -1) &&
10108 (comp->steps[op->ch2].ch2 != -1) &&
10109 (comp->steps[comp->steps[op->ch2].ch2].op ==
10110 XPATH_OP_VALUE)) {
10111 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010112
Daniel Veillardf06307e2001-07-03 10:35:50 +000010113 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10114 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10115 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010116
Daniel Veillardf06307e2001-07-03 10:35:50 +000010117 if (val->floatval == (float) indx) {
10118 total +=
10119 xmlXPathNodeCollectAndTestNth(ctxt, op,
10120 indx, NULL,
10121 NULL);
10122 return (total);
10123 }
10124 }
10125 }
10126 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10127 return (total);
10128 }
10129 case XPATH_OP_VALUE:
10130 valuePush(ctxt,
10131 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10132 return (total);
10133 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010134 xmlXPathObjectPtr val;
10135
Daniel Veillardf06307e2001-07-03 10:35:50 +000010136 if (op->ch1 != -1)
10137 total +=
10138 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010139 if (op->value5 == NULL) {
10140 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10141 if (val == NULL) {
10142 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10143 return(0);
10144 }
10145 valuePush(ctxt, val);
10146 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010147 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010148
Daniel Veillardf06307e2001-07-03 10:35:50 +000010149 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10150 if (URI == NULL) {
10151 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010152 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010153 op->value4, op->value5);
10154 return (total);
10155 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010156 val = xmlXPathVariableLookupNS(ctxt->context,
10157 op->value4, URI);
10158 if (val == NULL) {
10159 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10160 return(0);
10161 }
10162 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010163 }
10164 return (total);
10165 }
10166 case XPATH_OP_FUNCTION:{
10167 xmlXPathFunction func;
10168 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010169 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010170
10171 if (op->ch1 != -1)
10172 total +=
10173 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010174 if (ctxt->valueNr < op->value) {
10175 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010176 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010177 ctxt->error = XPATH_INVALID_OPERAND;
10178 return (total);
10179 }
10180 for (i = 0; i < op->value; i++)
10181 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10182 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010183 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010184 ctxt->error = XPATH_INVALID_OPERAND;
10185 return (total);
10186 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010187 if (op->cache != NULL)
10188 func = (xmlXPathFunction) op->cache;
10189 else {
10190 const xmlChar *URI = NULL;
10191
10192 if (op->value5 == NULL)
10193 func =
10194 xmlXPathFunctionLookup(ctxt->context,
10195 op->value4);
10196 else {
10197 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10198 if (URI == NULL) {
10199 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010200 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010201 op->value4, op->value5);
10202 return (total);
10203 }
10204 func = xmlXPathFunctionLookupNS(ctxt->context,
10205 op->value4, URI);
10206 }
10207 if (func == NULL) {
10208 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010209 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010210 op->value4);
10211 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010212 }
10213 op->cache = (void *) func;
10214 op->cacheURI = (void *) URI;
10215 }
10216 oldFunc = ctxt->context->function;
10217 oldFuncURI = ctxt->context->functionURI;
10218 ctxt->context->function = op->value4;
10219 ctxt->context->functionURI = op->cacheURI;
10220 func(ctxt, op->value);
10221 ctxt->context->function = oldFunc;
10222 ctxt->context->functionURI = oldFuncURI;
10223 return (total);
10224 }
10225 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010226 bakd = ctxt->context->doc;
10227 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010228 if (op->ch1 != -1)
10229 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010230 ctxt->context->doc = bakd;
10231 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010232 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010233 if (op->ch2 != -1)
10234 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010235 ctxt->context->doc = bakd;
10236 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010237 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010238 return (total);
10239 case XPATH_OP_PREDICATE:
10240 case XPATH_OP_FILTER:{
10241 xmlXPathObjectPtr res;
10242 xmlXPathObjectPtr obj, tmp;
10243 xmlNodeSetPtr newset = NULL;
10244 xmlNodeSetPtr oldset;
10245 xmlNodePtr oldnode;
10246 int i;
10247
10248 /*
10249 * Optimization for ()[1] selection i.e. the first elem
10250 */
10251 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10252 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10253 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10254 xmlXPathObjectPtr val;
10255
10256 val = comp->steps[op->ch2].value4;
10257 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10258 (val->floatval == 1.0)) {
10259 xmlNodePtr first = NULL;
10260
10261 total +=
10262 xmlXPathCompOpEvalFirst(ctxt,
10263 &comp->steps[op->ch1],
10264 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010265 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010266 /*
10267 * The nodeset should be in document order,
10268 * Keep only the first value
10269 */
10270 if ((ctxt->value != NULL) &&
10271 (ctxt->value->type == XPATH_NODESET) &&
10272 (ctxt->value->nodesetval != NULL) &&
10273 (ctxt->value->nodesetval->nodeNr > 1))
10274 ctxt->value->nodesetval->nodeNr = 1;
10275 return (total);
10276 }
10277 }
10278 /*
10279 * Optimization for ()[last()] selection i.e. the last elem
10280 */
10281 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10282 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10283 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10284 int f = comp->steps[op->ch2].ch1;
10285
10286 if ((f != -1) &&
10287 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10288 (comp->steps[f].value5 == NULL) &&
10289 (comp->steps[f].value == 0) &&
10290 (comp->steps[f].value4 != NULL) &&
10291 (xmlStrEqual
10292 (comp->steps[f].value4, BAD_CAST "last"))) {
10293 xmlNodePtr last = NULL;
10294
10295 total +=
10296 xmlXPathCompOpEvalLast(ctxt,
10297 &comp->steps[op->ch1],
10298 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010299 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010300 /*
10301 * The nodeset should be in document order,
10302 * Keep only the last value
10303 */
10304 if ((ctxt->value != NULL) &&
10305 (ctxt->value->type == XPATH_NODESET) &&
10306 (ctxt->value->nodesetval != NULL) &&
10307 (ctxt->value->nodesetval->nodeTab != NULL) &&
10308 (ctxt->value->nodesetval->nodeNr > 1)) {
10309 ctxt->value->nodesetval->nodeTab[0] =
10310 ctxt->value->nodesetval->nodeTab[ctxt->
10311 value->
10312 nodesetval->
10313 nodeNr -
10314 1];
10315 ctxt->value->nodesetval->nodeNr = 1;
10316 }
10317 return (total);
10318 }
10319 }
10320
10321 if (op->ch1 != -1)
10322 total +=
10323 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010324 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010325 if (op->ch2 == -1)
10326 return (total);
10327 if (ctxt->value == NULL)
10328 return (total);
10329
10330 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010331
10332#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010333 /*
10334 * Hum are we filtering the result of an XPointer expression
10335 */
10336 if (ctxt->value->type == XPATH_LOCATIONSET) {
10337 xmlLocationSetPtr newlocset = NULL;
10338 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010339
Daniel Veillardf06307e2001-07-03 10:35:50 +000010340 /*
10341 * Extract the old locset, and then evaluate the result of the
10342 * expression for all the element in the locset. use it to grow
10343 * up a new locset.
10344 */
10345 CHECK_TYPE0(XPATH_LOCATIONSET);
10346 obj = valuePop(ctxt);
10347 oldlocset = obj->user;
10348 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010349
Daniel Veillardf06307e2001-07-03 10:35:50 +000010350 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10351 ctxt->context->contextSize = 0;
10352 ctxt->context->proximityPosition = 0;
10353 if (op->ch2 != -1)
10354 total +=
10355 xmlXPathCompOpEval(ctxt,
10356 &comp->steps[op->ch2]);
10357 res = valuePop(ctxt);
10358 if (res != NULL)
10359 xmlXPathFreeObject(res);
10360 valuePush(ctxt, obj);
10361 CHECK_ERROR0;
10362 return (total);
10363 }
10364 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010365
Daniel Veillardf06307e2001-07-03 10:35:50 +000010366 for (i = 0; i < oldlocset->locNr; i++) {
10367 /*
10368 * Run the evaluation with a node list made of a
10369 * single item in the nodelocset.
10370 */
10371 ctxt->context->node = oldlocset->locTab[i]->user;
10372 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10373 valuePush(ctxt, tmp);
10374 ctxt->context->contextSize = oldlocset->locNr;
10375 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010376
Daniel Veillardf06307e2001-07-03 10:35:50 +000010377 if (op->ch2 != -1)
10378 total +=
10379 xmlXPathCompOpEval(ctxt,
10380 &comp->steps[op->ch2]);
10381 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010382
Daniel Veillardf06307e2001-07-03 10:35:50 +000010383 /*
10384 * The result of the evaluation need to be tested to
10385 * decided whether the filter succeeded or not
10386 */
10387 res = valuePop(ctxt);
10388 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10389 xmlXPtrLocationSetAdd(newlocset,
10390 xmlXPathObjectCopy
10391 (oldlocset->locTab[i]));
10392 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010393
Daniel Veillardf06307e2001-07-03 10:35:50 +000010394 /*
10395 * Cleanup
10396 */
10397 if (res != NULL)
10398 xmlXPathFreeObject(res);
10399 if (ctxt->value == tmp) {
10400 res = valuePop(ctxt);
10401 xmlXPathFreeObject(res);
10402 }
10403
10404 ctxt->context->node = NULL;
10405 }
10406
10407 /*
10408 * The result is used as the new evaluation locset.
10409 */
10410 xmlXPathFreeObject(obj);
10411 ctxt->context->node = NULL;
10412 ctxt->context->contextSize = -1;
10413 ctxt->context->proximityPosition = -1;
10414 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10415 ctxt->context->node = oldnode;
10416 return (total);
10417 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010418#endif /* LIBXML_XPTR_ENABLED */
10419
Daniel Veillardf06307e2001-07-03 10:35:50 +000010420 /*
10421 * Extract the old set, and then evaluate the result of the
10422 * expression for all the element in the set. use it to grow
10423 * up a new set.
10424 */
10425 CHECK_TYPE0(XPATH_NODESET);
10426 obj = valuePop(ctxt);
10427 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010428
Daniel Veillardf06307e2001-07-03 10:35:50 +000010429 oldnode = ctxt->context->node;
10430 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010431
Daniel Veillardf06307e2001-07-03 10:35:50 +000010432 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10433 ctxt->context->contextSize = 0;
10434 ctxt->context->proximityPosition = 0;
10435 if (op->ch2 != -1)
10436 total +=
10437 xmlXPathCompOpEval(ctxt,
10438 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010439 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010440 res = valuePop(ctxt);
10441 if (res != NULL)
10442 xmlXPathFreeObject(res);
10443 valuePush(ctxt, obj);
10444 ctxt->context->node = oldnode;
10445 CHECK_ERROR0;
10446 } else {
10447 /*
10448 * Initialize the new set.
10449 */
10450 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010451
Daniel Veillardf06307e2001-07-03 10:35:50 +000010452 for (i = 0; i < oldset->nodeNr; i++) {
10453 /*
10454 * Run the evaluation with a node list made of
10455 * a single item in the nodeset.
10456 */
10457 ctxt->context->node = oldset->nodeTab[i];
10458 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10459 valuePush(ctxt, tmp);
10460 ctxt->context->contextSize = oldset->nodeNr;
10461 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010462
Daniel Veillardf06307e2001-07-03 10:35:50 +000010463 if (op->ch2 != -1)
10464 total +=
10465 xmlXPathCompOpEval(ctxt,
10466 &comp->steps[op->ch2]);
10467 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010468
Daniel Veillardf06307e2001-07-03 10:35:50 +000010469 /*
10470 * The result of the evaluation need to be tested to
10471 * decided whether the filter succeeded or not
10472 */
10473 res = valuePop(ctxt);
10474 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10475 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10476 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010477
Daniel Veillardf06307e2001-07-03 10:35:50 +000010478 /*
10479 * Cleanup
10480 */
10481 if (res != NULL)
10482 xmlXPathFreeObject(res);
10483 if (ctxt->value == tmp) {
10484 res = valuePop(ctxt);
10485 xmlXPathFreeObject(res);
10486 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010487
Daniel Veillardf06307e2001-07-03 10:35:50 +000010488 ctxt->context->node = NULL;
10489 }
10490
10491 /*
10492 * The result is used as the new evaluation set.
10493 */
10494 xmlXPathFreeObject(obj);
10495 ctxt->context->node = NULL;
10496 ctxt->context->contextSize = -1;
10497 ctxt->context->proximityPosition = -1;
10498 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10499 }
10500 ctxt->context->node = oldnode;
10501 return (total);
10502 }
10503 case XPATH_OP_SORT:
10504 if (op->ch1 != -1)
10505 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010506 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010507 if ((ctxt->value != NULL) &&
10508 (ctxt->value->type == XPATH_NODESET) &&
10509 (ctxt->value->nodesetval != NULL))
10510 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10511 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010512#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010513 case XPATH_OP_RANGETO:{
10514 xmlXPathObjectPtr range;
10515 xmlXPathObjectPtr res, obj;
10516 xmlXPathObjectPtr tmp;
10517 xmlLocationSetPtr newset = NULL;
10518 xmlNodeSetPtr oldset;
10519 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010520
Daniel Veillardf06307e2001-07-03 10:35:50 +000010521 if (op->ch1 != -1)
10522 total +=
10523 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10524 if (op->ch2 == -1)
10525 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010526
Daniel Veillardf06307e2001-07-03 10:35:50 +000010527 CHECK_TYPE0(XPATH_NODESET);
10528 obj = valuePop(ctxt);
10529 oldset = obj->nodesetval;
10530 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010531
Daniel Veillardf06307e2001-07-03 10:35:50 +000010532 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010533
Daniel Veillardf06307e2001-07-03 10:35:50 +000010534 if (oldset != NULL) {
10535 for (i = 0; i < oldset->nodeNr; i++) {
10536 /*
10537 * Run the evaluation with a node list made of a single item
10538 * in the nodeset.
10539 */
10540 ctxt->context->node = oldset->nodeTab[i];
10541 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10542 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010543
Daniel Veillardf06307e2001-07-03 10:35:50 +000010544 if (op->ch2 != -1)
10545 total +=
10546 xmlXPathCompOpEval(ctxt,
10547 &comp->steps[op->ch2]);
10548 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010549
Daniel Veillardf06307e2001-07-03 10:35:50 +000010550 /*
10551 * The result of the evaluation need to be tested to
10552 * decided whether the filter succeeded or not
10553 */
10554 res = valuePop(ctxt);
10555 range =
10556 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10557 res);
10558 if (range != NULL) {
10559 xmlXPtrLocationSetAdd(newset, range);
10560 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010561
Daniel Veillardf06307e2001-07-03 10:35:50 +000010562 /*
10563 * Cleanup
10564 */
10565 if (res != NULL)
10566 xmlXPathFreeObject(res);
10567 if (ctxt->value == tmp) {
10568 res = valuePop(ctxt);
10569 xmlXPathFreeObject(res);
10570 }
10571
10572 ctxt->context->node = NULL;
10573 }
10574 }
10575
10576 /*
10577 * The result is used as the new evaluation set.
10578 */
10579 xmlXPathFreeObject(obj);
10580 ctxt->context->node = NULL;
10581 ctxt->context->contextSize = -1;
10582 ctxt->context->proximityPosition = -1;
10583 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10584 return (total);
10585 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010586#endif /* LIBXML_XPTR_ENABLED */
10587 }
10588 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010589 "XPath: unknown precompiled operation %d\n", op->op);
10590 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591}
10592
10593/**
10594 * xmlXPathRunEval:
10595 * @ctxt: the XPath parser context with the compiled expression
10596 *
10597 * Evaluate the Precompiled XPath expression in the given context.
10598 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010599static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010600xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10601 xmlXPathCompExprPtr comp;
10602
10603 if ((ctxt == NULL) || (ctxt->comp == NULL))
10604 return;
10605
10606 if (ctxt->valueTab == NULL) {
10607 /* Allocate the value stack */
10608 ctxt->valueTab = (xmlXPathObjectPtr *)
10609 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10610 if (ctxt->valueTab == NULL) {
10611 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010612 }
10613 ctxt->valueNr = 0;
10614 ctxt->valueMax = 10;
10615 ctxt->value = NULL;
10616 }
10617 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010618 if(comp->last < 0) {
10619 xmlGenericError(xmlGenericErrorContext,
10620 "xmlXPathRunEval: last is less than zero\n");
10621 return;
10622 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010623 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10624}
10625
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010626/************************************************************************
10627 * *
10628 * Public interfaces *
10629 * *
10630 ************************************************************************/
10631
10632/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010633 * xmlXPathEvalPredicate:
10634 * @ctxt: the XPath context
10635 * @res: the Predicate Expression evaluation result
10636 *
10637 * Evaluate a predicate result for the current node.
10638 * A PredicateExpr is evaluated by evaluating the Expr and converting
10639 * the result to a boolean. If the result is a number, the result will
10640 * be converted to true if the number is equal to the position of the
10641 * context node in the context node list (as returned by the position
10642 * function) and will be converted to false otherwise; if the result
10643 * is not a number, then the result will be converted as if by a call
10644 * to the boolean function.
10645 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010646 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010647 */
10648int
10649xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10650 if (res == NULL) return(0);
10651 switch (res->type) {
10652 case XPATH_BOOLEAN:
10653 return(res->boolval);
10654 case XPATH_NUMBER:
10655 return(res->floatval == ctxt->proximityPosition);
10656 case XPATH_NODESET:
10657 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010658 if (res->nodesetval == NULL)
10659 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010660 return(res->nodesetval->nodeNr != 0);
10661 case XPATH_STRING:
10662 return((res->stringval != NULL) &&
10663 (xmlStrlen(res->stringval) != 0));
10664 default:
10665 STRANGE
10666 }
10667 return(0);
10668}
10669
10670/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010671 * xmlXPathEvaluatePredicateResult:
10672 * @ctxt: the XPath Parser context
10673 * @res: the Predicate Expression evaluation result
10674 *
10675 * Evaluate a predicate result for the current node.
10676 * A PredicateExpr is evaluated by evaluating the Expr and converting
10677 * the result to a boolean. If the result is a number, the result will
10678 * be converted to true if the number is equal to the position of the
10679 * context node in the context node list (as returned by the position
10680 * function) and will be converted to false otherwise; if the result
10681 * is not a number, then the result will be converted as if by a call
10682 * to the boolean function.
10683 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010684 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010685 */
10686int
10687xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10688 xmlXPathObjectPtr res) {
10689 if (res == NULL) return(0);
10690 switch (res->type) {
10691 case XPATH_BOOLEAN:
10692 return(res->boolval);
10693 case XPATH_NUMBER:
10694 return(res->floatval == ctxt->context->proximityPosition);
10695 case XPATH_NODESET:
10696 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010697 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010698 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010699 return(res->nodesetval->nodeNr != 0);
10700 case XPATH_STRING:
10701 return((res->stringval != NULL) &&
10702 (xmlStrlen(res->stringval) != 0));
10703 default:
10704 STRANGE
10705 }
10706 return(0);
10707}
10708
10709/**
10710 * xmlXPathCompile:
10711 * @str: the XPath expression
10712 *
10713 * Compile an XPath expression
10714 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010715 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010716 * the caller has to free the object.
10717 */
10718xmlXPathCompExprPtr
10719xmlXPathCompile(const xmlChar *str) {
10720 xmlXPathParserContextPtr ctxt;
10721 xmlXPathCompExprPtr comp;
10722
10723 xmlXPathInit();
10724
10725 ctxt = xmlXPathNewParserContext(str, NULL);
10726 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010727
Daniel Veillard40af6492001-04-22 08:50:55 +000010728 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010729 /*
10730 * aleksey: in some cases this line prints *second* error message
10731 * (see bug #78858) and probably this should be fixed.
10732 * However, we are not sure that all error messages are printed
10733 * out in other places. It's not critical so we leave it as-is for now
10734 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010735 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10736 comp = NULL;
10737 } else {
10738 comp = ctxt->comp;
10739 ctxt->comp = NULL;
10740 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010741 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010742 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010743 comp->expr = xmlStrdup(str);
10744#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010745 comp->string = xmlStrdup(str);
10746 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010747#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010748 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010749 return(comp);
10750}
10751
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010752/**
10753 * xmlXPathCompiledEval:
10754 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010755 * @ctx: the XPath context
10756 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010757 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010758 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010759 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010760 * the caller has to free the object.
10761 */
10762xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010763xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010764 xmlXPathParserContextPtr ctxt;
10765 xmlXPathObjectPtr res, tmp, init = NULL;
10766 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010767#ifndef LIBXML_THREAD_ENABLED
10768 static int reentance = 0;
10769#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010770
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010771 if ((comp == NULL) || (ctx == NULL))
10772 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010773 xmlXPathInit();
10774
10775 CHECK_CONTEXT(ctx)
10776
Daniel Veillard81463942001-10-16 12:34:39 +000010777#ifndef LIBXML_THREAD_ENABLED
10778 reentance++;
10779 if (reentance > 1)
10780 xmlXPathDisableOptimizer = 1;
10781#endif
10782
Daniel Veillardf06307e2001-07-03 10:35:50 +000010783#ifdef DEBUG_EVAL_COUNTS
10784 comp->nb++;
10785 if ((comp->string != NULL) && (comp->nb > 100)) {
10786 fprintf(stderr, "100 x %s\n", comp->string);
10787 comp->nb = 0;
10788 }
10789#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010790 ctxt = xmlXPathCompParserContext(comp, ctx);
10791 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010792
10793 if (ctxt->value == NULL) {
10794 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010795 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010796 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010797 } else {
10798 res = valuePop(ctxt);
10799 }
10800
Daniel Veillardf06307e2001-07-03 10:35:50 +000010801
Owen Taylor3473f882001-02-23 17:55:21 +000010802 do {
10803 tmp = valuePop(ctxt);
10804 if (tmp != NULL) {
10805 if (tmp != init)
10806 stack++;
10807 xmlXPathFreeObject(tmp);
10808 }
10809 } while (tmp != NULL);
10810 if ((stack != 0) && (res != NULL)) {
10811 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010812 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010813 stack);
10814 }
10815 if (ctxt->error != XPATH_EXPRESSION_OK) {
10816 xmlXPathFreeObject(res);
10817 res = NULL;
10818 }
10819
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010820
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010821 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010822 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010823#ifndef LIBXML_THREAD_ENABLED
10824 reentance--;
10825#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010826 return(res);
10827}
10828
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010829/**
10830 * xmlXPathEvalExpr:
10831 * @ctxt: the XPath Parser context
10832 *
10833 * Parse and evaluate an XPath expression in the given context,
10834 * then push the result on the context stack
10835 */
10836void
10837xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10838 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010839 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010840 xmlXPathRunEval(ctxt);
10841}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010842
10843/**
10844 * xmlXPathEval:
10845 * @str: the XPath expression
10846 * @ctx: the XPath context
10847 *
10848 * Evaluate the XPath Location Path in the given context.
10849 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010850 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010851 * the caller has to free the object.
10852 */
10853xmlXPathObjectPtr
10854xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10855 xmlXPathParserContextPtr ctxt;
10856 xmlXPathObjectPtr res, tmp, init = NULL;
10857 int stack = 0;
10858
10859 xmlXPathInit();
10860
10861 CHECK_CONTEXT(ctx)
10862
10863 ctxt = xmlXPathNewParserContext(str, ctx);
10864 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010865
10866 if (ctxt->value == NULL) {
10867 xmlGenericError(xmlGenericErrorContext,
10868 "xmlXPathEval: evaluation failed\n");
10869 res = NULL;
10870 } else if (*ctxt->cur != 0) {
10871 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10872 res = NULL;
10873 } else {
10874 res = valuePop(ctxt);
10875 }
10876
10877 do {
10878 tmp = valuePop(ctxt);
10879 if (tmp != NULL) {
10880 if (tmp != init)
10881 stack++;
10882 xmlXPathFreeObject(tmp);
10883 }
10884 } while (tmp != NULL);
10885 if ((stack != 0) && (res != NULL)) {
10886 xmlGenericError(xmlGenericErrorContext,
10887 "xmlXPathEval: %d object left on the stack\n",
10888 stack);
10889 }
10890 if (ctxt->error != XPATH_EXPRESSION_OK) {
10891 xmlXPathFreeObject(res);
10892 res = NULL;
10893 }
10894
Owen Taylor3473f882001-02-23 17:55:21 +000010895 xmlXPathFreeParserContext(ctxt);
10896 return(res);
10897}
10898
10899/**
10900 * xmlXPathEvalExpression:
10901 * @str: the XPath expression
10902 * @ctxt: the XPath context
10903 *
10904 * Evaluate the XPath expression in the given context.
10905 *
10906 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10907 * the caller has to free the object.
10908 */
10909xmlXPathObjectPtr
10910xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10911 xmlXPathParserContextPtr pctxt;
10912 xmlXPathObjectPtr res, tmp;
10913 int stack = 0;
10914
10915 xmlXPathInit();
10916
10917 CHECK_CONTEXT(ctxt)
10918
10919 pctxt = xmlXPathNewParserContext(str, ctxt);
10920 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010921
10922 if (*pctxt->cur != 0) {
10923 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10924 res = NULL;
10925 } else {
10926 res = valuePop(pctxt);
10927 }
10928 do {
10929 tmp = valuePop(pctxt);
10930 if (tmp != NULL) {
10931 xmlXPathFreeObject(tmp);
10932 stack++;
10933 }
10934 } while (tmp != NULL);
10935 if ((stack != 0) && (res != NULL)) {
10936 xmlGenericError(xmlGenericErrorContext,
10937 "xmlXPathEvalExpression: %d object left on the stack\n",
10938 stack);
10939 }
10940 xmlXPathFreeParserContext(pctxt);
10941 return(res);
10942}
10943
Daniel Veillard42766c02002-08-22 20:52:17 +000010944/************************************************************************
10945 * *
10946 * Extra functions not pertaining to the XPath spec *
10947 * *
10948 ************************************************************************/
10949/**
10950 * xmlXPathEscapeUriFunction:
10951 * @ctxt: the XPath Parser context
10952 * @nargs: the number of arguments
10953 *
10954 * Implement the escape-uri() XPath function
10955 * string escape-uri(string $str, bool $escape-reserved)
10956 *
10957 * This function applies the URI escaping rules defined in section 2 of [RFC
10958 * 2396] to the string supplied as $uri-part, which typically represents all
10959 * or part of a URI. The effect of the function is to replace any special
10960 * character in the string by an escape sequence of the form %xx%yy...,
10961 * where xxyy... is the hexadecimal representation of the octets used to
10962 * represent the character in UTF-8.
10963 *
10964 * The set of characters that are escaped depends on the setting of the
10965 * boolean argument $escape-reserved.
10966 *
10967 * If $escape-reserved is true, all characters are escaped other than lower
10968 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10969 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10970 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10971 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10972 * A-F).
10973 *
10974 * If $escape-reserved is false, the behavior differs in that characters
10975 * referred to in [RFC 2396] as reserved characters are not escaped. These
10976 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10977 *
10978 * [RFC 2396] does not define whether escaped URIs should use lower case or
10979 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10980 * compared using string comparison functions, this function must always use
10981 * the upper-case letters A-F.
10982 *
10983 * Generally, $escape-reserved should be set to true when escaping a string
10984 * that is to form a single part of a URI, and to false when escaping an
10985 * entire URI or URI reference.
10986 *
10987 * In the case of non-ascii characters, the string is encoded according to
10988 * utf-8 and then converted according to RFC 2396.
10989 *
10990 * Examples
10991 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10992 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10993 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10994 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10995 *
10996 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010997static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010998xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10999 xmlXPathObjectPtr str;
11000 int escape_reserved;
11001 xmlBufferPtr target;
11002 xmlChar *cptr;
11003 xmlChar escape[4];
11004
11005 CHECK_ARITY(2);
11006
11007 escape_reserved = xmlXPathPopBoolean(ctxt);
11008
11009 CAST_TO_STRING;
11010 str = valuePop(ctxt);
11011
11012 target = xmlBufferCreate();
11013
11014 escape[0] = '%';
11015 escape[3] = 0;
11016
11017 if (target) {
11018 for (cptr = str->stringval; *cptr; cptr++) {
11019 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11020 (*cptr >= 'a' && *cptr <= 'z') ||
11021 (*cptr >= '0' && *cptr <= '9') ||
11022 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11023 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11024 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11025 (*cptr == '%' &&
11026 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11027 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11028 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11029 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11030 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11031 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11032 (!escape_reserved &&
11033 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11034 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11035 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11036 *cptr == ','))) {
11037 xmlBufferAdd(target, cptr, 1);
11038 } else {
11039 if ((*cptr >> 4) < 10)
11040 escape[1] = '0' + (*cptr >> 4);
11041 else
11042 escape[1] = 'A' - 10 + (*cptr >> 4);
11043 if ((*cptr & 0xF) < 10)
11044 escape[2] = '0' + (*cptr & 0xF);
11045 else
11046 escape[2] = 'A' - 10 + (*cptr & 0xF);
11047
11048 xmlBufferAdd(target, &escape[0], 3);
11049 }
11050 }
11051 }
11052 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11053 xmlBufferFree(target);
11054 xmlXPathFreeObject(str);
11055}
11056
Owen Taylor3473f882001-02-23 17:55:21 +000011057/**
11058 * xmlXPathRegisterAllFunctions:
11059 * @ctxt: the XPath context
11060 *
11061 * Registers all default XPath functions in this context
11062 */
11063void
11064xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11065{
11066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11067 xmlXPathBooleanFunction);
11068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11069 xmlXPathCeilingFunction);
11070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11071 xmlXPathCountFunction);
11072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11073 xmlXPathConcatFunction);
11074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11075 xmlXPathContainsFunction);
11076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11077 xmlXPathIdFunction);
11078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11079 xmlXPathFalseFunction);
11080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11081 xmlXPathFloorFunction);
11082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11083 xmlXPathLastFunction);
11084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11085 xmlXPathLangFunction);
11086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11087 xmlXPathLocalNameFunction);
11088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11089 xmlXPathNotFunction);
11090 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11091 xmlXPathNameFunction);
11092 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11093 xmlXPathNamespaceURIFunction);
11094 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11095 xmlXPathNormalizeFunction);
11096 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11097 xmlXPathNumberFunction);
11098 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11099 xmlXPathPositionFunction);
11100 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11101 xmlXPathRoundFunction);
11102 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11103 xmlXPathStringFunction);
11104 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11105 xmlXPathStringLengthFunction);
11106 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11107 xmlXPathStartsWithFunction);
11108 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11109 xmlXPathSubstringFunction);
11110 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11111 xmlXPathSubstringBeforeFunction);
11112 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11113 xmlXPathSubstringAfterFunction);
11114 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11115 xmlXPathSumFunction);
11116 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11117 xmlXPathTrueFunction);
11118 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11119 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011120
11121 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11122 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11123 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011124}
11125
11126#endif /* LIBXML_XPATH_ENABLED */